给定当前日期和周开始,获取周开始和结束日期

发布于 2025-01-04 16:20:40 字数 798 浏览 1 评论 0原文

如果可能的话,我更喜欢针对以下场景的 joda 或非 joda 解决方案

假设我的一周从 02/05/2012 开始,并且给定的当前日期是 02/22/2011。我需要计算给定当前日期的一周开始和结束日期。所以我的解决方案应该让一周从 02/19 开始,到 02/25 结束。 为简单起见,我将一周的开始时间设置为 02/05/2011,但也可以是任何一天,而且我的一周总是有 7 天。

我现有的代码如下,但似乎没有按预期工作。

public Interval getWeekInterval(Date calendarStartDate, Date date)
{
    Calendar sDate = Calendar.getInstance();
    sDate.setTime(getMidnightDate(calendarStartDate));

    Calendar eDate = Calendar.getInstance();
    eDate.setTime(date);

    Calendar weekStartDate = (Calendar) sDate.clone();
    logger.debug("Date:" + sDate.getTime());
    while (sDate.before(eDate)) {
        weekStartDate = sDate;
        sDate.add(Calendar.DAY_OF_WEEK_IN_MONTH, 1);
    }

    return new Interval(weekStartDate.getTime(), sDate.getTime());
}

If possible I would prefer a joda or non-joda solution for the scenario below

Lets say if my week starts on 02/05/2012 and the given current date is 02/22/2011. I need to calculate the week start and end date for the given current date. So my solution should have the week start as 02/19 and week ends at 02/25.
For simplicity, I have set my week start here as 02/05/2011 but it could be any day potentially and my week always has 7 days.

My existing code is below but doesnt seem to work as expected.

public Interval getWeekInterval(Date calendarStartDate, Date date)
{
    Calendar sDate = Calendar.getInstance();
    sDate.setTime(getMidnightDate(calendarStartDate));

    Calendar eDate = Calendar.getInstance();
    eDate.setTime(date);

    Calendar weekStartDate = (Calendar) sDate.clone();
    logger.debug("Date:" + sDate.getTime());
    while (sDate.before(eDate)) {
        weekStartDate = sDate;
        sDate.add(Calendar.DAY_OF_WEEK_IN_MONTH, 1);
    }

    return new Interval(weekStartDate.getTime(), sDate.getTime());
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

梅窗月明清似水 2025-01-11 16:20:40

定义一周

如果您使用日期时间对象,则应将一周定义为一周结束后当天的第一时刻(但不包括该时刻)。如下图所示。

时间线显示 ( >= start of day 1 ) and ( < start of day 8 )

这种方法称为 半开。这种方法通常用于处理时间跨度。

原因是,从逻辑上讲,新的一天之前的最后一刻可以无限整除为几分之一秒。您可能认为使用“.999”可以处理毫秒级的问题,但是在编写 Java 8 中具有纳秒分辨率而不是毫秒分辨率的新 java.time.* 类时,您可能会犯错误。您可能认为使用“.999999999”可以处理这种情况,但在处理来自许多数据库(例如使用微秒分辨率的 Postgres)“.999999”的日期时间值时,您会犯错误。

在第三方开源Joda-Time库中,这种Half-Open逻辑是它的间隔 类作品。开始是包容性的,结束是排他性的。这效果很好。同样,在 DateTime 上调用 plusWeeks(1) 将一周添加到一天的第一个时刻,即可获得第 8 天之后的第一个时刻(请参见下面的示例) 。

时区

该问题和其他答案忽略了时区问题。如果您不指定,您将获得默认时区。通常最好使用正确的时区名称(不是 3-字母代码)。

Joda-Time

避免 java.util.Date &与 Java 捆绑在一起的日历类。他们是出了名的麻烦。

下面是一些使用 Joda-Time 2.3 的示例代码。

警告:我没有彻底测试以下代码。这只是我的第一次尝试,草稿。很可能存在缺陷。

标准周(周一至周日)

Joda-Time 库是围绕 ISO 8601 标准构建的。该标准将一周的第一天定义为星期一,最后一天定义为星期日。

如果这符合您对一周的定义,那么开始和结束就很容易了。

更新作为下面讨论的替代方案,请参阅这个非常聪明且非常简单的单行SpaceTrucker的解决方案< /a>.

简单地强制星期几是有效的,因为 Joda-Time 假设您希望:

  • 星期一在今天之前(或与今天相同)。
  • 今天之后(或与今天相同)的星期日。
DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" );
DateTime now = new DateTime( timeZone );

DateTime weekStart = now.withDayOfWeek( DateTimeConstants.MONDAY ).withTimeAtStartOfDay();
DateTime weekEnd = now.withDayOfWeek(DateTimeConstants.SUNDAY).plusDays( 1 ).withTimeAtStartOfDay();
Interval week = new Interval( weekStart, weekEnd );

转储到控制台...

System.out.println( "now: " + now );
System.out.println( "weekStart: " + weekStart );
System.out.println( "weekEnd: " + weekEnd );
System.out.println( "week: " + week );

运行时...

now: 2014-01-24T06:29:23.043+01:00
weekStart: 2014-01-20T00:00:00.000+01:00
weekEnd: 2014-01-27T00:00:00.000+01:00
week: 2014-01-20T00:00:00.000+01:00/2014-01-27T00:00:00.000+01:00

要查看日期时间是否在该间隔内,请调用 contains 方法。

boolean weekContainsDate = week.contains( now );

非标准周

如果这不符合您对周的定义,那么您就对该代码进行了修改。

DateTimeZone timeZone = DateTimeZone.forID( "America/New_York" );
DateTime now = new DateTime( timeZone );

DateTime weekStart = now.withDayOfWeek( DateTimeConstants.SUNDAY ).withTimeAtStartOfDay();
if ( now.isBefore( weekStart )) {
    // If we got next Sunday, go back one week to last Sunday.
    weekStart = weekStart.minusWeeks( 1 );
}
DateTime weekEnd = weekStart.plusWeeks( 1 );
Interval week = new Interval( weekStart, weekEnd );

转储到控制台...

System.out.println( "now: " + now );
System.out.println( "weekStart: " + weekStart );
System.out.println( "weekEnd: " + weekEnd );
System.out.println( "week: " + week );

运行时...

now: 2014-01-24T00:54:27.092-05:00
weekStart: 2014-01-19T00:00:00.000-05:00
weekEnd: 2014-01-26T00:00:00.000-05:00
week: 2014-01-19T00:00:00.000-05:00/2014-01-26T00:00:00.000-05:00

Defining A Week

If you are using date-time objects, you should define a week as up to but not including the first moment of the day after the end of week. As seen in this diagram.

Timeline showing ( >= start of day 1 ) and ( < start of day 8 )

This approach is known as Half-Open. This approach is commonly used for working with spans of time.

The reason is because, logically, that last moment of the day before the new day is infinitely divisible as a fraction of a second. You may think that using ".999" would handle that for milliseconds, but then you'd mistaken when writing for the new java.time.* classes in Java 8 that have nanosecond resolution rather than millisecond. You may think think that using ".999999999" would handle that case, but then you’d be mistaken when handling date-time values from many databases such as Postgres that use microsecond resolution, ".999999".

In the third-party open-source Joda-Time library, this Half-Open logic is how its Interval class works. The beginning is inclusive and the ending is exclusive. This works out nicely. Similarly, calling plusWeeks(1) on a DateTime to add a week to the first moment of a day gives you the first moment of the 8th day later (see example below).

Time Zone

The question and other answers ignores the issue of time zone. If you do not specify, you'll be getting the default time zone. Usually better to specify a time zone, using a proper time zone name (not 3-letter code).

Joda-Time

Avoid the java.util.Date & Calendar classes bundled with Java. They are notoriously troublesome.

Here is some example code using Joda-Time 2.3.

CAVEAT: I have not tested of of the below code thoroughly. Just my first take, a rough draft. May well be flawed.

Standard Week (Monday-Sunday)

The Joda-Time library is built around the ISO 8601 standard. That standard defines the first day of the week as Monday, last day as Sunday.

If that meets your definition of a week, then getting the beginning and ending is easy.

UPDATE As an alternative to the discussion below, see this very clever and very simple one-liner solution by SpaceTrucker.

Simply forcing the day-of-week works because Joda-Time assumes you want:

  • Monday to be before (or same as) today.
  • Sunday to be after (or same as) today.
DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" );
DateTime now = new DateTime( timeZone );

DateTime weekStart = now.withDayOfWeek( DateTimeConstants.MONDAY ).withTimeAtStartOfDay();
DateTime weekEnd = now.withDayOfWeek(DateTimeConstants.SUNDAY).plusDays( 1 ).withTimeAtStartOfDay();
Interval week = new Interval( weekStart, weekEnd );

Dump to console…

System.out.println( "now: " + now );
System.out.println( "weekStart: " + weekStart );
System.out.println( "weekEnd: " + weekEnd );
System.out.println( "week: " + week );

When run…

now: 2014-01-24T06:29:23.043+01:00
weekStart: 2014-01-20T00:00:00.000+01:00
weekEnd: 2014-01-27T00:00:00.000+01:00
week: 2014-01-20T00:00:00.000+01:00/2014-01-27T00:00:00.000+01:00

To see if a date-time lands inside that interval, call the contains method.

boolean weekContainsDate = week.contains( now );

Non-Standard Week

If that does not meet your definition of a week, you a twist on that code.

DateTimeZone timeZone = DateTimeZone.forID( "America/New_York" );
DateTime now = new DateTime( timeZone );

DateTime weekStart = now.withDayOfWeek( DateTimeConstants.SUNDAY ).withTimeAtStartOfDay();
if ( now.isBefore( weekStart )) {
    // If we got next Sunday, go back one week to last Sunday.
    weekStart = weekStart.minusWeeks( 1 );
}
DateTime weekEnd = weekStart.plusWeeks( 1 );
Interval week = new Interval( weekStart, weekEnd );

Dump to console…

System.out.println( "now: " + now );
System.out.println( "weekStart: " + weekStart );
System.out.println( "weekEnd: " + weekEnd );
System.out.println( "week: " + week );

When run…

now: 2014-01-24T00:54:27.092-05:00
weekStart: 2014-01-19T00:00:00.000-05:00
weekEnd: 2014-01-26T00:00:00.000-05:00
week: 2014-01-19T00:00:00.000-05:00/2014-01-26T00:00:00.000-05:00
浪荡不羁 2025-01-11 16:20:40

一周的第一天取决于国家/地区。
使计算变得脆弱的原因是,人们可能会打破年份边界和周数 (Calendar.WEEK_OF_YEAR)。可以执行以下操作:

    Calendar currentDate = Calendar.getInstance(Locale.US);
    int firstDayOfWeek = currentDate.getFirstDayOfWeek();

    Calendar startDate = Calendar.getInstance(Locale.US);
    startDate.setTime(currentDate.getTime());
    //while (startDate.get(Calendar.DAY_OF_WEEK) != firstDayOfWeek) {
    //    startDate.add(Calendar.DATE, -1);
    //}
    int days = (startDate.get(Calendar.DAY_OF_WEEK) + 7 - firstDayOfWeek) % 7;
    startDate.add(Calendar.DATE, -days);

    Calendar endDate = Calendar.getInstance(Locale.US);
    endDate.setTime(startDate.getTime());
    endDate.add(Calendar.DATE, 6);

日历中的错误破坏了您的代码,克隆似乎只是给出了相同的对象,因此最终您拥有相同的日期。 (至少 Java 7)。

First day of week depends on the country.
What makes the calculation fragile, is that one may break the year boundary, and the week number (Calendar.WEEK_OF_YEAR). The following would do:

    Calendar currentDate = Calendar.getInstance(Locale.US);
    int firstDayOfWeek = currentDate.getFirstDayOfWeek();

    Calendar startDate = Calendar.getInstance(Locale.US);
    startDate.setTime(currentDate.getTime());
    //while (startDate.get(Calendar.DAY_OF_WEEK) != firstDayOfWeek) {
    //    startDate.add(Calendar.DATE, -1);
    //}
    int days = (startDate.get(Calendar.DAY_OF_WEEK) + 7 - firstDayOfWeek) % 7;
    startDate.add(Calendar.DATE, -days);

    Calendar endDate = Calendar.getInstance(Locale.US);
    endDate.setTime(startDate.getTime());
    endDate.add(Calendar.DATE, 6);

One bug in Calendar breaks your code, clone, seems to simply give the identical object, hence at the end you have identical dates. (Java 7 at least).

意犹 2025-01-11 16:20:40
 DateTime sDateTime = new DateTime(startDate); // My calendar start date
 DateTime eDateTime = new DateTime(date); // the date for the week to be determined

 Interval interval = new Interval(sDateTime, sDateTime.plusWeeks(1));
 while(!interval.contains(eDateTime))
 {
    interval = new Interval(interval.getEnd(), interval.getEnd().plusWeeks(1));
 }
 return interval;
 DateTime sDateTime = new DateTime(startDate); // My calendar start date
 DateTime eDateTime = new DateTime(date); // the date for the week to be determined

 Interval interval = new Interval(sDateTime, sDateTime.plusWeeks(1));
 while(!interval.contains(eDateTime))
 {
    interval = new Interval(interval.getEnd(), interval.getEnd().plusWeeks(1));
 }
 return interval;
天荒地未老 2025-01-11 16:20:40

试试这个(伪代码):

// How many days gone after reference date (a known week-start date)
daysGone  = today - referenceDate;

// A new week starts after each 7 days
dayOfWeek = daysGone % 7;

// Now, we know today is which day of the week.
// We can find start & end days of this week with ease
weekStart = today - dayOfWeek;
weekEnd   = weekStart + 6;

现在,我们可以将所有这些缩短为两行:

weekStart = today - ((today - referenceDate) % 7);
weekEnd   = weekStart + 6;

注意我们减去了整数等日期值来显示算法。你必须正确编写你的java代码。

Try this (pseudo-code):

// How many days gone after reference date (a known week-start date)
daysGone  = today - referenceDate;

// A new week starts after each 7 days
dayOfWeek = daysGone % 7;

// Now, we know today is which day of the week.
// We can find start & end days of this week with ease
weekStart = today - dayOfWeek;
weekEnd   = weekStart + 6;

Now, we can shorten all of this to two lines:

weekStart = today - ((today - referenceDate) % 7);
weekEnd   = weekStart + 6;

Note that we subtracted date values like integers to show algorithm. You have to write your java code properly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文