Java中的时区问题

5

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

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

我得到的输出是这样的:
Sat Nov 28 19:55:49 PKT 2009

Please help!


请参见http://stackoverflow.com/questions/1802758/how-do-i-get-the-current-time-in-a-different-timezone-in-java/1802787#1802787。 - b.roth
3个回答

10

我不确定这是否回答了你的问题,但这是一种获取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));

查看SimpleDateFormat的Javadoc以获取不同的格式。此外,考虑使用Joda Time,因为它在处理日期和时间方面优于SimpleDateFormat。


1
+1 针对我的废话提供了一个漂亮详细的例子,并建议使用 Joda Time。java.util.Date 和 Calendar 是 Java 语言的污点。 - Carl Smotricz
获取日历的首选方式不是:Calendar cal = Calendar.getInstance() 吗? - kgrad
@kgrad - 日历是抽象的,所以你不能这样做! - Brian Agnew
@Brian:你不能直接实例化一个抽象类,但这并不妨碍你调用它的静态方法。不过,我想知道Calendar是如何知道返回一个Gregorian实例的?文档没有说明,所以实现可以自由地返回玛雅日历吗? - Carl Smotricz
如何获取实际日期而不是字符串? - Tulains Córdova

6
问题不在于GregorianCalendar,而是在于Date。为了对println中的日期/时间进行格式化,使用了Date
如果您想控制日期格式,则需要实例化自己的DateFormat——我总是使用SimpleDateFormat,因为我非常挑剔我的日期外观。
如果您对日期格式的详细信息不感兴趣,也可以使用DateFormat的一个getInstance...工厂方法。
您可以在DateFormat(当然包括SimpleDateFormat)上明确地setTimeZone

他明确地调用了 getTime(),它返回 Date 类型,正如你所说,应该避免使用。 - Bozho
我没有说那个。我说需要避免将日期格式化为字符串的方式。 - Carl Smotricz
1
啊,我明白了“正在使用”的意思,日历是“执行者”,但你指的是提问者 :) - Bozho
谢谢澄清。恐怕Michael Esther想到了更好的点子,他就坐下来演示了如何做。 - Carl Smotricz
在Java8的日期时间API中,java.time.Instant.now()将返回当前的GMT时间。 - rsinha

1

tl;dr

Instant.now().toString()

2020-03-08T00:21:48.647951Z

java.util.Date::toString 说了谎话

你调用 GregorianCalendar::getTime 返回一个 java.util.Date。正如你从这个方法和类名中看到的那样,这些类的设计非常糟糕。

然后你隐式地调用了 Date::toString 方法来生成表示该对象内部值的文本。该值实际上是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() ;

查看此在IdeOne.com上运行的代码

2020-03-08T00:21:48.647951Z

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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接