日历返回错误的时区日期

12

如果我在格林威治标准时间时区的计算机上执行以下操作

TimeZone timeZone = TimeZone.getTimeZone('IST');  // India Standard Time
Calendar calendar = Calendar.getInstance(timeZone);

System.out.println(calendar.getTime());

它打印出:

Fri Oct 31 15:18:22 GMT 2014

为什么日期打印出的是计算机默认的时区,而不是构造 Calendar 时使用的 TimeZone


可能是为什么Calendar在正确的时区返回错误的小时? 的重复问题以及这个这个这个和许多其他问题。 - Basil Bourque
5个回答

12

Joshi的回答是正确但简短的。我会稍微扩展一下,并展示一个使用现代类的替代方法。

Date没有时区

你的代码calendar.getTime()java.util.Calendar对象中提取一个java.util.Date对象。

java.util.Date类有一个善意的但令人困惑的特性,即其toString方法在生成字符串时应用JVM的当前默认时区。这会产生Date类具有时区的错觉,但实际上它没有。一个Date表示时间线上的一个瞬间,以自1970年UTC第一个时刻参考日期的毫秒计数为基础(1970-01-01T00:00:00Z)。(更让人困惑的是,Date类实际上确实有一个深藏不露且与本讨论无关的时区。)

避免使用过时的日期时间类

旧的日期时间类现在已经过时,被java.time类所取代。请只使用java.time类。

Instant

要表示UTC上的一个瞬间,相当于java.util.Date,请使用Instant类。Instant类表示UTC时间轴上的一个瞬间,精确到纳秒(小数点后最多九位)。

Instant instant = Instant.now();  // Current moment in UTC.

ZonedDateTime

若要按照特定区域的壁钟时间查看相同时刻,请应用ZoneId获取ZonedDateTime

请以continent/region的格式指定正确的时区名称,例如America/MontrealAfrica/CasablancaPacific/Auckland。请勿使用3-4个字母的缩写,例如ESTIST,因为它们不是真正的时区,没有标准化,甚至不唯一(!)。

ZoneId z = ZoneId.of( "Asia/Kolkata" );
ZonedDateTime zdt = instant.atZone( z );

在Stack Overflow上搜索此主题的许多其他问题和答案。这个问题实际上是其他许多问题的重复。


关于java.time

java.time框架内置于Java 8及以上版本。这些类替代了老旧的遗留日期时间类,例如java.util.DateCalendarSimpleDateFormat

Joda-Time项目现处于维护模式,建议迁移到java.time类。

要了解更多信息,请查看Oracle教程。在Stack Overflow上搜索许多示例和解释。规范是JSR 310
在哪里获取java.time类? 这个 ThreeTen-Extra 项目扩展了 java.time 的附加类。该项目是 java.time 可能未来添加的地方。您可能会在这里找到一些有用的类,例如 IntervalYearWeekYearQuarter更多

9

因为Date对象不包含时区信息,所以你需要使用SimpleDateFormat来格式化并在你需要的时区打印日期。


1
当将Calendar对象转换为Date对象时,时区会丢失。Calendar本身使用时区。以下内容将打印到指定的时区。
TimeZone timeZone = TimeZone.getTimeZone('IST');  // India Standard Time
Calendar calendar = Calendar.getInstance(timeZone);

System.out.println(calendar.get(Calendar.DAY_OF_MONTH) + "/" + 
(calendar.get(Calendar.MONTH)+1) + "/" + calendar.get(Calendar.YEAR) + " Time: " + 
calendar.get(Calendar.HOUR_OF_DAY) + ":" + calendar.get(Calendar.MINUTE));
 System.out.println(calendar.getTime());

注意不要像这样使用日历API,它非常混乱。请使用日期格式化API。
日期API存在许多问题(这就是为什么它在Java 8中完全重做) 。

-1

Calendar#getTime() - 返回一个代表此日历时间值的日期对象(从纪元开始的毫秒偏移量)。确切地说,java.util.Date中的值是自1970年1月1日午夜UTC以来的毫秒数,而java.util.Date没有特定的时区。

在Java 8中引入了ZoneDateTime,应该可以满足您的需求:

ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("Asia/Kolkata"));
LocalDate localDate = zonedDateTime.toLocalDate();

-2

在打印日期/时间之前,您必须应用时区

example: TimeZone.setDefault(TimeZone.getTimeZone("IST"));

(代码未经测试)


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