【问题标题】:Locale independent year week date format独立于语言环境的年周日期格式
【发布时间】:2017-08-25 11:43:36
【问题描述】:

我想以独立于区域设置的方式打印Instant,ISO 设置为一周的第一天(星期一)和第一周的最少天数 (4)。

我目前的设置是:

private String print(Instant i) {
    DateTimeFormatter formatter = DateTimeFormatter
            .ofPattern("YYYY-ww")
            .withZone(UTC);
    return formatter.format(i);
}

@Test
public void test() {
    System.out.format("First day of week      : %s%n",
            WeekFields.of(Locale.getDefault()).getFirstDayOfWeek());
    System.out.format("Min days in 1st week   : %s%n",
            WeekFields.of(Locale.getDefault()).getMinimalDaysInFirstWeek());
    Instant instant = Instant.parse("1998-12-31T00:00:00Z");
    System.out.println(print(instant));
}

对于系统区域设置“en_US”,测试打印:

First day of week      : SUNDAY
Min days in 1st week   : 1
1999-01

对于系统区域设置“de_DE”,测试打印:

First day of week      : MONDAY
Min days in 1st week   : 4
1998-53

“de_DE”区域设置与 ISO 设置一致,我知道我可以将格式化程序设置为

DateTimeFormatter formatter = DateTimeFormatter
        .ofPattern("YYYY-ww")
        .withZone(UTC)
        .withLocale(Locale.GERMANY);

但我可以在不指定绑定到特定国家/地区的任何语言环境的情况下这样做吗?我找到了java.time.temporal.WeekFields#ISO:

public static final WeekFields ISO = new WeekFields(DayOfWeek.MONDAY, 4);

这是我想要的,但我不知道如何将它与DateTimeFormatter结合起来。

【问题讨论】:

  • 根据 DateTimeFormatter 的文档,“如果 [withZone] 被覆盖,则日期时间值将在格式化之前转换为具有请求的 ZoneId 的 ZonedDateTime。在解析期间,在返回值之前应用 ZoneId” .所以我认为会发生什么是解析创建一个美国当地时间,然后在格式化期间重新分区为 UTC。
  • @daniu 我最初的想法和你一样,但现在我认为它与 zoneId 无关。即使我创建了一个没有区域 (DateTimeFormatter.ofPattern("YYYY-ww")) 的格式化程序并使用它来格式化 LocalDate(没有时区信息),每个区域设置的输出也会发生变化。星期字段 Yw 的行为似乎确实是特定于语言环境的,无论时区如何。

标签: java datetime datetime-format java-time


【解决方案1】:

您可以使用java.time.format.DateTimeFormatterBuilderWeekFields.ISO 的相应字段:

代码是:

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
    // append week year
    .appendValue(WeekFields.ISO.weekBasedYear(), 4)
    // separator
    .appendLiteral('-')
    // append week of week year field
    .appendValue(WeekFields.ISO.weekOfWeekBasedYear(), 2)
    // create formatter
    .toFormatter().withZone(ZoneOffset.UTC);

而不是创建一个新的WeekFields 实例(使用WeekFields.of(locale)),而是使用WeekFields.ISO

System.out.format("First day of week      : %s%n", WeekFields.ISO.getFirstDayOfWeek());
System.out.format("Min days in 1st week   : %s%n", WeekFields.ISO.getMinimalDaysInFirstWeek());
Instant instant = Instant.parse("1998-12-31T00:00:00Z");
System.out.println(formatter.format(instant));

输出是:

一周的第一天:星期一
第 1 周的最少天数:4
1998-53


即使我更改了格式化程序的语言环境:

formatter = formatter.withLocale(Locale.GERMANY);

或者:

formatter = formatter.withLocale(Locale.ENGLISH);

输出保持不变。

【讨论】:

  • 谢谢,正是我想要的!不过有一个小的改进:使用.appendLiteral('-') 代替.appendPattern("-"),并使用.appendValue(WeekFields.ISO.weekBasedYear(), 4).appendValue(WeekFields.ISO.weekOfWeekBasedYear(), 2) 指定年份和星期部分的宽度。
  • @AdamMichalik 不客气!确实,我忘记了字段的宽度。在这种情况下,使用appendLiteral 真的更清楚。我已经更新了答案,谢谢!
猜你喜欢
  • 2013-06-14
  • 2010-11-23
  • 2019-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-27
  • 2023-04-03
相关资源
最近更新 更多