为什么要减去这两次(在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 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. 你是真的在真实的场景中碰到了这种确切的情况呢,还是这个问题只是为了一个难题 – 只是为了好玩吗?
  2. 我可以很容易地想象这是由于减少了一个更大的bug而导致的 – 也就是说,“为什么这两个日期相距不到一年呢?
  3. 真正的答案是始终使用秒数来记录日志,如Unix纪元,具有64位整数表示(签名,如果您想在纪元之前允许戳记)。任何现实世界的时间系统都有一些非线性的,非单调的行为,如跳跃小时或夏令时。
  4. 我真的不知道从哪个bug报告挖掘了这一个。我也非常确定,除了是一个难题,99.9(增加9位数字)用户百分比没有用。他获得了“游戏”声誉的奖章。

答案:

 

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

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

在经常奇怪和奇妙的时区世界的另一个情节。

编辑:停止按!历史变化…

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

我只注意到这一点,因为我在野田时间以单元测试的形式收集了这样的问题……测试现在已经改变了,但它只是表明 – 甚至没有历史数据是安全的。

编辑:历史已经改变了…

在TZDB 2014F,变化的时间已经转移到1900年12月31日,它现在是一个单纯的343秒变化(这样的时间tt+1有344秒,如果你明白我的意思)。

编辑:要回答1900年的转换周围的一个问题…它看起来像Java时区实现对待所有的时区,只是在1900年开始之前的任何时刻,在他们的标准时间:

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假定为有效的概念)的概念,所以其他库不需要引入这种人为的转换。

答案评论:

不,但是查看那个时期上海时区转型的细节是我的第一个停靠港。而且我最近也一直在努力研究野田时间的时区转换,所以模棱两可的可能性在我的想法的最前沿呢.

@Johannes:为了使它成为一个更全球的正常时区,我相信 – 由此产生的偏移量是UTC + 8。巴黎在1911年做了同样的事情,例如:timeanddate.com/worldclock/clockchange.html?n=195&year= 1911

当时,旅行者知道当地时间与其他地方不同(因为是这样)。另外,手表是机械的,而且很快就会漂移,所以无论如何,即使他们没有旅行,我们也会根据当地的钟表机构调整它们。那么塔钟(也是漂移的)如何设置?当太阳达到每日高峰时,最容易的是将它们设置为12:00,这在每个不同的地方都是不同的。在铁路时刻表需要某种标准化之前,这几乎是无处不在。

但是,那么,在这个世界上,这种知识如何在世纪之后存在下来,几乎在一个世纪以前,它是用软件来实现的。在2011年,任何向非软件工程师提及时区怪异的人都会被看作书呆子。(实际上,人们期望所有的软件都能抽象出来,如果软件模糊不清,当他们说“中午”时,我们的软件工程师就应该去处理它)。但想象一下1927年12月在上海的一个人,认为把这样一个事情记下来是有道理的,而且这个信息从来不会丢失,被删除,任何事情……心灵都会被吹灭。

实际上他只花了15分钟,因为它显示了16分钟的差距,这是由于2011年7月27日由于Jon Skeet有多棒而造成的轻微时区差异。

添加评论

友情链接:蝴蝶教程