如何为人类在特定时区的特定区域设置即时格式

How to format an instant in a particular locale at a particular timezone for a human

我正在使用:

Locale locale = Locale.FRENCH;
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL).withLocale(locale).withZone(zone);
System.out.println(formatter.format(Instant.now()));

我得到的结果是 lundi 25 mai 2020 20 h 21 CESTLocale.FRENCHMonday, May 25, 2020 8:05:11 PM CESTLocale.English

我发现 CEST 对非 IT 人员不友好,我怎样才能可靠地删除它?

编辑

我不想启用 CLDR,我的用户已经知道他们在哪个国家/地区,因此我们可以安全地删除时区信息。

我必须能够处理 AN/PM 和 24 小时格式,而无需列出所有国家/地区。

这怎么可能?

您可以自定义要显示的内容和不显示的内容 例如 DateTimeFormatter.ofPattern("EEEE, MMMM dd, yyyy hh:mm:ss a") 给出 lundi, mai 25, 2020 07:02:57 PM

利用 CLDR

我知道您正在使用 Java 8,并且在我的 Java 8 上我可以重现您的结果。为避免用户不友好的缩写 CEST(其他时区也类似),我建议您使用 CLDR,Unicode Common Locale Data Repository。

运行 您的 Java 程序使用此 JVM 参数:-Djava.locale.providers=CLDR.

或者在您的程序中设置系统 属性:

    System.setProperty("java.locale.providers", "CLDR");

这会改变你的输出。现在使用法语语言环境,输出为:

lundi 25 mai 2020 21:06:07 heure avancée d’Europe centrale

和英语:

Monday, May 25, 2020 9:09:39 PM Central European Summer Time

为什么会这样? Java 从最多四个来源获取其语言环境数据,包括在不同语言环境中使用的日期和时间格式。在 Java 8 及之前的版本中,Java 自己的语言环境数据是默认的;但默认值是通过提到的系统属性更改的。在 Java 9 及更高版本中,CLDR 是默认值 (JEP 252)。因此,在 Java 8 中进行此更改以使用 CLDR 也将为迁移到 Java 9 或更高版本做好准备。

完全省略时区

I want to remove the time zone since the user already know that he is [in h]is country.

附带说明:在某些情况下,用户希望确信他们得到的时间在他们自己的时区。它还将有助于消除歧义,以防您需要在时钟倒转的秋季重叠中打印时间。 heure avancée d’Europe centrale 将在时钟更改之前打印,heure normale de l’Europe centrale 之后打印。

您当然更了解您的 用户想要什么和需要什么。所以有几个选项:

  1. 手动从格式模式中取出时区,如 munge 的答案中所示。
  2. 使用FormatStyle.MEDIUM。 Deadpool 在现已删除的答案中已经提出了这一建议。您可以为日期和时间使用不同的格式样式:

        DateTimeFormatter formatter = DateTimeFormatter
                .ofLocalizedDateTime(FormatStyle.FULL, FormatStyle.MEDIUM)
                .withLocale(locale)
                .withZone(zone);
        System.out.println(formatter.format(Instant.now()));
    

    Java8:

    法语语言环境中的示例输出

    mardi 26 mai 2020 19:26:59

    在英语语言环境中:

    Tuesday, May 26, 2020 7:27:26 PM

要可靠地删除时区信息,您首先必须获取特定于语言环境的模式并在使用它进行格式化之前对其进行调整:

Locale locale = Locale.FRENCH;
Instant instant = Instant.now();

String pattern = getPatternWithoutTimezone(FormatStyle.FULL, Chronology.from(instant), locale);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern).withLocale(locale)
    .withZone(TimeZone.getDefault().toZoneId());
System.out.println(formatter.format(Instant.now()));

...

 private String getPatternWithoutTimezone(FormatStyle style, Chronology chronology,
  Locale locale) {
String pattern = java.time.format.DateTimeFormatterBuilder
    .getLocalizedDateTimePattern(FormatStyle.FULL, FormatStyle.FULL, chronology, locale);

/* remove time zone from pattern 
 * (see spec of "Date and time pattern" in Javadoc of java.text.SimpleDateFormat class)
 */
return pattern.replaceAll("[zZX]", "");

}

请注意,.withLocale(locale) 仍然是必需的,否则您只能使用特定于语言环境的格式,而不是日期、月份等的本地化名称。