使用 with* 函数、TemporalAdjusters 或通过设置 TemporalFields 调整 ZonedDateTimes 之间有什么区别吗?
Is there ever any difference between adjusting ZonedDateTimes using the with* functions, TemporalAdjusters or by setting TemporalFields?
假设我有以下代码:
java.time.ZonedDateTime inputZonedDateTime = inputDate.toInstant().atZone(zoneId);
ZonedDateTime flattenedDateTime = inputZonedDateTime.withDayOfYear(1);
奇怪的是这个实用方法已经好几个星期不存在了,所以好几个星期我都是这样实现的:
flattenedDateTime = inputZonedDateTime.with(java.time.temporal.ChronoField.DAY_OF_WEEK, 1);
然后你也可以这样做:
flattenedDateTime = inputZonedDateTime.with(TemporalAdjusters.firstDayOfMonth());
(也有几周不可用)
这3种调整日期的方式有什么区别吗?我想确保它们 always 在功能上是等价的,这样我就可以确保在将 ChronoUnit 调整为 1 的这种特定情况下,我可以始终互换使用它们。特别是因为没有实用方法对于 "week" 案例。
如果您质疑这是否是正确的查找方法:
给我划日期时间,将星期几调整为星期一。
示例:05-03-2019 .... -> 04-03-2019 ....
给我划日期时间,日期适合一个月的第一天!
示例:05-03-2019 .... -> 01-03-2019 ....
那么答案是肯定的
ZoneId zoneID = ZoneId.of( "Europe/Belgrade" ) ;
ZonedDateTime zoneDateTime = ZonedDateTime.now(zoneID) ;
System.out.println(zoneDateTime.withDayOfMonth(1));
System.out.println(zoneDateTime.withMonth(1));
System.out.println(zoneDateTime.with(ChronoField.DAY_OF_WEEK,1));
System.out.println(zoneDateTime.with(TemporalAdjusters.firstDayOfMonth()));
我理解你的困惑。区别不在于 withXx
方法与 TemporalAdjusters
的工作方式不同。区别是:
- 年的第一天和月份的第一天被明确定义,因此很容易构建到
withXx
方法或时间调整器中。
- 一周的第一天因文化而异。在某些地方,一周从星期日或其他某天开始。将
ChronoField.DAY_OF_WEEK
设置为 1 会将星期几设置为星期一。因此,无论是 withFirstDayOfWeek
方法还是 firstDayOfWeek
时间调整器都是危险的,并且会给一些用户带来意想不到的结果。
如果您确定只想考虑 ISO 周,其中星期一是第一天,inputZonedDateTime.with(ChronoField.DAY_OF_WEEK, 1)
可以满足您的目的。否则正确的解决方案是使用 WeekFields
对象及其 dayOfWeek()
时间场。将此字段设置为 1 将根据 WeekFields
对象表示的周定义设置为一周的第一天。
根据维基百科:
- 在中东大部分地区,星期六开始。
- 在加拿大、美国、印度、日本、台湾、香港、澳门、以色列、埃及、南非、菲律宾和拉丁美洲的大部分地区,它从周日开始。
- 欧盟和大多数其他欧洲国家、大部分亚洲和大洋洲使用星期一(与 ISO 达成一致)。
I was trying to take into account that Sunday can be the first day of the week in for example the US.
示例代码
// Don’t set default locale from production code, it’s for demonstration only
Locale.setDefault(Locale.forLanguageTag("ar-SD"));
WeekFields wf = WeekFields.of(Locale.getDefault());
DateTimeFormatter formatter = DateTimeFormatter
.ofLocalizedDateTime(FormatStyle.FULL, FormatStyle.MEDIUM)
.withLocale(Locale.ENGLISH);
ZonedDateTime inputZonedDateTime
= ZonedDateTime.of(2019, 3, 3, 12, 0, 0, 0, ZoneId.of("Asia/Amman"));
ZonedDateTime flattenedDateTime = inputZonedDateTime.with(wf.dayOfWeek(), 1);
System.out.println("First day of week in "
+ Locale.getDefault().getDisplayCountry(Locale.ENGLISH)
+ " is " + flattenedDateTime.format(formatter));
First day of week in Sudan is Saturday, March 2, 2019, 12:00:00 PM
当然,您可以通过其他方式获得 WeekFields.of
的正确语言环境。其他几个语言环境的输出包括:
- es-PY:
First day of week in Paraguay is Sunday, March 3, 2019, 12:00:00 PM
- 毫克-毫克:
First day of week in Madagascar is Monday, February 25, 2019, 12:00:00 PM
Link: Wikipedia article: week
假设我有以下代码:
java.time.ZonedDateTime inputZonedDateTime = inputDate.toInstant().atZone(zoneId);
ZonedDateTime flattenedDateTime = inputZonedDateTime.withDayOfYear(1);
奇怪的是这个实用方法已经好几个星期不存在了,所以好几个星期我都是这样实现的:
flattenedDateTime = inputZonedDateTime.with(java.time.temporal.ChronoField.DAY_OF_WEEK, 1);
然后你也可以这样做:
flattenedDateTime = inputZonedDateTime.with(TemporalAdjusters.firstDayOfMonth());
(也有几周不可用)
这3种调整日期的方式有什么区别吗?我想确保它们 always 在功能上是等价的,这样我就可以确保在将 ChronoUnit 调整为 1 的这种特定情况下,我可以始终互换使用它们。特别是因为没有实用方法对于 "week" 案例。
如果您质疑这是否是正确的查找方法:
给我划日期时间,将星期几调整为星期一。
示例:05-03-2019 .... -> 04-03-2019 ....
给我划日期时间,日期适合一个月的第一天!
示例:05-03-2019 .... -> 01-03-2019 ....
那么答案是肯定的
ZoneId zoneID = ZoneId.of( "Europe/Belgrade" ) ;
ZonedDateTime zoneDateTime = ZonedDateTime.now(zoneID) ;
System.out.println(zoneDateTime.withDayOfMonth(1));
System.out.println(zoneDateTime.withMonth(1));
System.out.println(zoneDateTime.with(ChronoField.DAY_OF_WEEK,1));
System.out.println(zoneDateTime.with(TemporalAdjusters.firstDayOfMonth()));
我理解你的困惑。区别不在于 withXx
方法与 TemporalAdjusters
的工作方式不同。区别是:
- 年的第一天和月份的第一天被明确定义,因此很容易构建到
withXx
方法或时间调整器中。 - 一周的第一天因文化而异。在某些地方,一周从星期日或其他某天开始。将
ChronoField.DAY_OF_WEEK
设置为 1 会将星期几设置为星期一。因此,无论是withFirstDayOfWeek
方法还是firstDayOfWeek
时间调整器都是危险的,并且会给一些用户带来意想不到的结果。
如果您确定只想考虑 ISO 周,其中星期一是第一天,inputZonedDateTime.with(ChronoField.DAY_OF_WEEK, 1)
可以满足您的目的。否则正确的解决方案是使用 WeekFields
对象及其 dayOfWeek()
时间场。将此字段设置为 1 将根据 WeekFields
对象表示的周定义设置为一周的第一天。
根据维基百科:
- 在中东大部分地区,星期六开始。
- 在加拿大、美国、印度、日本、台湾、香港、澳门、以色列、埃及、南非、菲律宾和拉丁美洲的大部分地区,它从周日开始。
- 欧盟和大多数其他欧洲国家、大部分亚洲和大洋洲使用星期一(与 ISO 达成一致)。
I was trying to take into account that Sunday can be the first day of the week in for example the US.
示例代码
// Don’t set default locale from production code, it’s for demonstration only
Locale.setDefault(Locale.forLanguageTag("ar-SD"));
WeekFields wf = WeekFields.of(Locale.getDefault());
DateTimeFormatter formatter = DateTimeFormatter
.ofLocalizedDateTime(FormatStyle.FULL, FormatStyle.MEDIUM)
.withLocale(Locale.ENGLISH);
ZonedDateTime inputZonedDateTime
= ZonedDateTime.of(2019, 3, 3, 12, 0, 0, 0, ZoneId.of("Asia/Amman"));
ZonedDateTime flattenedDateTime = inputZonedDateTime.with(wf.dayOfWeek(), 1);
System.out.println("First day of week in "
+ Locale.getDefault().getDisplayCountry(Locale.ENGLISH)
+ " is " + flattenedDateTime.format(formatter));
First day of week in Sudan is Saturday, March 2, 2019, 12:00:00 PM
当然,您可以通过其他方式获得 WeekFields.of
的正确语言环境。其他几个语言环境的输出包括:
- es-PY:
First day of week in Paraguay is Sunday, March 3, 2019, 12:00:00 PM
- 毫克-毫克:
First day of week in Madagascar is Monday, February 25, 2019, 12:00:00 PM
Link: Wikipedia article: week