【问题标题】:Get the week start and end date given a current date and week start在给定当前日期和周开始的情况下获取周开始和结束日期
【发布时间】:2012-02-10 22:43:19
【问题描述】:

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

假设我的一周从 2012 年 2 月 5 日开始,并且给定的当前日期是 2011 年 2 月 22 日。我需要计算给定当前日期的周开始日期和结束日期。所以我的解决方案应该从 02/19 开始一周,在 02/25 结束一周。 为简单起见,我在这里将我的一周开始时间设置为 2011 年 2 月 5 日,但它可能是任何一天,我的一周总是有 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());
}

【问题讨论】:

  • 你期待什么,你得到了什么?
  • 好的,我调用了 getWeekInterval("02/05/2012", "02/11/2012")。我预计 02/05-02/12 但我得到了 02/12-02/12

标签: java date jodatime


【解决方案1】:

定义一周

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

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

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

在第三方开源的Joda-Time库中,这个Half-Open逻辑就是它的Interval类的工作原理。开头是包容的,结尾是排他的。这很好。同样,在DateTime 上调用plusWeeks(1) 将一周添加到一天的第一个时刻会为您提供第8 天后的第一个时刻(参见下面的示例)。

时区

问题和其他答案忽略了时区问题。如果您不指定,您将获得默认时区。通常最好使用proper time zone name(不是三字母代码)指定时区。

乔达时间

避免使用 Java 捆绑的 java.util.Date 和 Calendar 类。它们是出了名的麻烦。

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

CAVEAT:我没有彻底测试过以下代码。只是我的初稿,草稿。可能有缺陷。

标准周(周一至周日)

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

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

更新 作为下面讨论的替代方案,请参阅这个非常聪明且非常简单的单行代码solution by SpaceTrucker

只需强制执行星期几即可,因为 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

【讨论】:

    【解决方案2】:

    一周的第一天取决于国家/地区。 使计算变得脆弱的原因是,可能会打破年份边界和周数(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);
    

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

    【讨论】:

      【解决方案3】:
       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;
      

      【讨论】:

        【解决方案4】:

        试试这个(伪代码):

        // 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代码。

        【讨论】:

        • 感谢伪代码。我设法使用 Joda Time 找到了一个好的工作解决方案
        猜你喜欢
        • 2012-07-25
        • 2010-11-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-05-18
        相关资源
        最近更新 更多