6

我正在尝试了解时间处理,我偶然发现了 Java 中的一些东西,这让我有些困惑。拿这个示例代码:

public static void main(String[] args)
{
    //Calendar set to 12:00 AM of the current day (Eastern Daylight Time)
    Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT-4"));
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);
    /////

    //Calendar set to 12:00 AM of the current day (UTC time)
    Calendar utcCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
    utcCal.set(Calendar.HOUR_OF_DAY, 0);
    utcCal.set(Calendar.MINUTE, 0);
    utcCal.set(Calendar.SECOND, 0);
    utcCal.set(Calendar.MILLISECOND, 0);
    /////

    long oneHourMilliseconds = 3600000;
    System.out.println((cal.getTimeInMillis() - utcCal.getTimeInMillis()) / oneHourMilliseconds);
}

我将计算时间的算法可视化为cal两种形式中的一种:

  1. 计算从Epoch开始的毫秒数,加上offset(加-4)
  2. 从 (Epoch + offset) 计算毫秒数。所以从 ( Epoch - 4 * oneHourMilliseconds) 开始的毫秒数。

这两种算法都应该产生比 4 小时后的结果utcCal,但是运行代码会返回4

有人可以向我解释为什么cal尽管设置为比 utcCal 晚 4 小时的时区但最终在utcCalutcCal后 4 小时获得毫秒值?代码不应该返回吗?-4

4

3 回答 3

11

这是一段不幸的历史。ID 为“GMT-4”的时区是您所期望的“UTC+4”,即它UTC 早 4 小时。

从 tzdb 的 etcetera 文件中:

# We use POSIX-style signs in the Zone names and the output abbreviations,
# even though this is the opposite of what many people expect.
# POSIX has positive signs west of Greenwich, but many people expect
# positive signs east of Greenwich.  For example, TZ='Etc/GMT+4' uses
# the abbreviation "GMT+4" and corresponds to 4 hours behind UTC
# (i.e. west of Greenwich) even though many people would expect it to
# mean 4 hours ahead of UTC (i.e. east of Greenwich).

这个类似的解释中:

如果您可以管理它,请避免定义和使用 GMT 时区...

于 2012-04-18T14:49:50.857 回答
2

日历cal设置为2012-04-18 00:00:00timezone GMT-4

那一刻对应于2012-04-18 04:00:00in UTC(换句话说,当它是 12 AM 在 timezone GMT-4,它是 4 AM in UTC)。

日历utcCal设置为2012-04-18 00:00:00timezone UTC

2012-04-18 04:00:00和之间的差2012-04-18 00:00:00是 4 小时,所以您会看到 4 被打印出来。

于 2012-04-18T14:53:51.893 回答
0
于 2018-02-28T22:41:44.250 回答