Java 8 LocalDate:确定每月的哪个星期一(第 1、第 2、第 3 等)

Posted

技术标签:

【中文标题】Java 8 LocalDate:确定每月的哪个星期一(第 1、第 2、第 3 等)【英文标题】:Java 8 LocalDate: Determine What Monday of the Month its (1st, 2nd, 3rd, etc) 【发布时间】:2018-06-17 17:29:10 【问题描述】:

我试图弄清楚如何确定某个特定的星期一是给定月份的第一个、第二个、第三个或第四个星期一。我已经弄清楚如何使用 LocalDate 类来获取下周一和每月的一周。

LocalDate now = LocalDate.of(2018, 2, 1);
LocalDate nextMonday = now.with(next(DayOfWeek.MONDAY));
WeekFields weekFields = WeekFields.of(Locale.getDefault());
int week = nextMonday.get(weekFields.weekOfMonth());

在上面的示例中,代码获取下一个星期一和它所在的星期。星期是二月的第二个星期,但那个星期一不是第二个星期一,而是第一个星期一。对此的任何帮助将不胜感激。

【问题讨论】:

java2s.com/Tutorials/Java/java.time/LocalDate/index.htm 前 7 天的第一个星期一,接下来的 7 天的第二个星期一,依此类推。所以从月份中减去 1,除以 7,再加 1。 @AndyTurner 我并不热衷于将给定日期除以数字,你能举个例子吗? 有趣的问题:java.time 有类似Calendar.DAY_OF_WEEK_IN_MONTH 的东西吗?它用于设置月份中的星期几,例如将星期一更改为该月的第三个星期一:TemporalAdjusters.dayOfWeekInMonth。但是为了得到? 【参考方案1】:

您不应该为此使用自己的算术。使用内置功能:

    int week = nextMonday.get(ChronoField.ALIGNED_WEEK_OF_MONTH);

根据您的代码中的日期,这会产生:

1

这意味着您获得的星期一(2 月 5 日)是该月的第一个星期一。此外,您不需要任何 WeekFields,因为无论哪一天是一周的第一天,或者一年中的周数如何编号,每个月的第一个星期一都是该月的第一个星期一。

日期算术通常很复杂且容易出错。这也意味着即使您最终计算正确,读者也很难说服自己/他自己您的代码是正确的。因此,最好使用我们相信要进行测试的内置功能,它使用解释性名称而不是像 1 和 7 这样的数字。

您可能会对要使用的字段名为ALIGNED_WEEK_OF_MONTH 感到惊讶。将对齐的周视为从每月 1 日开始的一周,无论是在一周中的哪一天,以及接下来的几周。 2018 年 2 月,第一个对齐周从 2 月 1 日星期四到 2 月 7 日星期三。接下来的对齐周从 2 月 8 日、2 月 15 日和 2 月 22 日星期四开始。显然,该月的第一个星期一在对齐的第 1 周,第 2 周的第 2 个星期一等。因此可以使用 ALIGNED_WEEK_OF_MONTH

【讨论】:

【参考方案2】:

编辑:您应该选择 Ole V. V 的答案 (ChronoField.ALIGNED_WEEK_OF_MONTH) 而不是这个答案。

你可以算出月份中的哪一天,除以 7 再加上 1:

LocalDate nextMonday = now.with(next(DayOfWeek.MONDAY));
int weekNo = ((nextMonday.getDayOfMonth()-1) / 7) +1;

例如这段代码:

LocalDate now = LocalDate.of(2018, 2, 1);
for(int i = 0; i < 10; i++) 
    now = now.with(next(DayOfWeek.MONDAY));
    int weekNo = ((now.getDayOfMonth()-1) / 7) +1;
    System.out.println("Date : " + now + " == " + weekNo);

打印出以下内容,我相信这是你想要的……

Date : 2018-02-05 == 1
Date : 2018-02-12 == 2
Date : 2018-02-19 == 3
Date : 2018-02-26 == 4
Date : 2018-03-05 == 1
Date : 2018-03-12 == 2
Date : 2018-03-19 == 3
Date : 2018-03-26 == 4
Date : 2018-04-02 == 1
Date : 2018-04-09 == 2

【讨论】:

除以7前要减1,否则会说7号和1号不在同一周。 @AndyTurner 很好,已修复。 我相信@AndyTurner 的观点很好地说明了使用你自己的算法来完成这样的任务的危险。我建议您改用内置功能。 【参考方案3】:

您可以尝试从日期中反复减去一周,直到月份发生变化。那么您执行该操作的次数将是原始日期的“该月一周中的第 X 天”。

编辑:一些代码。

LocalDate now = LocalDate.of(2018, 2, 1);

int i = 0;
Month originalMonth = now.getMonth();
while (now.getMonth() == originalMonth)  // its an enum, you can do this
    now = now.plusWeeks(-1);
    i++;


System.out.println(i); // prints 1

【讨论】:

【参考方案4】:
String[] arr =  "2018-01-01", "2018-01-07", "2018-01-30", "2018-01-22", 
               "2018-01-25" ;
for (String str : arr) 
    LocalDate ld = LocalDate.parse(str);
    ld = ld.with(TemporalAdjusters.nextOrSame(DayOfWeek.MONDAY));
    int res = (ld.getDayOfMonth()/7) + 
                   (Integer.min(1, ld.getDayOfMonth() % 7));
    System.out.printf("%s  => %d\n", str, res);

【讨论】:

以上是关于Java 8 LocalDate:确定每月的哪个星期一(第 1、第 2、第 3 等)的主要内容,如果未能解决你的问题,请参考以下文章

在 mongoDB 中存储 java 8 LocalDate

Java 8 LocalDate 到 JavaScript 日期

Java 8 Time Api 使用(LocalDate,LocalTime和LocalDateTime等)

Java 8 Time Api 使用(LocalDate,LocalTime和LocalDateTime等)

在数据库中使用Java 8 LocalDate和LocalDateTime进行Hibernate

使用 Java 8 流在 LocalDate 属性的对象列表中查找最近的日期