zoukankan      html  css  js  c++  java
  • 程序员如何处理好时区问题

    写国际化的程序,经常会遇到两种问题:字符编码、时间问题。今天我们就聊聊程序中如何处理时间问题。

    首先,要了解一些基本的概念,只有对概念有清晰的掌握,才能明白解决方法。

    基本概念

    GMT时间:格林尼治标准时间(英语:Greenwich Mean Time,GMT)是指位于英国伦敦郊区的皇家格林尼治天文台当地的平太阳时,因为本初子午线被定义为通过那里的经线。

    由于地球每天的自转是有些不规则的,而且正在缓慢减速,因此格林尼治平时基于天文观测本身的缺陷,已经被原子钟报时的协调世界时(UTC)所取代。

    UTC时间:协调世界时(英语:Coordinated Universal Time,法语:Temps Universel Coordonné,简称UTC)是最主要的世界时间标准,其以原子时秒长为基础,在时刻上尽量接近于格林尼治标准时间。

    对于大多数用途来说,UTC时间被认为能与GMT时间互换,但GMT时间已不再被科学界所确定。

    UNIX时间戳:Unix time又叫POSIX time或UNIX Epoch time,是从UTC时间1970年1月1日起到现在的秒数,不考虑闰秒,一天有86400秒。

    时区:时区是地球上的区域使用同一个时间定义。世界各个国家位于地球不同位置上,因此不同国家特别是东西跨度大的国家日出、日落时间必定有所偏差。这些偏差就是所谓的时差。

    闰秒:闰秒是在协调世界时(UTC)中增加或减少一秒,使它与平太阳时贴近所做调整。在UTC时间中,有时会出现一分钟有59秒或61秒。

    夏令时:美国原本于每年4月的第一个星期日凌晨2时起至10月的最后一个星期日凌晨2时实施夏时制;但经美国国会2005年通过的能源法案,自2007年起延长夏时制,开始日期从每年4月的第一个星期日,提前到3月的第二个星期日,结束日期从每年10月的最后一个星期日,延后到11月的第一个星期日。美国夏时制实行与否,完全由各州各郡自己决定。

    时间格式的标准:参考ISO_8601日期格式标准 https://zh.wikipedia.org/wiki/ISO_8601。例如:2004-05-03T17:30:08+08:00 在时间前面加上大些字母T,要标明偏移的时区时间。

    概念解读

    通过上面的概念介绍了解到,GMT就是0时区的时间,以前是标准,但现在国际上已经用UTC取代他了。在写程序时,可以认为UTC和GMT是等价的。为了严谨只需要关心UTC时间。

    UNIX时间戳是程序中最常用的,他的特点是和UTC时间的1970年1月1日到现在的秒数,和时区无关,无论在地球上的那个角落,同一时刻,UNIX时间戳都是一样的。是一个通用的时间偏移度量,计算每个时区当地时间时,都可以用时间戳推算出来。

    不同时区的时间,都用UTC时间的偏移来计算。例如北京是东八区,比UTC时间快8个小时,所以计算北京时间,就在UTC时间的基础上加8个小时实现。

    我们在调用系统函数展示时间时,底层是根据UNIX时间戳转换为UTC时间,再加上偏移的小时数,就得出了程序要用的当地时间。

    UNIX时间戳可以映射到每个时区的当地时间,如果程序涉及到两个时区的时间转换,最好的方法是存储UNIX时间戳,在使用的时候再做转换。

    在各种语言的函数库中,都已经定义了时间时区转换的函数。在使用时,还有一点要注意「时区偏移(time offset)」和「时区地区(time zone)」是两个不同的概念。

    偏移是一个数学上的值,直接能计算出时间。时区地区,会根据当地的法律规则,来得出最终的时间,混入了人为的规则。

    例如:
    在夏令时时,北京和纽约时差是12个小时,但是当夏令时结束时,北京和纽约的时差是11个小时。如果一直用固定的时间偏移,就会计算出错。如果用指定的地区当参数,就会根据当地规则返回正确时间。

    具体例子见代码:

    <?php                                                                              
    
    date_default_timezone_set('Asia/Shanghai');                                        
    $d=strtotime("2018-11-04 13:00:00");                                               
    echo "Beijing " . date("Y-m-d h:i:sa", $d) . "
    ";                                 
    
    date_default_timezone_set('America/New_York');                                     
    echo "NewYork " . date("Y-m-d h:i:sa", $d) . "
    ";                                 
    
    echo "
    ";                                                                         
    
    date_default_timezone_set('Asia/Shanghai');                                        
    $d=strtotime("2018-11-04 14:00:00");                                               
    echo "Beijing " . date("Y-m-d h:i:sa", $d) . "
    ";                                 
    
    date_default_timezone_set('America/New_York');                                     
    echo "NewYork " . date("Y-m-d h:i:sa", $d) . "
    ";                                 
    
    echo "
    ";                                                                                                                                          
    
    date_default_timezone_set('Asia/Shanghai');                                        
    $d=strtotime("2018-11-04 15:00:00");                                               
    echo "Beijing " . date("Y-m-d h:i:sa", $d) . "
    ";                                 
    
    date_default_timezone_set('America/New_York');                                     
    echo "NewYork " . date("Y-m-d h:i:sa", $d) . "
    ";                                 
    
    

    输出结果

    Beijing 2018-11-04 01:00:00pm   //没结束夏令时时,时差12个小时
    NewYork 2018-11-04 01:00:00am
    
    Beijing 2018-11-04 02:00:00pm   //夏令时切换,时差为11个小时
    NewYork 2018-11-04 01:00:00am
    
    Beijing 2018-11-04 03:00:00pm
    NewYork 2018-11-04 02:00:00am
    
    

    总结

    1. 涉及到多个时区的转换,统一使用unix时间戳存储或交互,或者使用带有时区信息的字符串。
    2. 尽量在上层的代码层面修改时区配置,不要修改系统或软件的配置,防止其他程序因为修改受到影响。

    本质:时区概念是上层人为转换的概念,程序的逻辑不要依赖于他,要有个统一的时刻值概念来衡量真实的时间(例如UNIX时间戳),然后在上层做转换。

    参考

    https://zh.wikipedia.org/wiki/%E6%A0%BC%E6%9E%97%E5%B0%BC%E6%B2%BB%E6%A8%99%E6%BA%96%E6%99%82%E9%96%93

    https://en.wikipedia.org/wiki/Unix_time

    https://zh.wikipedia.org/wiki/%E5%8D%8F%E8%B0%83%E4%B8%96%E7%95%8C%E6%97%B6

    https://zh.wikipedia.org/wiki/%E6%97%B6%E5%8C%BA

    https://www.cnblogs.com/zihanxing/articles/6224263.html


    转载请注明来源:程序员如何处理好时区问题
    欢迎收听公众号
  • 相关阅读:
    Recommender Systems 基于知识的推荐
    粒子群优化算法简介
    彻底弄懂LSH之simHash算法
    c++ 字符串函数用法举例
    Linux上的运行的jar包
    推荐系统判定标准
    python 细枝末节
    PV UV
    python解析json
    生成n对括号的所有合法排列
  • 原文地址:https://www.cnblogs.com/owenandhisfriends/p/10015572.html
Copyright © 2011-2022 走看看