首先把時間相關的概念解釋一下:
GMT時間
格林尼治标準時間(Greenwich Mean Time ,GMT)是指位于英國倫敦郊區的皇家格林尼治天文台的标準時間,因為本初子午線被定義在通過那裡的經線.自1924年2月5日開始,格林尼治天文台每隔一小時會向全世界發放調時資訊.
理論上來說,格林尼治标準時間的正午是指當太陽橫穿格林尼治子午線時的時間.由于地球在它的橢圓軌道裡的運動速度不均勻,這個時刻可能與實際的太陽時有誤差,最大誤差達16分鐘.由于地球每天的自轉是有些不規則的,而且正在緩慢減速,是以格林尼治時間已經不再被作為标準時間使用.現在的标準時間,是由原子鐘報時的協調世界時(UTC).
UTC時間
UTC時間是 Universal Time, Coordinated的縮寫;中文名為協調世界時,又稱世界标準時間或世界協調時間;這個略顯怪異的名字來由是這樣的:國際電信聯盟希望協調世界時能夠在所有語言有單一的縮寫.英語和法語區的人同時希望各自的語言縮寫,CUT和TUC,能夠成為國際标準.結果最後妥協使用UTC.
這套時間系統被應用于許多網際網路和網際網路的标準中,例如,網絡時間協定就是協調世界時在網際網路中使用的一種方式.在軍事和航空中,協調世界時區會使用“Z”來表示.
在中國大陸,港澳台的本地時間比UTC快8小時,就會寫作UTC+8,俗稱東8區。如果是在本地時間比UTC時間慢的地區,例如夏威夷的時間是比UTC時間慢10小時,就會寫作UTC-10,并俗稱西10區。
時區
理論時區以被15整除的子午線為中心,向東西兩側延伸7.5度,即每15°劃分一個時區,這是理論時區.理論時區的時間采用其中央經線(或标準經線)的地方時.是以每差一個時區,區時相差一個小時,相差多少個時區,就相差多少個小時.東邊的時區比西邊的時區時間來得早.為了避免日期的紊亂,提出國際日期變更線的概念。為了避開國界線,有的時區的形狀并不規則,而且比較大的國家以國家内部行政分界線為時區界線,這是實際時區,即法定時區.
所有的時區都相對于UTC時設定.
UNIX時間戳
UNIX時間或稱POSIX時間是UNIX或類UNIX系統使用的時間表示方式:從UTC時1970年1月1日0時0分0秒起至現在的總秒數.
2038年問題:現時大部分使用UNIX的系統都是32位元的,即它們會以32位二進制數字表示時間.但是它們最多隻能表示至協調世界時間2038年1月19日3時14分07秒(二進制:01111111 11111111 11111111 11111111),在下一秒二進制數字會是10000000 00000000 00000000 00000000,這是負數,是以各系統會把時間誤解作1901年12月13日20時45分52秒(亦有說回歸到1970年)。這時可能會令軟體發生問題,導緻系統癱瘓。
目前解決方案是把系統由32位元轉為64位元系統。在64位系統下,此時間最多可以表示到292,277,026,596年12月4日15時30分08秒。
是不是想到了很久以前的千年蟲問題?
公曆 Gregorian calendar
公曆是現在國際通用的曆法,又稱格列曆,通稱陽曆.“陽曆”又名“太陽曆”,系以地球繞行太陽一周為一年,為西方各國所通用,故又名“西曆”.公曆定義了月,閏月等計算方式;能夠廢掉帝号紀年法,是文化上的一大進步.除了帝号紀年我國還有幹支紀年法,這個很有意思,即把十天幹(甲,乙,丙,丁,戊,己,庚,辛,壬,癸)和十二地支(子,醜,寅,卯,辰,巳,午,未,申,酉,戌,亥)分别組合起來,共配成六十組,用來表示年月日的次序,周而複始,循環使用.
2012年是壬辰年,呵呵,明白為什麼好多人選擇在今年生孩子了吧?
夏令時 DST
電影《國家寶藏》裡面有一個情節就是三個人看到美元背後的4:10以為來不及了,但是意識到夏時令之後,發現還有一個小時的時間,一切還來得及;那麼什麼是夏令時呢?
夏時制(Daylight Saving Time:DST)又稱“日光節約時制”和“夏令時間”,是一種為節約能源而人為規定地方時間的制度,在這一制度實行期間所采用的統一時間稱為“夏令時間”.一般在天亮早的夏季人為将時間提前一小時,可以使人早起早睡,減少照明量,以充分利用光照資源,進而節約照明用電.各個采納夏時制的國家具體規定不同.目前全世界有近110個國家每年要實行夏令時. 自2011年3月27日開始俄羅斯永久使用夏令時,把時間撥快一小時,不再調回.
據稱最早有夏令時構思的是本傑明·富蘭克林 夏令時的提出者本傑明·富蘭克林(被印在100美元鈔票上的人物),他在任美國駐法國大使期間,由于習慣于當時美國農村貴族的早睡早起生活,早上散步時看到法國人10點才起床,夜生活過到深夜.于是他在1784年給《巴黎雜志》的編輯寫了一封信,信上說法國人的生活習慣浪費了大好的陽光,建議他們早睡早起,說每年可以節約6千4百萬磅蠟燭.但他當時并沒有建議實行夏令時,隻是建議人們應該早睡早起.直到1907年,一位英國建築師威廉·維萊特(William Willett)才正式向英國議會提出夏時制的構思,主要是為了節省能源和提供更多的時間用來訓練士兵,但議會經過辯論沒有采納.由于名聲不及本傑明·富蘭克林,是以人們很多都将本傑明·富蘭克林當為夏時制的發明者而忽略了威廉·維萊特.
中國曾在1986-1991年推行夏時制,後停止原因是:1.區域遼闊大部分地區都沒有必要實行2.中國大多數的平民都已習慣中原標準時間,實行夏令時對于他們來說難以接受,認為多此一舉.3.夏時制使鐵路和航班需要每年修改時間表,造成麻煩和不便.
公元紀元
"公曆紀元"是國際通行的紀年體系.以傳說中耶稣基督的生年為公曆元年,産生于基督教盛行的六世紀,當時,為了擴大教會的統治勢力,神父們把任何事情都附會在基督教上.
日期時間格式化表示
文化差異下日期的表示方式也各有不同,就英語而言英聯邦國家和美國就在日期表示慣用法上有不同;要想流暢的溝通就要有日期時間的表示規範,ISO 8601對日期時間表示做了詳細的描述,可以看一下維基百科的簡介.
erlang:now() Returns the tuple {MegaSecs, Secs, MicroSecs} which is the elapsed time since 00:00 GMT, January 1, 1970 (zero hour) on the assumption that the underlying OS supports this. Otherwise, some other point in time is chosen. It is also guaranteed that subsequent calls to this BIF returns continuously increasing values. Hence, the return value from now() can be used to generate unique time-stamps, and if it is called in a tight loop on a fast machine the time of the node can become skewed.
It can only be used to check the local time of day if the time-zone info of the underlying operating system is properly configured.
• there are 86400 seconds in a day
• there are 365 days in an ordinary year
• there are 366 days in a leap year
• there are 1461 days in a 4 year period
• there are 36524 days in a 100 year period
• there are 146097 days in a 400 year period
• there are 719528 days between Jan 1, 0 and Jan 1, 1970.
以及閏年規則:
• Y is divisible by 4, but not by 100; or
• Y is divisible by 400.
calendar子產品已經廢棄或者不建議使用的子產品:
local_time_to_universal_time({Date1, Time1}) -> {Date2, Time2}
time_difference(T1, T2) -> {Days, Time}
erlang:now轉本地時間
15> calendar:now_to_local_time(erlang:now()).
{{2012,5,17},{14,32,6}}
erlang:now轉世界時間
16> calendar:now_to_universal_time(erlang:now()).
{{2012,5,17},{6,33,2}}
17>
驗證合法的日期
20> calendar:valid_date({0,0,0}).
false
21> calendar:valid_date({0,1,0}).
22> calendar:valid_date({0,1,1}).
true
26> calendar:valid_date(90,1,10).
true
獲得本地時間 年 月 日小時 分 秒
1> {{Year,Month,Day},{Hour,Min,Second}}=calendar:local_time().
{{2012,5,17},{14,13,14}}
2> b().
Day = 17
Hour = 14
Min = 13
Month = 5
Second = 14
Year = 2012
ok
獲得世界時間
3> calendar:universal_time().
{{2012,5,17},{6,16,27}}
本地時間轉換到世界時間
10> calendar:local_time_to_universal_time_dst({{2012,3,12},{3,23,12}}).
[{{2012,3,11},{19,23,12}}]
11> calendar:local_time_to_universal_time_dst({{2012,3,12},{4,23,12}}).
[{{2012,3,11},{20,23,12}}]
12> calendar:local_time_to_universal_time_dst({{2012,3,12},{5,23,12}}).
[{{2012,3,11},{21,23,12}}]
13> calendar:local_time_to_universal_time_dst({{2012,3,12},{15,23,12}}).
[{{2012,3,12},{7,23,12}}]
14> calendar:local_time_to_universal_time_dst({{2012,3,12},{16,23,12}}).
[{{2012,3,12},{8,23,12}}]
世界時間轉本地時間
12> calendar:universal_time_to_local_time({{2012,3,12},{3,23,12}}).
{{2012,3,12},{11,23,12}}
13> calendar:universal_time_to_local_time({{2012,3,12},{5,23,12}}).
{{2012,3,12},{13,23,12}}
14> calendar:universal_time_to_local_time({{2012,3,12},{20,23,12}}).
{{2012,3,13},{4,23,12}}
計算是星期幾
13> calendar:day_of_the_week(1984,5,15).
2
14> calendar:day_of_the_week(2012,5,17).
4
計算是否閏年
5> calendar:is_leap_year(1990).
6> calendar:is_leap_year(2000).
計算某年某月有多少天
7> calendar:last_day_of_the_month(2000,2).
29
8> calendar:last_day_of_the_month(2000,3).
31
9> calendar:last_day_of_the_month(1990,2).
28
秒轉時間
4> calendar:now_to_datetime(erlang:now()).
{{2012,5,17},{5,41,24}}
5> calendar:seconds_to_daystime(87400).
{1,{0,16,40}}
6> calendar:seconds_to_daystime(97400).
{1,{3,3,20}}
7> calendar:seconds_to_daystime(80400).
{0,{22,20,0}}
如果沒有超過一天可以使用
8> calendar:seconds_to_time(80400).
{22,20,0}
9> calendar:seconds_to_time(86400).
** exception error: no function clause matching calendar:seconds_to_time(86400) (calendar.erl, line 357)
時間轉到秒
10> calendar:time_to_seconds({22,20,0}).
80400
11> calendar:time_to_seconds({1,{22,20,0}}).
** exception error: no function clause matching calendar:time_to_seconds({1,{22,20,0}}) (calendar.erl, line 390)
計算Unix Timestamp
timestamp() ->
calendar:datetime_to_gregorian_seconds(erlang:universaltime()).
或者:
{M, S, _} = erlang:now(),
M * 1000000 + S.
日期時間格式化
16> test:now_to_local_string(erlang:now()).
"2012-05-17T16:14:42.195510+08:00"
17> test:now_to_utc_string(erlang:now()).
"2012-05-17T08:15:26.907466Z"
18> test:timestamp_to_iso(calendar:local_time()).
"20120517T16:27:18"
下面的代碼實作上面的時間格式化效果:
構造日期字元串
當然下面的代碼段也很有可能被用到:
Note:天(Day)這個概念是和時區有關的,使用Unix時間戳計算的時候要考慮到時區差異,比如兩個Unix時間戳是否在同一天,一天的起始時間的時間戳,等等;軟體多語言版本的時候這個問題特别要關注
晚 安 !
相關資料:
[11] http://stackoverflow.com/questions/5468791/erlang-timestamp-with-time-zone-arithmetics
[12] https://github.com/choptastic/qdate/blob/master/src/qdate.erl
[13] Erlang Date and Timezone Handling with qdate http://sigma-star.com/blog/post/qdate