我正在尝试处理时间,而我偶然发现了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);
}

我以2种形式之一可视化用于计算cal表示的时间的算法:
  • 计算距纪元的毫秒数,加上偏移量(加-4)
  • 从(Epoch +偏移量)计算毫秒数。因此,距离(Epoch - 4 * oneHourMilliseconds)的毫秒数。

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

    有人可以向我解释为什么cal尽管设置为比utcCal落后4个小时的时区,却在utcCal的4个小时后仍然具有毫秒值?该代码不应该返回-4吗?

    最佳答案

    这是一段不幸的历史。 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).
    

    this similar explanation:

    09-25 22:06