你确信你了解时间吗?
你还记得“软件真的好难做”中的那个有意思的例子吗?那个例子告诉我们软件开发中假设可能会是致命的事。今天,我又在StackOverflow上看到一个关于时间的问题——为什么1927年12月31日的午夜时间这么奇怪?提问题的这个人给了下面的一段java代码(我做一些修改,保证让你可以copy过去就可以编译运行)
我在其中高亮了几行,这个程序就是想比较一下“1927-12-31 23:54:07” 和 “1927-12-31 23:54:08” 差几秒,很明显,是差一秒。但是程序的输出却不是这样的。
import java.text.SimpleDateFormat; import java.text.ParseException; import java.util.Date; import java.util.TimeZone; class time{ public static void main(String[] args) throws ParseException { SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); sf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai")); 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(ld3); System.out.println(ld4); System.out.println(ld4-ld3); } }
下面,让我们来看看程序的输出:(是的,差出353秒钟来)
-1325491905
-1325491552
353
Stackoverflow真的很强大,在大家要求发问者给出时区(中国上海)的15分钟内就解决了这个问题。相当的令人惊叹。原因是什么呢?大家需要围观一下这个网页。(为了怕被墙或是被和谐,我已习惯了抓屏保存,如果有人能开发一个软件能随看随抓,然后如果源被删了可以P2P的从已下载了的人那里获取,那么这个软件应该会很有国内市场。蛋扯远了,Sorry)
从上图中我们可以看到—— 在1927年12月31日23:59:59时,往后面的一秒应该是1928年1月1日 0:0:0,但是这个时间被往后调整了5分52秒,而成了,1927年12月31日的,23:54:08,于是,完成了352秒的穿越。于是我们的Java程序出了这样的一个问题,这真是一个奇迹。
为什么会有这个调整呢?我居然Google不到,不过,我在这个timeanddate.com上查看了一下北京的时间,发现北京的时间只到1970年,于是我猜想,中国近代历史乱七八糟的政权交替可能是这个原因。于是我看 了一下北京和上海物理时差,果然,北京上海的时差在5分50秒左右。因此,我觉得这个时间的变化应该是从上海(南京)时间变成了北京时间。至于你信不信,反正我是信了。
从这个事,我得到下面的一些启示:
- Java在的时区实现相当的强大啊。这种细节都能考虑到。
- 本地时间的完全就是一锅粥,应该尽量不用。
- 如果你要开发和时区有关系的程序,你的系统里一定要使用GMT标准时间,仅在显示的时候才转成本地时间。
(转载本站文章请注明作者和出处 酷 壳 – CoolShell ,请勿用于任何商业用途)
《你确信你了解时间吗?》的相关评论
@pip
的确,按照您的说法,改为“Asia/Shanghai”,重新编译后,运行结果如下所示:
[email protected]:~/work/08$ javac time.java
[email protected]:~/work/08$ java time
-1325491905
-1325491552
353
[email protected]:~/work/08$
可见,在 Linux 操作系统中,不但文件名的大小写很重要,时区名称的大小写也很重要。
这个问题是程序员需要考虑的吗?表示压力很大。。。
反正它就是发生了
我觉得这就是一个BUG,不是什么强大的智能性。上海和北京之间也不可能存在时差,而且是353秒这么久。
最后追踪到 sun.util.calendar.ZoneInfoFile,各种时区信息数据库文件保存在/lib/zi目录下。
包括夏令时、天文学调整、立法调整等等都是用同样的方式处理的。
@dragonball
这个时差真的不是可能存在而是的确存在。。你跟你隔壁如果是东西向的,都存在时差,更别说是北京到上海经度差了这么多。地理常识~
這邊有對時區調整的說明,見「南京政府時期」一節
http://zh.wikipedia.org/wiki/%E4%B8%AD%E5%9C%8B%E6%99%82%E5%8D%80 (維基百科)
Wikipedia 好像在牆內是看不到的,我把相關文字轉貼過來:
====
民國17年(1928年),國民政府統一中國,原中央觀象台的業務由南京政府中央研究院的天文研究所和氣象研究所分別接收。天文研究所編寫的曆書基本上沿襲中央觀象台的做法,仍將全國劃分為5個標準時區,只是在有關交氣、合朔、太陽出沒時刻等處,不再使用北平的地方平時,而改以南京所在的標準時區的區時即東經120°標準時替代。
====
從北平地方平時改為東經120°標準時,兩者相差了352秒
剛沒看到第一頁的評論,結果發了重複的訊息。
好像也沒法子刪掉,抱歉了
也许这就是MySQL的Timestamp最小值不能小于1928-01-01 00:00:00的原因
不知道这个上海和北京之间的“物理时差”是什么概念,北京经度116°.25′(东西跨度2度)上海经度东经 121°.4′,最大跨度竟然有五度之多,地理时间上差了近20分钟。
太强悍了!居然这种细节到考虑到了!看来我们还有好多路要走啊!加油!
测试了下,和博主测试结果有很大差异哦!
JDK version:1.6.0_26
OS:Windows XP
我测出来结果是相差60秒。。。
其实大家对时区可能还有个误解。比如当朝正在用的“北京时间”,其实不是北京地方时(东经116.4°),而是北京所处的时区(东八区)的中间经线(东经120°)的“地方时”!
所以“北京时间”会比“北京市的地方时”早一点点哦~~
当然这个不是解释LZ的问题。
如果利用JAVA的时差之强大来做穿越项目的话。。。
这里解释稍微详细些
压力相当大,看来想成为一名真正优秀的程序员不是我想的那么容易啊
这尼玛还得了解近代史,擦!
但是1.4的JDK测试还是1s
這一期的Computerphile就是在說計算時間的難題(Youtube,翻牆注意)
http://youtu.be/-5wpm-gesOY
它的結論是:從此你不再自己去寫計算時間的系統,而是直接複製前人寫好的那一大坨代碼,放進自己的代碼裡,發誓以後不再嘗試去看這坨代碼,並感激前人把它寫好及開源了。
@dragonball
北京上海地方是是有差别的。
@haitao
中国放弃夏令时有不方便的原因,但是更主要的是不节省能源。
国外这种横跨多个时区而全国并不使用统一时间的情况下,夏令时让人们生产生活提前一个小时,能充分利用日光,缩短夜间活动时间,减少夜间电能消耗。
但是中国横跨多个时区又是全国统一时间,使用夏令时了之后东部地区能充分利用日光了,但是西部地区提前了之后太阳还没有升起来,还得用电,结果就是夏令时带来不方便了,却没有节约多少能源,得不偿失。
1928年变化之后应该是用中原标准时间,没有北京时间一说。
民国17年(1928年),国民政府统一中国,原中央观象台的业务由南京政府中央研究院的天文研究所和气象研究所分别接收。天文研究所编写的历书基本上沿袭中央观象台的做法,仍将全国划分为5个标准时区,只是在有关交气、合朔、太阳出没时刻等处,不再使用北平的地方平时,而改以南京所在的标准时区的区时即东经120°标准时替代
是由上海本地时间变为东八区标准时间
来晚了。实际上这是个bug,现在已经被修正。如楼上所说当时是把上海本地时间变为东八区标准时间。但是实际上,上海因为是口岸,至少从1903年就开始使用海岸时(即东八区标准时)。所以1928年的变化并不会影响上海的时区。