程序员的午夜一秒谜案:1927年12月31日

这真是一个特殊的日子啊。

1927年12月31日。

StackOverflow是一个程序员向的问答网站,广大程序员们在上面交流经验、提问答疑,三天前,一位名叫Freewind的用户发布了一个问题1927年12月31日,一秒谜案

我在用Java编写一段比较两个字符串时间间隔的程序,然而当我比较“1927-12-31 23:54:07”和“1927-12-31 23:54:08”这两个时间时,输出结果却不是1……而是353。

当我把两个时间分别往后调整1秒,变成“1927-12-31 23:54:08”和“1927-12-31 23:54:09”,结果就又是1了!—-可为什么那两个时间的结果,却是353呢?

面对这一诡异的问题,网友们很快追问,“你的区域(Locale)设置是什么?这可能是个区域问题/和当地夏令时之类的东西有关。”

楼主很快附上了Java版本号和区域设置:

sun.util.calendar.ZoneInfo[id=”Asia/Shanghai”,

offset=28800000,dstSavings=0,

useDaylight=false,

transitions=19,

lastRule=null]

(……没错,Freewind君,似乎是一位魔都死程。不知道这里有没有人认识这位老兄?)

在这份追加信息出现仅仅两分钟之后,StackOverflow站上的问答狂人Jon Skeet给出了如下答复

这是因为上海的时区在12月31日发生了变化。

请看这里

为什么时间往回拨了5分52秒?

(1928年1月1日0点0分,当地时间由地方平时(Local Mean Time) 改为北京时间/中国标准时间)

简单地说,在1927年末的最后那一个午夜,时钟被往回拨了5分52秒。所以“1927-12-31 23:54:08”这一秒,事实上,发生了两次,而看起来在计算当地时间时,Java将其视为了后面那一个时间点,于是就产生了这一差别。

这正是时区世界的奇妙与不可思议啊。

在StackFlow网民们纷纷膜拜Jon Skeet的神速之时,其他程序员也以测试的方式验证了这一结果的正确—-美国时间木有这个问题。看来,当一枚程序员,有时真的需要上通天文、下知地理啊……


ps:我刚刚用C#做了一下,一下是我的测试代码:

1
2
3
double t1 = (DateTime.Parse("1927/12/31 23:54:07") - Convert.ToDateTime("1970/01/01 00:00:00")).TotalMilliseconds / 1000;// -8 * 3600;
double t2 = (DateTime.Parse("1927/12/31 23:54:08") - Convert.ToDateTime("1970/01/01 00:00:00")).TotalMilliseconds / 1000;// -8 * 3600;
MessageBox.Show(string.Format("[{0}] [{1}] : {2}", t1, t2, t2 - t1));

我并没有遇到上面的问题,无论是235408-235407或者235409-235408,我的结果都是1。因为C#没有从1970年1月1日开始获取时间的方法。

所以我换了js,如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var d = new Date();
d.setFullYear(1927,12,31);
d.setHours(23);
d.setMinutes(54);
d.setSeconds(7);

var a = new Date();
a.setFullYear(1927,12,31);
a.setHours(23);
a.setMinutes(54);
a.setSeconds(8);
var t1=d.getTime()/1000;
var t2=a.getTime()/1000;
alert(t1);
alert(t2);
alert(t2-t1);

答案依旧,都是1的结果,那么,是不是我的测试代码不正确呢?还是这个问题已经解决了?或者。。是不是只有java有这样的问题?

我依然没有得到答案。

201108130035:上面提到一个东西,叫做地方平时,我在网上搜到一个对地方平时的解释:

local mean time

地方时的一种,地方平太阳时的简称。

体现平太阳的周日视运动。它没有季节性的快慢变化,因而不同于地方视时。

由于地区间的联系日益频繁,它在实用上已被标准时(区时或法定时)所代替。

通常根据标准时和地方经度进行推算,也可根据太阳的地方时角和时差进行推算。

地方平太阳时:http://baike.baidu.com/view/37435.htm

上面这个是百度百科对地方平太阳时的解释。

大家都知道,在java中gettime方法获取的时间是自1970年1月1日开始至此地毫秒数。而上面用的时间是1927年12月31日。早于1970年,所以,流传着一种说法,就是1928年的1月1日开始,当地的时间计时更改为格林威治标准时间,而格林威治标准时间与当地的地方平时正好相差了5分52秒。至于我用C#没有得出353或许是因为C#中获取的时间戳是从0001年1月1日开始的。

也许是jdk的关系造成这样的结果吧。


程序员的午夜一秒谜案:1927年12月31日
https://oujun.work/2011/08/12/19271231.html
作者
欧俊
发布于
2011年8月12日
许可协议