Skip to content

Instantly share code, notes, and snippets.

@macintux
Created June 22, 2016 20:06
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save macintux/734c7c16b3f5887d7c588c9c05be4500 to your computer and use it in GitHub Desktop.
Save macintux/734c7c16b3f5887d7c588c9c05be4500 to your computer and use it in GitHub Desktop.
Illustrate key Erlang date/time structures and conversions.
%% Date formats in Erlang are a bit tricky to keep straight,
%% especially since the `calendar' library leverages Gregorian seconds
%% (seconds since year 0) rather than the more traditional UNIX epoch
%% seconds.
%%
%% This module illustrates the structures and conversions.
-module(erlang_dates).
-compile(export_all).
-record(formats, {
universal_datetime,
local_datetime,
utc_now,
utc_seconds,
gregorian_seconds
}).
%% Seconds between year 0 and 1970. Unsurprisingly, a pretty big number.
-define(GREGORIAN_MAGIC, 62167219200).
%% `os:timestamp/0' and `erlang:now/0' return a three-tuple
%% representing epoch time with megaseconds as the first element. This
%% value is multiplied against megaseconds to convert to UNIX epoch
%% seconds.
-define(MEGA_CONVERSION, 1000000).
%% Generate a set of equivalent(*) date/time values.
%%
%% * Caveat: These are only equivalent in US/Eastern time zone. The
%% `local_datetime' value would need to be modified for `test/0' to
%% pass on a system in any other time zone.
setup() ->
#formats{
%% A UTC datetime structure can be generated with
%% calendar:universal_time/0
universal_datetime = {{2016,6,22},{18,11,23}},
%% A local datetime structure can be generated with
%% calendar:local_time/0
local_datetime = {{2016,6,22},{14,11,23}},
%% A "now" structure can be generated with os:timestamp/0 or
%% (deprecated) erlang:now/0
utc_now = {1466,619083,272373},
%% Perhaps more properly named `epoch_seconds' since Gregorian
%% seconds are also effectively in UTC
utc_seconds = 1466619083,
gregorian_seconds = 63633838283
}.
test() ->
Data = setup(),
UD = Data#formats.universal_datetime,
UD = local_datetime_TO_universal_datetime(Data#formats.local_datetime),
UD = utc_now_TO_universal_datetime(Data#formats.utc_now),
UD = utc_seconds_TO_universal_datetime(Data#formats.utc_seconds),
UD = gregorian_seconds_TO_universal_datetime(Data#formats.gregorian_seconds),
LD = Data#formats.local_datetime,
LD = universal_datetime_TO_local_datetime(Data#formats.universal_datetime),
LD = utc_now_TO_local_datetime(Data#formats.utc_now),
LD = utc_seconds_TO_local_datetime(Data#formats.utc_seconds),
LD = gregorian_seconds_TO_local_datetime(Data#formats.gregorian_seconds),
US = Data#formats.utc_seconds,
US = universal_datetime_TO_utc_seconds(Data#formats.universal_datetime),
US = local_datetime_TO_utc_seconds(Data#formats.local_datetime),
US = utc_now_TO_utc_seconds(Data#formats.utc_now),
US = gregorian_seconds_TO_utc_seconds(Data#formats.gregorian_seconds),
GS = Data#formats.gregorian_seconds,
GS = universal_datetime_TO_gregorian_seconds(Data#formats.universal_datetime),
GS = local_datetime_TO_gregorian_seconds(Data#formats.local_datetime),
GS = utc_now_TO_gregorian_seconds(Data#formats.utc_now),
GS = utc_seconds_TO_gregorian_seconds(Data#formats.utc_seconds),
ok.
local_datetime_TO_universal_datetime(Datetime) ->
case calendar:local_time_to_universal_time_dst(Datetime) of
[] -> %% This local time literally did not exist during a DST jump forward
throw(illegal_conversion);
[_, _] -> %% This local time existed twice during a DST jump backward
throw(dst_ambiguous_conversion);
[UTC] ->
UTC
end.
utc_now_TO_universal_datetime(Now) ->
calendar:now_to_universal_time(Now).
utc_seconds_TO_universal_datetime(Seconds) ->
calendar:gregorian_seconds_to_datetime(Seconds + ?GREGORIAN_MAGIC).
gregorian_seconds_TO_universal_datetime(Seconds) ->
calendar:gregorian_seconds_to_datetime(Seconds).
universal_datetime_TO_local_datetime(Datetime) ->
calendar:universal_time_to_local_time(Datetime).
utc_now_TO_local_datetime(Now) ->
calendar:now_to_local_time(Now).
utc_seconds_TO_local_datetime(Seconds) ->
calendar:universal_time_to_local_time(
calendar:gregorian_seconds_to_datetime(
Seconds + ?GREGORIAN_MAGIC)).
gregorian_seconds_TO_local_datetime(Seconds) ->
calendar:universal_time_to_local_time(
calendar:gregorian_seconds_to_datetime(Seconds)).
universal_datetime_TO_utc_seconds(Datetime) ->
calendar:datetime_to_gregorian_seconds(Datetime)
- ?GREGORIAN_MAGIC.
local_datetime_TO_utc_seconds(Datetime) ->
calendar:datetime_to_gregorian_seconds(
local_datetime_TO_universal_datetime(Datetime))
- ?GREGORIAN_MAGIC.
utc_now_TO_utc_seconds(Now) ->
{M, S, _} = Now,
M*?MEGA_CONVERSION + S.
gregorian_seconds_TO_utc_seconds(Seconds) ->
Seconds - ?GREGORIAN_MAGIC.
universal_datetime_TO_gregorian_seconds(Datetime) ->
calendar:datetime_to_gregorian_seconds(Datetime).
local_datetime_TO_gregorian_seconds(Datetime) ->
calendar:datetime_to_gregorian_seconds(
local_datetime_TO_universal_datetime(Datetime)
).
utc_now_TO_gregorian_seconds(Now) ->
utc_seconds_TO_gregorian_seconds(utc_now_TO_utc_seconds(Now)).
utc_seconds_TO_gregorian_seconds(Seconds) ->
Seconds + ?GREGORIAN_MAGIC.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment