【问题标题】:How to format time objects in Java into the correct timezone如何将 Java 中的时间对象格式化为正确的时区
【发布时间】:2020-09-27 08:51:32
【问题描述】:

我想使用 Java Time API 获取中欧夏令时间 (CEST) 并正确格式化。我有以下代码:

LocalDateTime localDateTime= LocalDateTime.now();
DateTimeFormatter myFormatObj = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss");
localDateTime.format(myFormatObj);
ZoneId europeBerlin = ZoneId.of("Europe/Berlin");
ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, europeBerlin);

命令zonedDateTime.toString()离开到以下输出:

2020-09-27T08:42:33.660+02:00[Europe/Berlin]

但我希望在 DateTimeFormatter 中获得之前指定的输出(“dd-MM-yyyy HH:mm:ss”)。我已经将 localDateTime 格式化为这种格式,现在我只想获取 CEST 时间。我怎样才能做到这一点?我会很感激每一条评论。

【问题讨论】:

  • 如果您想使用分区时间,请使用ZonedDateTime。要将其转换回LocalDateTime,请致电ZonedDateTime::toLocalDateTime
  • 感谢图灵的评论。对我来说,我使用的是哪个课程并不重要。我只想按照我在代码中指定的方式格式化 CEST 时间 ("dd-MM-yyyy HH:mm:ss")
  • 我曾经使用过 SimpleDateFormat。我刚刚读到使用 Java Time API 会更好。所以我想这会很好,如果我可以坚持 Java Time API 并且如果可能的话不使用 ZonedTime。但总的来说,如果更好的话,我也可以使用 ZonedTime
  • 这能回答你的问题吗? String to ZonedDateTime is changing format
  • 您只需要String formattedDateTime = zonedDateTime.format(myFormatObj);

标签: java time date-formatting


【解决方案1】:

请注意,Java Time API 中的日期时间对象是不可变的。因此,每当您想修改现有的日期时间实例时,都会返回一个新的副本,而旧的副本保持不变。

另外,一个小的优化:DateTimeFormatter 是线程安全的。因此,不需要每次都构造一个新实例,因为格式是恒定的。您可以像这样在顶部声明它:

private static final DateTimeFormatter FORMATTER;

static {
    FORMATTER = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss");
}

要打印格式化的String,请使用以下命令:

LocalDateTime localDateTime = LocalDateTime.now();
ZoneId europeBerlin = ZoneId.of("Europe/Berlin");
ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, europeBerlin);

// please note that #format has a return value
// originally, you called 'localDateTime.format(myFormatObj);' while ignoring
// the return value
String formatted = FORMATTER.format(zonedDateTime);

System.out.println(formatted); // e.g. 27-09-2020 11:44:27

编辑 1: 关于线程安全 线程安全是指一个对象可以安全地被多个线程同时使用,而不会破坏类的内部结构。如果一个类是线程安全的,你可以同时从多个线程调用它(因此你不需要每次都创建一个新实例,而只需要一个)。如果一个类不是线程安全的,则每个线程都需要一个新实例。

【讨论】:

  • 感谢 Glains 的回答。 Thead-safe 是什么意思?而且您使用的是静态初始化程序,对吗?我被多次告知我应该避免使用这样的东西。
  • 查看我的线程安全编辑。关于静态初始化器:您也可以使用实例初始化器。你被告知要避开这些障碍的原因是什么?您也可以坚持使用之前的示例,以免使其过于复杂,但我认为提供最佳实践是件好事(也适用于学习 Java 的新人,因为我看到很多代码都存在这些效率低下 i>)。
  • 一个非常常见的例子是正则表达式的用法,如果您有兴趣,请参阅here了解更多信息。
  • 感谢 Glains 的回答和努力。 Ole 发布了一个非常简单的格式化解决方案:“String formattedDateTime = zonedDateTime.format(myFormatObj);” (往上看)。但是,时区不正确。但基本上我想坚持简单的解决方案。您使用静态初始化程序的解决方案似乎过于复杂。但仍然非常感谢您的回答。如果我无法通过 Ole 的建议解决时区问题,我将使用您的答案。
  • Time API 的一个普遍缺点是我在 Android Studio 中收到警告,告诉我:“调用需要 API 级别 26(当前最低为 15):java.time.LocalDateTime#format”。使用 SimpleDateFormat 不会收到此警告。所以也许我应该使用 SimpleDateFormat 这样旧的 Android 版本也可以使用我的应用程序。
【解决方案2】:
    DateTimeFormatter myFormatObj = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss");
    ZoneId europeBerlin = ZoneId.of("Europe/Berlin");
    ZonedDateTime zonedDateTime = ZonedDateTime.now(europeBerlin);
    
    String formattedDateTime = zonedDateTime.format(myFormatObj);
    System.out.println(formattedDateTime);

刚才在UTC时区运行时的输出:

27-09-2020 20:33:53

我们得到的是柏林时间(不是 UTC 时间)。

你的代码出了什么问题?

两件事:

  1. LocalDateTime.now() 为您提供 JVM 默认时区的当前时间。似乎这不是 Europoe/Berlin(也许是 UTC,也可能是其他东西)。然后ZonedDateTime.of(localDateTime, europeBerlin) 采用该日期和时间并声称它是欧洲/柏林时区,这是错误的,也是您得到错误结果的原因。您并不经常需要 LocalDateTime 类,也几乎不需要无参数 LocalDateTime.now() 方法。
  2. 要以特定格式获取时间,您需要将日期和时间格式化为字符串。 LocalDateTimeZonedDateTime 对象没有任何格式。

链接

【讨论】:

    猜你喜欢
    • 2015-02-10
    • 1970-01-01
    • 2015-09-13
    • 2015-09-25
    • 2015-11-19
    • 2015-08-25
    • 2019-10-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多