根据 Java 中的 LocalDate.now() 获取一周第一天的日期 8
Get date of first day of week based on LocalDate.now() in Java 8
我想根据 LocalDate.now() 获取一周中第一天的日期。 JodaTime 可以实现以下内容,但似乎已从 Java 8.
中的新日期 API 中删除
LocalDate now = LocalDate.now();
System.out.println(now.withDayOfWeek(DateTimeConstants.MONDAY));
我不能调用'withDayOfWeek()',因为它不存在。
所以我的问题是: 如何根据一些 LocalDate 获取一周的第一天的日期?
尝试
System.out.println(now.with(DayOfWeek.MONDAY));
感谢come from in this question。
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());
请注意,表达式 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
美国的例子非常清楚地表明,居住在美国的人希望去到最后一个而不是下个星期日,因为星期日在美国被认为是一周的第一天。基于 ISO 的简单表达式 with(DayOfWeek.SUNDAY)
忽略了这个本地化问题。
作为 by Ray says, you can call with
and pass the DayOfWeek
枚举。
时区
请注意,时区对于确定 "today" 的日期至关重要。在任何时候,日期都会因您在地球上所处的位置而异。
ZoneId zoneId = ZoneId.of ( "America/Montreal" );
LocalDate firstDayOfThisWeek = LocalDate.now ( zoneId ).with ( DayOfWeek.MONDAY );
如果您不指定时区,则会静默应用 JVM 当前的默认时区。当心:在运行时 期间,默认值可以随时更改! 最好指定 your desired/expected time zone.
ZonedDateTime
您可以应用时区(ZoneId
) to your LocalDate
to get a ZonedDateTime
代表一周的第一时刻。
ZonedDateTime thisWeekStart = firstDayOfThisWeek.atStartOfDay ( zoneId );
有了Joda Time,你觉得怎么样
now.toString("EEEE", locale)
尽管前面有所有答案,但我仍然不得不四处挖掘以弄清楚 Java8 在做什么,所以这是我发现最直观的方法:
LocalDate implements Temporal
with(TemporalField field, long newValue)
Returns an object of the same type as this object with the specified field altered.
所以我们必须告诉它我们要更改 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()
中的代码,它非常有趣。
LocalDate 似乎没有这个,但是 WeekFields(来自 java-8 API)有 (here)。所以你可以这样做:
WeekFields.of(Locale.getDefault()).firstDayOfWeek.value
这个returns一周第一天的值,从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 的幕后代码实际上使用日历 class 无论如何...
如果您不喜欢使用用于 LocalDate 的 dayOfWeek(就像我一样),而您更喜欢用于 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
}
}
如果我想将 星期一 作为本周的第一天,它对我有用:
LocalDate mondayDate = LocalDate.now().with(WeekFields.of(Locale.FRANCE).getFirstDayOfWeek());
public void getWeekFromADateOfAMonth(){
String date = "2019-01-02T18:25:43.511Z";
TemporalField fieldISO = WeekFields.of(Locale.US).dayOfWeek();
ZonedDateTime dateTime = ZonedDateTime.parse(date);
int week = dateTime.get ( IsoFields.WEEK_OF_WEEK_BASED_YEAR );
int weekYear = dateTime.get ( IsoFields.WEEK_BASED_YEAR );
System.out.println ( "now: " + dateTime + " is week: " + week + " of weekYear: " + weekYear );
int startDate = dateTime.with(fieldISO,1).getDayOfMonth();
int endDate = dateTime.with(fieldISO,7).getDayOfMonth();
String startMonth = String.valueOf(dateTime.with(fieldISO,1).getMonth());
String endMonth = String.valueOf(dateTime.with(fieldISO,7).getMonth());
}
LocalDate.now( ZoneId.systemDefault()).with( TemporalAdjusters.previousOrSame( DayOfWeek.MONDAY ) );
这return本周的第一个星期一(考虑今天是否是星期一)
我想根据 LocalDate.now() 获取一周中第一天的日期。 JodaTime 可以实现以下内容,但似乎已从 Java 8.
中的新日期 API 中删除LocalDate now = LocalDate.now();
System.out.println(now.withDayOfWeek(DateTimeConstants.MONDAY));
我不能调用'withDayOfWeek()',因为它不存在。
所以我的问题是: 如何根据一些 LocalDate 获取一周的第一天的日期?
尝试
System.out.println(now.with(DayOfWeek.MONDAY));
感谢come from in this question。
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());
请注意,表达式 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
美国的例子非常清楚地表明,居住在美国的人希望去到最后一个而不是下个星期日,因为星期日在美国被认为是一周的第一天。基于 ISO 的简单表达式 with(DayOfWeek.SUNDAY)
忽略了这个本地化问题。
作为 with
and pass the DayOfWeek
枚举。
时区
请注意,时区对于确定 "today" 的日期至关重要。在任何时候,日期都会因您在地球上所处的位置而异。
ZoneId zoneId = ZoneId.of ( "America/Montreal" );
LocalDate firstDayOfThisWeek = LocalDate.now ( zoneId ).with ( DayOfWeek.MONDAY );
如果您不指定时区,则会静默应用 JVM 当前的默认时区。当心:在运行时 期间,默认值可以随时更改! 最好指定 your desired/expected time zone.
ZonedDateTime
您可以应用时区(ZoneId
) to your LocalDate
to get a ZonedDateTime
代表一周的第一时刻。
ZonedDateTime thisWeekStart = firstDayOfThisWeek.atStartOfDay ( zoneId );
有了Joda Time,你觉得怎么样
now.toString("EEEE", locale)
尽管前面有所有答案,但我仍然不得不四处挖掘以弄清楚 Java8 在做什么,所以这是我发现最直观的方法:
LocalDate implements Temporal
with(TemporalField field, long newValue)
Returns an object of the same type as this object with the specified field altered.
所以我们必须告诉它我们要更改 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()
中的代码,它非常有趣。
LocalDate 似乎没有这个,但是 WeekFields(来自 java-8 API)有 (here)。所以你可以这样做:
WeekFields.of(Locale.getDefault()).firstDayOfWeek.value
这个returns一周第一天的值,从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 的幕后代码实际上使用日历 class 无论如何...
如果您不喜欢使用用于 LocalDate 的 dayOfWeek(就像我一样),而您更喜欢用于 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
}
}
如果我想将 星期一 作为本周的第一天,它对我有用:
LocalDate mondayDate = LocalDate.now().with(WeekFields.of(Locale.FRANCE).getFirstDayOfWeek());
public void getWeekFromADateOfAMonth(){
String date = "2019-01-02T18:25:43.511Z";
TemporalField fieldISO = WeekFields.of(Locale.US).dayOfWeek();
ZonedDateTime dateTime = ZonedDateTime.parse(date);
int week = dateTime.get ( IsoFields.WEEK_OF_WEEK_BASED_YEAR );
int weekYear = dateTime.get ( IsoFields.WEEK_BASED_YEAR );
System.out.println ( "now: " + dateTime + " is week: " + week + " of weekYear: " + weekYear );
int startDate = dateTime.with(fieldISO,1).getDayOfMonth();
int endDate = dateTime.with(fieldISO,7).getDayOfMonth();
String startMonth = String.valueOf(dateTime.with(fieldISO,1).getMonth());
String endMonth = String.valueOf(dateTime.with(fieldISO,7).getMonth());
}
LocalDate.now( ZoneId.systemDefault()).with( TemporalAdjusters.previousOrSame( DayOfWeek.MONDAY ) );
这return本周的第一个星期一(考虑今天是否是星期一)