【问题标题】:What is the best way to retrieve the dates for last Monday and Friday检索上周一和周五日期的最佳方法是什么
【发布时间】:2012-09-21 14:09:03
【问题描述】:

我需要获取上周星期一和星期五的日期。为此,我得到本周星期一的日期并减去 7 天。这给了我上周星期一的日期。

要获得星期五的日期,我必须添加 4。这让我有点困惑,因为由于某种原因,一周的第一天是星期日,而不是英国的星期一。

无论如何,这就是我获取日期的方式。

            // Get the dates for last MON & FRI
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);

        cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        cal.add(Calendar.DAY_OF_WEEK, -7);

        cal.set(Calendar.HOUR_OF_DAY,0);
        cal.set(Calendar.MINUTE,0);
        cal.set(Calendar.SECOND,0);
        cal.set(Calendar.MILLISECOND,0);

        // Get the date on Friday
        cal.add(Calendar.DAY_OF_WEEK, 4);

        cal.set(Calendar.HOUR_OF_DAY,23);
        cal.set(Calendar.MINUTE,59);
        cal.set(Calendar.SECOND,59);
        cal.set(Calendar.MILLISECOND,0);

上述方法有效,但如果逻辑有任何问题,我很感兴趣。 IE。它适用于二月、闰年等吗?

欢迎提出更好的解决方案/方法。

谢谢

【问题讨论】:

  • 由于星期是有规律的,我认为 2 月或闰年没有任何问题:如果今天是星期一,那么最后一个星期一就是 7 天前。
  • 如果你昨天运行它,你期望得到什么结果?如果你今天运行它会怎样?昨天它会给 2012-09-17 星期一,今天是 2012-09-24。
  • 我希望它返回上周周一和周五的日期。因此,如果我昨天(甚至今天)运行它,两次运行都应该给我第 17 和第 21 名。如果我明天运行它,那是新的一周,它应该给我 24 和 29 日。
  • 你如何定义“上周”?最后七天?标准的周一至周日时段?本地化周,例如美国的周日至周六?今天的前一周还是包括今天的部分星期?

标签: java date datetime calendar


【解决方案1】:

tl;博士

获取上周周一和周五的日期

LocalDate                                           // Represent a date only, without a time-of-day, and without a time zone or offset.
.now                                                // Capture the current date as seen through the wall-clock time used by the people of a certain region (a time zone). 
( 
    ZoneId.of( "America/Montreal" ) 
)                                                   // Returns a `LocalDate` object.
.with                                               // Move to another date.
( 
    TemporalAdjusters.previous( DayOfWeek.MONDAY )  // Returns an implementation of the `TemporalAdjuster` interface.
)                                                   // Returns another `LocalDate` object, separate and distinct from our original `LocalDate` object. Per the immutable objects design pattern. 

避免使用旧的日期时间类

其他答案使用麻烦的旧日期时间类,现在已被 java.time 问题所取代。

LocalDate

LocalDate 类表示没有时间和时区的仅日期值。

时区对于确定日期至关重要。对于任何给定的时刻,日期在全球范围内因区域而异。例如,Paris France 中午夜过后几分钟是新的一天,而 Montréal Québec 中仍然是“昨天”。

ZoneId z = ZoneId.of( “America/Montreal” );
LocalDate today = LocalDate.now( z );

TemporalAdjuster

TemporalAdjuster 接口提供了从一个日期时间值移动到另一个日期时间值的调整。在TemporalAdjusters 类中找到方便的实现(注意复数's')。 previous 调整器从 DayOfWeek 枚举中找到任何指定的对象。

该问题并未准确定义“上周”。最后七天?标准的周一至周日时段?本地化周,例如美国的周日至周六?今天的前一周还是包括今天的部分星期?

我会假设前 7 天是预定的。

LocalDate previousMonday = today.with( TemporalAdjusters.previous( DayOfWeek.MONDAY ) ) ;
LocalDate previousFriday = today.with( TemporalAdjusters.previous( DayOfWeek.FRIDAY ) ) ;

顺便说一句,如果您想考虑初始日期(如果它恰好已经是所需的星期几),请使用备用 TemporalAdjuster 实现:previousOrSamenextOrSame


关于java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。

从哪里获得 java.time 类?

  • Java SE 8Java SE 9 及更高版本
    • 内置。
    • 标准 Java API 的一部分,带有捆绑实现。
    • Java 9 添加了一些小功能和修复。
  • Java SE 6Java SE 7
    • ThreeTen-Backport 中的大部分 java.time 功能都向后移植到 Java 6 和 7。
  • Android
    • java.time 类的 Android 捆绑包实现的更高版本。
    • 对于早期的 Android (ThreeTenABP 项目采用 ThreeTen-Backport(如上所述)。见How to use ThreeTenABP…

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

【讨论】:

  • 'previousMonday' 值可能是本周的星期一
  • @qianlei 不,不是本周的星期一。该问题明确要求“上周星期一的日期”。但是,如果想要使用初始日期(如果它已经在所需的星期几),请使用替代的 TemporalAdjuster 实现:TemporalAdjusters.previousOrSame( DayOfWeek )TemporalAdjusters.nextOrSame( DayOfWeek )
【解决方案2】:

注意:对于 Java 8 及更高版本,请查看 Basil Bourque 的答案 (link)。
Java 8 引入了一个新的时间/日期 API,它提供了 Joda-Time 的大部分功能。


Joda-Time 为此类问题提供了非常好的方法。

使用 Joda Time 获取上周星期一和星期五的日期看起来像这样:

DateTime today = DateTime.now();
DateTime sameDayLastWeek = today.minusWeeks(1);
DateTime mondayLastWeek = sameDayLastWeek.withDayOfWeek(DateTimeConstants.MONDAY);
DateTime fridayLastWeek = sameDayLastWeek.withDayOfWeek(DateTimeConstants.FRIDAY);

您可以从java.util.Date 对象创建DateTime 对象,反之亦然,因此很容易与Java 日期一起使用。


用上面的代码加上日期

DateTime today = new DateTime("2012-09-30");

结果为星期一的“2012-09-17”和星期五的“2012-09-21”,将日期设置为

DateTime tomorrow = new DateTime("2012-10-01");

周一的结果为“2012-09-24”,周五的结果为“2012-09-28”。

【讨论】:

    【解决方案3】:

    您仍然将周开始设置为星期日,这意味着星期六的 Calendar.MONDAY 是前一个星期一,而星期日的 Calendar.MONDAY 是第二天。

    您需要做的是(根据您在上面的评论中想要的方式),将一周的开始设置为星期一。

    Calendar cal = Calendar.getInstance();
    cal.setFirstDayOfWeek(Calendar.MONDAY);
    
    cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
    cal.add(Calendar.DAY_OF_WEEK, -7); 
    ...
    

    除此之外,周五的最后一秒不包括在范围内,您的逻辑似乎是合理的,并且在闰年/DST 转换等方面应该没有问题。

    【讨论】:

    • 我会很快补充一点,如果一周中的当前日期是星期一,您仍然会转到前一个星期一,以防有人对这种极端情况感到疑惑。
    【解决方案4】:

    我看到的唯一错误是您实际上是在测试 范围 Mo-Fr,而不是如前所述,检索两个特定的日子。使用专属上限测试 Mo-Sa 范围会更安全。

    【讨论】:

    • 我不太明白你的意思。检索两个特定日期(星期一和星期五)是我想要做的。你的意思是我应该得到周一到周六的范围,然后从那一周得到周一和周五的日期?
    • Ziggy,我看到您将星期五日期的时间设置为 23:59:59。这对我来说是一个强有力的迹象,表明您的意图是针对此上限检查某些日期。我的建议是使用周六午夜作为唯一的上限。
    • @gekkostate 根据要求,我提出了一个更好的方法。为什么你认为这不能作为答案?光是字数就困扰你吗?
    • 嗨,Marko,我需要在数据库中运行查询以检索报告数据。我想包含在报告中的数据只是从周一早上到周五晚上。我不想包含周六的数据。
    • Ziggy 这正是我的观点。使用周六午夜作为专属上限是实现目标的正确方法。
    猜你喜欢
    • 1970-01-01
    • 2017-09-16
    • 2014-03-13
    • 2021-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-12
    • 1970-01-01
    相关资源
    最近更新 更多