为什么要减去这两次(在1927年)给出一个奇怪的结果?

问题

如果我运行下面的程序,该程序分析引用时间间隔1秒的两个日期字符串并对它们进行比较:

public static void main(String[] args) throws ParseException {
    SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
    String str3 = "1927-12-31 23:54:07";  
    String str4 = "1927-12-31 23:54:08";  
    Date sDt3 = sf.parse(str3);  
    Date sDt4 = sf.parse(str4);  
    long ld3 = sDt3.getTime() /1000;  
    long ld4 = sDt4.getTime() /1000;
    System.out.println(ld4-ld3);
}

输出是:

353

为什么“ld4-ld3”不是“1”(正如我期望的那样,时间的一秒差异),而是“353”?

如果我将日期更改为1秒后的时间:

String str3 = "1927-12-31 23:54:08";  
String str4 = "1927-12-31 23:54:09";

然后ld4-ld3将会是1

Java版本:

java version "1.6.0_22"
Java(TM) SE Runtime Environment (build 1.6.0_22-b04)
Dynamic Code Evolution Client VM (build 0.2-b02-internal, 19.0-b04-internal, mixed mode)

Timezone(`TimeZone.getDefault()`):

sun.util.calendar.ZoneInfo[id="Asia/Shanghai",
offset=28800000,dstSavings=0,
useDaylight=false,
transitions=19,
lastRule=null]

Locale(Locale.getDefault()): zh_CN

#1 热门回答(9660 赞)

这是12月31日上海的时区变化。

有关1927年上海的详情,请参阅this page。基本上在1927年底的午夜,时钟回落了5分52秒。所以“1927-12-31 23:54:08”实际上发生了两次,它看起来像Java将它解析为当地日期/时间的后置瞬间 - 因此是差异。

在时区的奇怪而美妙的世界中,又是一段情节。

**编辑:**停止按!历史更改...

如果用版本2013a的TZDB进行重建,原始问题将不再显示相同的行为。在2013a中,结果将是358秒,转换时间为23:54:03而不是23:54:08。

我只注意到这一点,因为我在野田时间收集了这样的问题,形式为unit tests ......测试现在已经改变了,但它只是表明 - 甚至连历史数据都是安全的。

**编辑:**History又改变了...

在TZDB 2014f中,变化的时间已经转移到了1900-12-31,现在它只有343秒的变化(所以如果你明白我的意思,那么't'和't 1'之间的时间为344秒) 。

**编辑:**要回答1900年左右转换的问题......它看起来像Java时区实现一样将对待所有时区仅视为1900年开始之前的任何时刻的标准时间UTC:

import java.util.TimeZone;

public class Test {
    public static void main(String[] args) throws Exception {
        long startOf1900Utc = -2208988800000L;
        for (String id : TimeZone.getAvailableIDs()) {
            TimeZone zone = TimeZone.getTimeZone(id);
            if (zone.getRawOffset() != zone.getOffset(startOf1900Utc - 1)) {
                System.out.println(id);
            }
        }
    }
}

上面的代码在Windows机器上没有输出。因此,任何在1900年初具有任何其他偏移量的时区都将被视为一个转换。 TZDB本身有一些数据早于此,并且不依赖任何“固定”标准时间的概念(这是'getRawOffset`假定为有效概念的概念),所以其他库不需要引入这种人为转换。


#2 热门回答(1453 赞)

您遇到了alocal time discontinuity

当地方标准时间即将到达星期日,1928年1月1日,00:00:00时钟被转换为0:05:52小时到星期六,1927年12月31日,23:54:08当地标准时间

这并不奇怪,并且由于政治或行政行为而导致时区被切换或更改,因此在任何时候都发生过这样或那样的事情。


#3 热门回答(571 赞)

这种奇怪的道德是:

  • 尽可能使用UTC的日期和时间。
  • 如果无法以UTC显示日期或时间,请始终指示时区。
  • 如果您不需要UTC的输入日期/时间,则需要明确指示的时区。