Erlang日期與時間處理

來源:互聯網
上載者:User

標籤:

  在開發過程中,有兩個概念是和地區地區相關的:字元編碼和時間;編碼和時間的規範演變過程中有文化的衝突有曆史的遺留,是軟體開發中充滿人文氣息的一角;關於字元編碼我之前整理過一篇文章, [Erlang 0024]Erlang位元據處理 這部分知識很有意思,特別是格列佛遊記所引出的大端小端概念,妙趣橫生;平時筆記中也零零散散記錄了一些和時間處理相關的內容,今天按圖索驥把相關的資料整理彙集於此.

    首先把時間相關的概念解釋一下: 有關時間的概念 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 Calendar 瞭解了這些之後,我們迴歸到技術之上,看一下Erlang中有關時間的計算,這基本上集中在calendar模組. 平時我們調用的erlang:now()得到的是從 00:00 GMT, January 1, 1970起經過的時間,結果構成為:{MegaSecs, Secs, MicroSecs},對於西曆計時的起點Erlang回溯到0年.若計算時間差,需轉成世界時間之後再進行計算;時間運算基於下面的規則: 

     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}).
false
22> calendar:valid_date({0,1,1}).
true26> 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).
計算是否閏年5> calendar:is_leap_year(1990).
false
6> calendar:is_leap_year(2000).
true  計算某年某月有多少天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 Timestamptimestamp() ->
    calendar:datetime_to_gregorian_seconds(erlang:universaltime()).或者:timestamp() ->
    {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"下面的代碼實現上面的時間格式化效果:
timestamp_to_iso({{Year, Month, Day}, {Hour, Minute, Second}}) ->    lists:flatten(      io_lib:format("~4..0w~2..0w~2..0wT~2..0w:~2..0w:~2..0w",            [Year, Month, Day, Hour, Minute, Second])).now_to_utc_string({MegaSecs, Secs, MicroSecs}) ->    {{Year, Month, Day}, {Hour, Minute, Second}} =    calendar:now_to_universal_time({MegaSecs, Secs, MicroSecs}),    lists:flatten(      io_lib:format("~4..0w-~2..0w-~2..0wT~2..0w:~2..0w:~2..0w.~6..0wZ",            [Year, Month, Day, Hour, Minute, Second, MicroSecs])).now_to_local_string({MegaSecs, Secs, MicroSecs}) ->    LocalTime = calendar:now_to_local_time({MegaSecs, Secs, MicroSecs}),    UTCTime = calendar:now_to_universal_time({MegaSecs, Secs, MicroSecs}),    Seconds = calendar:datetime_to_gregorian_seconds(LocalTime) -            calendar:datetime_to_gregorian_seconds(UTCTime),    {{H, M, _}, Sign} = if                Seconds < 0 ->                {calendar:seconds_to_time(-Seconds), "-"};                true ->                {calendar:seconds_to_time(Seconds), "+"}    end,    {{Year, Month, Day}, {Hour, Minute, Second}} = LocalTime,    lists:flatten(      io_lib:format("~4..0w-~2..0w-~2..0wT~2..0w:~2..0w:~2..0w.~6..0w~s~2..0w:~2..0w",            [Year, Month, Day, Hour, Minute, Second, MicroSecs, Sign, H, M])).% yyyy-mm-ddThh:mm:ss[.sss]{Z|{+|-}hh:mm} -> {MegaSecs, Secs, MicroSecs}datetime_string_to_timestamp(TimeStr) ->    case catch parse_datetime(TimeStr) of    {‘EXIT‘, _Err} ->        undefined;    TimeStamp ->        TimeStamp    end.parse_datetime(TimeStr) ->    [Date, Time] = string:tokens(TimeStr, "T"),    D = parse_date(Date),    {T, MS, TZH, TZM} = parse_time(Time),    S = calendar:datetime_to_gregorian_seconds({D, T}),    S1 = calendar:datetime_to_gregorian_seconds({{1970, 1, 1}, {0, 0, 0}}),    Seconds = (S - S1) - TZH * 60 * 60 - TZM * 60,    {Seconds div 1000000, Seconds rem 1000000, MS}.% yyyy-mm-ddparse_date(Date) ->    [Y, M, D] = string:tokens(Date, "-"),    Date1 = {list_to_integer(Y), list_to_integer(M), list_to_integer(D)},    case calendar:valid_date(Date1) of    true ->        Date1;    _ ->        false    end.% hh:mm:ss[.sss]TZDparse_time(Time) ->    case string:str(Time, "Z") of    0 ->        parse_time_with_timezone(Time);    _ ->        [T | _] = string:tokens(Time, "Z"),        {TT, MS} = parse_time1(T),        {TT, MS, 0, 0}    end.parse_time_with_timezone(Time) ->    case string:str(Time, "+") of    0 ->        case string:str(Time, "-") of        0 ->            false;        _ ->            parse_time_with_timezone(Time, "-")        end;    _ ->        parse_time_with_timezone(Time, "+")    end.parse_time_with_timezone(Time, Delim) ->    [T, TZ] = string:tokens(Time, Delim),    {TZH, TZM} = parse_timezone(TZ),    {TT, MS} = parse_time1(T),    case Delim of    "-" ->        {TT, MS, -TZH, -TZM};    "+" ->        {TT, MS, TZH, TZM}    end.parse_timezone(TZ) ->    [H, M] = string:tokens(TZ, ":"),    {[H1, M1], true} = check_list([{H, 12}, {M, 60}]),    {H1, M1}.parse_time1(Time) ->    [HMS | T] =  string:tokens(Time, "."),    MS = case T of         [] ->         0;         [Val] ->         list_to_integer(string:left(Val, 6, $0))     end,    [H, M, S] = string:tokens(HMS, ":"),    {[H1, M1, S1], true} = check_list([{H, 24}, {M, 60}, {S, 60}]),    {{H1, M1, S1}, MS}.check_list(List) ->    lists:mapfoldl(      fun({L, N}, B)->      V = list_to_integer(L),      if          (V >= 0) and (V =< N) ->          {V, B};          true ->          {false, false}      end      end, true, List).

 

構造日期文字


% a function to format date/time properly (e.g. 09 instead of 9)return_2columns(X) ->    case length(X) of        1 ->            "0" ++ X;        _ ->            X    end.%%% 顯然這裡可以直接使用 io_lib:format("~2..0B", [X])% returns date/time as a properly formatted string (e.g. "01-01-2000 12:12:12")get_current_time() ->    {{Y, M, D}, {H, Mi, S}} = calendar:local_time(),    L = lists:map(fun(X) ->                           X2=integer_to_list(X),                           return_2columns(X2)                   end,                   [Y, M, D, H, Mi, S]                 ),    [Y2, M2, D2, H2, Mi2, S2] = L,    Y2 ++ "-" ++ M2 ++ "-" ++ D2 ++ " " ++ H2 ++ ":" ++ Mi2 ++ ":" ++ S2.

 當然下面的程式碼片段也很有可能被用到:

 
day(1) -> "Mon";day(2) -> "Tue";day(3) -> "Wed";day(4) -> "Thu";day(5) -> "Fri";day(6) -> "Sat";day(7) -> "Sun".month_to_list(1)  -> "Jan";month_to_list(2)  -> "Feb";month_to_list(3)  -> "Mar";month_to_list(4)  -> "Apr";month_to_list(5)  -> "May";month_to_list(6)  -> "Jun";month_to_list(7)  -> "Jul";month_to_list(8)  -> "Aug";month_to_list(9)  -> "Sep";month_to_list(10) -> "Oct";month_to_list(11) -> "Nov";month_to_list(12) -> "Dec".list_to_month("Jan") -> 1;list_to_month("Feb") -> 2;list_to_month("Mar") -> 3;list_to_month("Apr") -> 4;list_to_month("May") -> 5;list_to_month("Jun") -> 6;list_to_month("Jul") -> 7;list_to_month("Aug") -> 8;list_to_month("Sep") -> 9;list_to_month("Oct") -> 10;list_to_month("Nov") -> 11;list_to_month("Dec") -> 12. 

Note:(Day)這個概念是和時區有關的,使用Unix時間戳記計算的時候要考慮到時區差異,比如兩個Unix時間戳記是否在同一天,一天的起始時間的時間戳記,等等;軟體多語言版本的時候這個問題特別要關注 

 

 晚 安 ! 

  相關資料:[1] 時區 http://zh.wikipedia.org/wiki/%E6%97%B6%E5%8C%BA[2] 國家授時中心網路伺服器時間發布 http://www.time.ac.cn/stime.asp[3] GMT時間 http://zh.wikipedia.org/wiki/GMT[4] UTC時間 http://zh.wikipedia.org/wiki/%E5%8D%94%E8%AA%BF%E4%B8%96%E7%95%8C%E6%99%82[5] UNIX時間 http://zh.wikipedia.org/wiki/UNIX%E6%97%B6%E9%97%B4[6] 千年蟲問題 http://zh.wikipedia.org/wiki/%E5%8D%83%E5%B9%B4%E8%99%AB[7] 西曆 http://en.wikipedia.org/wiki/Gregorian_calendar[8] 夏時制 http://zh.wikipedia.org/wiki/%E5%A4%8F%E6%97%B6%E5%88%B6[9] 日期格式化 http://en.wikipedia.org/wiki/ISO_8601[10] $100 http://zh.wikipedia.org/wiki/100%E7%BE%8E%E5%85%83%E7%BA%B8%E5%B8%81

Erlang日期與時間處理

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.