根据Java 8中的LocalDate.now()获取一周的第一天的日期

我希望根据LocalDate.now()得到一周中第一天的日期。 使用JodaTime可以实现以下function,但似乎已从Java 8中的新Date API中删除。

LocalDate now = LocalDate.now(); System.out.println(now.withDayOfWeek(DateTimeConstants.MONDAY)); 

我不能称’withDayOfWeek()’,因为它不存在。

所以我的问题是:如何根据一些LocalDate获取一周中第一天的日期?

请注意,表达式System.out.println(now.with(DayOfWeek.MONDAY))与区域设置无关,因为它使用ISO-8601,因此它总是向后跳到上周一(或者在星期一停留,以防日期已经指向星期一) )。

因此,在美国或其他一些国家 – 周日开始周日 – 它可能无法正常工作 – now.with(DayOfWeek.MONDAY) 不会跳到周一,如果日期指向星期日。

如果您需要解决这些问题,最好使用本地化字段WeekFields.dayOfWeek() :

 LocalDate now = LocalDate.now(); TemporalField fieldISO = WeekFields.of(Locale.FRANCE).dayOfWeek(); System.out.println(now.with(fieldISO, 1)); // 2015-02-09 (Monday) TemporalField fieldUS = WeekFields.of(Locale.US).dayOfWeek(); System.out.println(now.with(fieldUS, 1)); // 2015-02-08 (Sunday) 

另一个例子是由于下面的评论:

 LocalDate ld = LocalDate.of(2017, 8, 18); // Friday as original date System.out.println( ld.with(DayOfWeek.SUNDAY)); // 2017-08-20 (2 days later according to ISO) // Now let's again set the date to Sunday, but this time in a localized way... // the method dayOfWeek() uses localized numbering (Sunday = 1 in US and = 7 in France) System.out.println(ld.with(WeekFields.of(Locale.US).dayOfWeek(), 1L)); // 2017-08-13 System.out.println(ld.with(WeekFields.of(Locale.FRANCE).dayOfWeek(), 7L)); // 2017-08-20 

美国的例子清楚地表明,居住在美国的人会期望持续到下周日,因为周日被视为美国的第一天。 with(DayOfWeek.SUNDAY)的基于ISO的简单表达式忽略了此本地化问题。

尝试

 System.out.println(now.with(DayOfWeek.MONDAY)); 

尽管有以前的所有答案,我仍然需要深入研究Java8正在做什么,所以我发现这是最直观的方法:

LocalDate实现Temporal

with(TemporalField field, long newValue)

返回与此对象相同类型的对象,并更改指定的字段。

所以我们必须告诉它我们要更改的LocalDate哪个日期部分( DAY_OF_WEEK )并更改为什么值。

如果您怀疑本周的日期可能从0到6或从1到7计算:

  System.out.printf("first day of week (0 or 1) == %d \n", ChronoField.DAY_OF_WEEK.range().getMinimum()); 
 first day of week (0 or 1) == 1 

我不得不确定我的JDK为默认设置提供的内容 – YMMV:

  System.out.printf("default zone offset==[%s]\n", ZoneId.systemDefault()); System.out.printf("1st day of week==%s\n", WeekFields.of(Locale.getDefault()).getFirstDayOfWeek()); 
 default zone offset==[Europe/London] 1st day of week==MONDAY 

所以如果我根据这些默认值执行一些代码,就像这样:

  LocalDate localDate = LocalDate.now(); System.out.printf("localDate == %s \n", localDate); System.out.printf("localdate first day of week == %s (%s) \n", localDate.with(ChronoField.DAY_OF_WEEK, 1), localDate.with(ChronoField.DAY_OF_WEEK, 1).getDayOfWeek()); 
 localDate == 2017-10-24 localdate first day of week == 2017-10-23 (MONDAY) 

然后Java使用ChronoField.DAY_OF_WEEK ,它不仅定义了我们想要改变的日期的哪一部分,而且还定义了如何改变它。

因此,如果我们希望我们的代码处理用户指定为一周中第一天的任何内容,我们将使用WeekFields.of()工厂方法创建自己的基于周计算的方式。

使用这个,我们可以将自己的dayOfWeek参数传递给with()以我们想要的方式进行日期计算:

  TemporalField myWeek = WeekFields.of(DayOfWeek.SUNDAY, 1).dayOfWeek(); System.out.printf("configured localdate first day of week == %s (%s) \n", localDate.with(myWeek, 1), localDate.with(myWeek, 1).getDayOfWeek()); 
 configured localdate first day of week == 2017-10-22 (SUNDAY) 

要了解更多信息,请查看LocalDate.with()中的代码,这非常有趣。

感谢来自 这个问题 。

 Calendar cal = Calendar.getInstance(); cal.set(Calendar.HOUR_OF_DAY, 0); // ! clear would not reset the hour of day ! cal.clear(Calendar.MINUTE); cal.clear(Calendar.SECOND); cal.clear(Calendar.MILLISECOND); // get start of this week in milliseconds cal.set(Calendar.DAY_OF_WEEK, cal.getFirstDayOfWeek()); System.out.println("Start of this week: " + cal.getTime()); System.out.println("... in milliseconds: " + cal.getTimeInMillis()); 

正如Ray所说的正确答案 ,你可以调用并传递DayOfWeek枚举。

时区

请注意,时区对于确定“今天”的日期至关重要。 在任何时候,日期都会因您站在地球上的位置而异。

 ZoneId zoneId = ZoneId.of ( "America/Montreal" ); LocalDate firstDayOfThisWeek = LocalDate.now ( zoneId ).with ( DayOfWeek.MONDAY ); 

如果未指定时区,则会以静默方式应用JVM的当前默认时区。 注意:默认情况下可以在运行时随时更改 最好指定所需/预期的时区 。

ZonedDateTime

您可以将时区( ZoneId )应用于LocalDate以获取表示一周中第一时刻的ZonedDateTime

 ZonedDateTime thisWeekStart = firstDayOfThisWeek.atStartOfDay ( zoneId ); 

LocalDate似乎没有这个,但是WeekFields(来自java-8 API)确实( 这里 )。 所以你可以这样做:

 WeekFields.of(Locale.getDefault()).firstDayOfWeek.value 

这将返回星期的第一天的值,从1开始为星期一,以7结尾为星期日。

使用示例(在Kotlin中),获取一个设置了dayOfWeek的新LocalDate,时间倒退而不是前进:

 /**@param targetDayOfWeek day of week to go to, starting from 1 as Monday (and 7 is Sunday) */ fun LocalDate.minusDaysToDayOfWeek(targetDayOfWeek: Int = WeekFields.of(Locale.getDefault()).firstDayOfWeek.value): LocalDate { //conversion so that Sunday is 0, Monday is 1, etc: val diffDays = (dayOfWeek.value % 7) - (targetDayOfWeek % 7) val result = when { diffDays == 0 -> this diffDays < 0 -> minusDays((7 + diffDays).toLong()) else -> minusDays(diffDays.toLong()) } return result } 

输入输出示例:

 2017-12-31 -> 2017-12-31 2018-01-01 -> 2017-12-31 2018-01-02 -> 2017-12-31 2018-01-03 -> 2017-12-31 2018-01-04 -> 2017-12-31 2018-01-05 -> 2017-12-31 2018-01-06 -> 2017-12-31 2018-01-07 -> 2018-01-07 2018-01-08 -> 2018-01-07 2018-01-09 -> 2018-01-07 2018-01-10 -> 2018-01-07 2018-01-11 -> 2018-01-07 2018-01-12 -> 2018-01-07 2018-01-13 -> 2018-01-07 2018-01-14 -> 2018-01-14 2018-01-15 -> 2018-01-14 

这是一个示例函数,可以及时前进到目标星期几:

 fun LocalDate.plusDaysToDayOfWeek(targetDayOfWeek: Int = getLastDayOfWeek()): LocalDate { val diffDays = (targetDayOfWeek % 7) - (dayOfWeek.value % 7) val result = when { diffDays == 0 -> this diffDays < 0 -> plusDays((7 + diffDays).toLong()) else -> plusDays(diffDays.toLong()) } return result } /**@return the last day of week, when 1 is Monday ... 7 is Sunday) */ @JvmStatic fun getLastDayOfWeek(firstDayOfWeek: DayOfWeek = WeekFields.of(Locale.getDefault()).firstDayOfWeek): Int { return when (firstDayOfWeek) { DayOfWeek.MONDAY -> DayOfWeek.SUNDAY.value else -> firstDayOfWeek.value - 1 } } 

顺便说一句,奇怪的是我认为新API背后的代码实际上使用的是Calendar类……

如果你不喜欢使用dayOfWeek用于LocalDate(和我一样),而你更喜欢用于Calendar的那个,你可以使用这些简单的转换器:

 fun DayOfWeek.toCalendarDayOfWeek(): Int { return when (this) { DayOfWeek.SATURDAY -> Calendar.SATURDAY else -> (this.value + 1) % 7 } } @JvmStatic fun convertLocalDateDayOfWeekToCalendarDayOfWeek(localDateDayOfWeek: Int): Int { return when (localDateDayOfWeek) { DayOfWeek.SATURDAY.value -> Calendar.SATURDAY else -> (localDateDayOfWeek + 1) % 7 } } @JvmStatic fun convertFromCalendarDayOfWeekToLocalDateDayOfWeek(calendarDayOfWeek: Int): Int { return when (calendarDayOfWeek) { Calendar.SUNDAY -> DayOfWeek.SUNDAY.value else -> calendarDayOfWeek - 1 } } 

有了Joda Time,您怎么看?

 now.toString("EEEE", locale)