使用with *函数,TemporalAdjusters或通过设置TemporalFields来调整ZonedDateTimes之间是否有任何区别?

时间:2019-03-05 08:43:07

标签: java datetime java-8 dayofweek

说我有以下代码:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

// Parse: String -> LocalDateTime
LocalDateTime now = LocalDateTime.parse("2018-03-03 11:00:00", formatter);

// Format: LocalDateTime -> String
System.out.println(now.format(formatter));

奇怪的是,这个实用程序方法已经有好几个星期不存在了,所以好几个星期我都这样实现:

java.time.ZonedDateTime inputZonedDateTime = inputDate.toInstant().atZone(zoneId);
ZonedDateTime flattenedDateTime = inputZonedDateTime.withDayOfYear(1);

然后您也可以这样做:

flattenedDateTime = inputZonedDateTime.with(java.time.temporal.ChronoField.DAY_OF_WEEK, 1);

(数周也无法使用)

这三种调整日期的方式之间是否有任何区别?我想确保它们在功能上始终是等效的,因此我确信在将ChronoUnit调整为1的特定情况下,我可以始终互换使用它们。尤其是因为“周”的情况。

2 个答案:

答案 0 :(得分:2)

我了解您的困惑。区别不在于withXx方法与TemporalAdjusters的工作方式不同。区别是:

  • 一年中的第一天和月中的第一天是明确定义的,因此很容易内置到withXx方法或时间调节器中。
  • 一周的第一天因文化而异。在某些地方,一周从星期日或其他日子开始。将ChronoField.DAY_OF_WEEK设置为1会将星期几设置为星期一。因此,withFirstDayOfWeek方法或firstDayOfWeek时间调整器都会很危险,并且会给某些用户带来令人惊讶的结果。

如果您确定只考虑ISO星期(星期一是第一天),则inputZonedDateTime.with(ChronoField.DAY_OF_WEEK, 1)可以满足您的需求。否则,正确的解决方案是使用WeekFields对象及其dayOfWeek​()时间字段。将此字段设置为1将根据WeekFields对象表示的星期定义将其设置为一周的第一天。

根据Wikipedia:

  • 在中东大部分地区,一周从星期六开始。
  • 在加拿大,美国,印度,日本,台湾,香港,澳门,以色列,埃及,南非,菲律宾和大部分拉丁美洲,它从星期日开始。
  • 欧盟和大多数其他欧洲国家,大部分亚洲和大洋洲使用星期一(与ISO达成协议)。
  

我试图考虑到星期日在美国可能是一周的第一天。

示例代码

    // 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));
  

苏丹每周的第一天是2019年3月2日(星期六)下午12:00:00

当然,您可以通过其他方式获得WeekFields.of的正确语言环境。带有其他几个语言环境的输出包括:

  • es-PY:
      

    巴拉圭一周中的第一天是2019年3月3日(星期日)下午12:00:00

  • mg-MG:
      

    马达加斯加一周中的第一天是2019年2月25日星期一,下午12:00:00

链接: Wikipedia article: week

答案 1 :(得分:0)

如果您怀疑这是否是正确的寻找方法:

  1. 让我将日期时间区域划分为星期几,将其改编为星期一。

    例如:05-03-2019 ....-> 04-03-2019 ....

  2. 让我将日期时间分区为一个月的第一天!

    例如: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()));