【问题标题】:TimeZone problem in JavaJava中的时区问题
【发布时间】:2020-12-20 20:23:57
【问题描述】:

我正在尝试使用 TimeZone GMT 实例化 GregorianCalendar,但每当我调用 getTime() 方法时,它都会给我本地时区的时间。这是我的代码:

Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
System.out.println(cal.getTime());

我得到的输出是这样的:

Sat Nov 28 19:55:49 PKT 2009

请帮忙!

【问题讨论】:

标签: java timezone


【解决方案1】:

我不确定这是否能回答您的问题,但这是在 GMT 中获取“现在”的一种方式。

import java.text.*
import java.util.* 

Calendar cal = new GregorianCalendar();
Date date = cal.getTime();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss z");
formatter.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println(formatter.format(date));

查看Javadoc on SimpleDateFormat 了解不同的模式。此外,您可能需要考虑 Joda Time,因为它在日期和时间方面要优越得多。

【讨论】:

  • +1 提供了一个很好的详细示例来配合我的闲聊,并建议 Joda Time。 java.util.Date 和 Calendar 是 Java 语言的一个尴尬。
  • 不是获取日历的首选方式:Calendar cal = Calendar.getInstance() 吗?
  • @kgrad - 日历是抽象的,所以你不能这样做!
  • @Brian:你不能直接实例化一个抽象类,但这并不妨碍你调用它的静态方法。不过,我想知道 Calendar 是如何知道返回一个 Gregorian 实例的?文档没有说,所以实现可以免费返回玛雅日历??
  • 如何获得实际的日期而不是字符串?
【解决方案2】:

问题不在于GregorianCalendar,而在于Date,它用于为toString 格式化println 的日期/时间。

如果您想控制日期格式,则需要实例化自己的 DateFormat - 我总是使用 SimpleDateFormat,因为我对日期的外观相当挑剔。

如果您对日期格式的细节不感兴趣,也可以使用DateFormatgetInstance... 工厂方法之一。

您可以在DateFormat 上显式地setTimeZone(当然包括SimpleDateFormat)。

【讨论】:

  • 他特别调用getTime(),返回日期,正如你所说,应该避免。
  • 我没这么说。我说过需要避免将 Date 格式化为 String 的方式。
  • 啊,我理解“正在使用的”,日历是“执行者”,但您的意思是 qustion-author :)
  • 感谢您的澄清。恐怕 Michael Esther (sp?) 刚坐下并展示了如何做的时候有更好的主意。
  • 在 java8 中的 datetime api java.time.Instant.now() 将返回当前的 GMT 时间。
【解决方案3】:

tl;博士

Instant.now().toString()

2020-03-08T00:21:48.647951Z

java.util.Date::toString 撒谎

您对GregorianCalendar::getTime 的调用会返回java.util.Date。从这个方法和类命名中可以看出,这些类的设计很糟糕。

然后您隐式调用Date::toString 以生成表示该对象内值的文本。该值实际上是 UTC,仅是自 UTC 1970 年第一刻的纪元参考以来的毫秒数。不幸的是,该方法在生成文本时动态应用 JVM 当前的默认时区。这会产生该区域包含在对象内的错觉。

令人困惑?是的。 从不使用这些旧的日期时间类的众多原因之一。请改用 java.time 类。

java.time

其他答案是正确的,但现在已过时。可怕的 DateCalendarGregorianCalendarSimpleDateFormat 类在几年前被 JSR 310 中定义的现代 java.time 类所取代。

要获取 UTC 中的当前时刻,请使用 Instant。根据定义,java.time 中的这个基本构建块类始终采用 UTC。

Instant instant = Instant.now() ;

通过调用toString 以ISO 8601 格式生成标准字符串。

String output = instant.toString() ;

看到这个code run live at IdeOne.com

2020-03-08T00:21:48.647951Z

要在生成字符串时更灵活地格式化,请使用OffsetDateTime 类。搜索 Stack Overflow 以了解 DateTimeFormatter

OffsetDateTime odt = OffsetDateTime.now( ZoneOffset.UTC ) ;

【讨论】: