Erlang Central

Difference between revisions of "Convert Epoch Seconds to DMYHMS"

From ErlangCentral Wiki

(reverted spam... sigh)
(Added a symmetric solution that returns values)
Line 14:Line 14:
 
{{34,4,26},{23,34,18}}
 
{{34,4,26},{23,34,18}}
 
4> io:fwrite("Today's Date is ~2B/~2B/~4..0B ~2B:~2.10.0B:~2.10.0B\n",
 
4> io:fwrite("Today's Date is ~2B/~2B/~4..0B ~2B:~2.10.0B:~2.10.0B\n",
4> [Month, Day, Year, Hour, Min, Sec]).
+
              [Month, Day, Year, Hour, Min, Sec]).
 
Today's Date is  4/26/0034 23:34:18
 
Today's Date is  4/26/0034 23:34:18
 
ok                       
 
ok                       
Line 26:Line 26:
 
6> io_lib:fread("~4d-~2d-~2dT~2d:~2d:~2d-~4d", Some_Date_String).
 
6> io_lib:fread("~4d-~2d-~2dT~2d:~2d:~2d-~4d", Some_Date_String).
 
{ok,[2004,4,26,18,26,18,500],[]}
 
{ok,[2004,4,26,18,26,18,500],[]}
 +
</code>
 +
 +
 +
== Symmetric conversion ==
 +
 +
[[Author:Thomas Arts]]
 +
 +
The above conversion writes directly to the console, but sometimes, one would like an approach in which functions return the converted string and given a string, seconds are returned:
 +
<code>
 +
epoch_to_mdyhms(Seconds) -> DateString
 +
mdyhms_to_epoch(DateString) -> Seconds
 +
</code>
 +
When creating such a solution, symmetry is an important property to strive after. Intuitively, one expects the following property to hold for conversions
 +
<code>
 +
prop_epoch_mdyhms_identity() ->
 +
    ?FORALL(Seconds,seconds(),
 +
            mdyhms_to_epoch(epoch_to_mdyhms(Seconds)) == Seconds).
 +
 +
seconds() ->
 +
    ?LET(I,largeint(),abs(I)).
 +
</code>
 +
However, that property clearly is violated in the code above, which we can observe by manually looking at the output produced.
 +
 +
A symmetric and testable solution is given by:
 +
<code>
 +
epoch_to_mdyhms(Seconds) ->
 +
    {{Year, Month, Day}, {Hour, Min, Sec}} =
 +
        calendar:gregorian_seconds_to_datetime(Seconds),
 +
    lists:flatten(
 +
io_lib:fwrite("~2B/~2B/~4..0B ~2B:~2.10.0B:~2.10.0B",
 +
                      [Month, Day, Year, Hour, Min, Sec])).
 +
 +
 +
mdyhms_to_epoch(DateString) ->
 +
{ok,[Month, Day, Year, Hour, Min, Sec],_} =
 +
  io_lib:fread("~d/~d/~d ~d:~d:~d", DateString),
 +
        calendar:datetime_to_gregorian_seconds({{Year,Month,Day},{Hour,Min,Sec}}).
 
</code>
 
</code>
  
 
[[Category:CookBook]][[Category:DateTimeRecipes]]
 
[[Category:CookBook]][[Category:DateTimeRecipes]]

Revision as of 14:15, 9 August 2008

Problem

You have a date and time in Erlang Epoch seconds (i.e., Gregorian calendar year 0 seconds), and you want to calculate the individual DMYHMS values from it.

Solution

In recipe TimeToday we did exactly this but only for the current date. How about if we wanted to get the date, and time (DMYHMS) associated to a particular number of seconds? Once more we would use gre.

1> Seconds = 1083022458.
1083022458
2> DateTime = calendar:gregorian_seconds_to_datetime(Seconds).
{{34,4,26},{23,34,18}}
3> {{Year, Month, Day}, {Hour, Min, Sec}} = DateTime.
{{34,4,26},{23,34,18}}
4> io:fwrite("Today's Date is ~2B/~2B/~4..0B ~2B:~2.10.0B:~2.10.0B\n",
              [Month, Day, Year, Hour, Min, Sec]).
Today's Date is  4/26/0034 23:34:18
ok                       

In recipe TimeToday we discussed how to convert a date structure to a string. Convert in the opposite direction is also possible, and useful. Unfortunately, there is not a lot of built-in Erlang plumbing to do so. However, if we are very sure of the format we can easily extract the data we need using Erlang's ever-helpful io and io_lib modules:

5> Some_Date_String = "2004-04-26T18:26:18-0500".
"2004-04-26T18:26:18-0500".
6> {ok, [YYY,MMM,DD,HH,MM,SS,ZZ],_} = 
6> io_lib:fread("~4d-~2d-~2dT~2d:~2d:~2d-~4d", Some_Date_String).
{ok,[2004,4,26,18,26,18,500],[]}


Symmetric conversion

Author:Thomas Arts

The above conversion writes directly to the console, but sometimes, one would like an approach in which functions return the converted string and given a string, seconds are returned:

epoch_to_mdyhms(Seconds) -> DateString
mdyhms_to_epoch(DateString) -> Seconds

When creating such a solution, symmetry is an important property to strive after. Intuitively, one expects the following property to hold for conversions

prop_epoch_mdyhms_identity() ->
    ?FORALL(Seconds,seconds(),
            mdyhms_to_epoch(epoch_to_mdyhms(Seconds)) == Seconds).

seconds() ->
    ?LET(I,largeint(),abs(I)).

However, that property clearly is violated in the code above, which we can observe by manually looking at the output produced.

A symmetric and testable solution is given by:

epoch_to_mdyhms(Seconds) -> 
    {{Year, Month, Day}, {Hour, Min, Sec}} =
        calendar:gregorian_seconds_to_datetime(Seconds),
    lists:flatten(
	io_lib:fwrite("~2B/~2B/~4..0B ~2B:~2.10.0B:~2.10.0B",
                      [Month, Day, Year, Hour, Min, Sec])).


mdyhms_to_epoch(DateString) ->
	{ok,[Month, Day, Year, Hour, Min, Sec],_} = 
	   io_lib:fread("~d/~d/~d ~d:~d:~d", DateString),
        calendar:datetime_to_gregorian_seconds({{Year,Month,Day},{Hour,Min,Sec}}).