2013-01-14 13:58:12 -06:00
|
|
|
-module(qdate).
|
|
|
|
|
|
|
|
-export([
|
|
|
|
to_string/1,
|
|
|
|
to_string/2,
|
2013-02-21 22:43:02 -06:00
|
|
|
to_string/3,
|
2013-01-14 13:58:12 -06:00
|
|
|
to_date/1,
|
2013-02-21 22:43:02 -06:00
|
|
|
to_date/2,
|
2013-01-14 13:58:12 -06:00
|
|
|
to_now/1,
|
2013-01-15 17:33:30 -06:00
|
|
|
to_unixtime/1,
|
|
|
|
unixtime/0
|
2013-01-14 13:58:12 -06:00
|
|
|
]).
|
|
|
|
|
2013-01-15 17:33:30 -06:00
|
|
|
%% -export([
|
|
|
|
%% register_parser/2,
|
|
|
|
%% register_parser/1
|
|
|
|
%% ]).
|
2013-02-21 22:43:02 -06:00
|
|
|
%%
|
|
|
|
%% -export([
|
|
|
|
%% register_format/2,
|
|
|
|
%% register_format/1
|
|
|
|
%% ]).
|
2013-01-15 17:33:30 -06:00
|
|
|
%%
|
2013-03-25 11:52:14 -05:00
|
|
|
-export([
|
|
|
|
set_timezone/1,
|
|
|
|
set_timezone/2,
|
|
|
|
get_timezone/0,
|
|
|
|
get_timezone/1,
|
|
|
|
clear_timezone/0,
|
|
|
|
clear_timezone/1
|
|
|
|
]).
|
2013-01-15 17:33:30 -06:00
|
|
|
|
|
|
|
|
2013-01-14 13:58:12 -06:00
|
|
|
%% Exported for API compatibility with ec_date
|
|
|
|
-export([
|
|
|
|
format/1,format/2,
|
|
|
|
nparse/1,
|
|
|
|
parse/1
|
|
|
|
]).
|
|
|
|
|
2013-01-15 17:33:30 -06:00
|
|
|
%% This the value in gregorian seconds for jan 1st 1970, 12am
|
|
|
|
%% It's used to convert to and from unixtime, since unixtime starts
|
|
|
|
%% 1970-01-01 12:00am
|
2013-03-06 17:19:08 -06:00
|
|
|
-define(UNIXTIME_BASE,62167219200).
|
2013-03-24 14:00:11 -05:00
|
|
|
|
|
|
|
%% This is the timezone only if the qdate application variable
|
|
|
|
%% "default_timezone" isn't set or is set to undefined.
|
|
|
|
%% It's recommended that your app sets the var in a config, or at least using
|
|
|
|
%%
|
|
|
|
%% application:set_env(qdate, default_timezone, "GMT").
|
|
|
|
%%
|
|
|
|
-define(DEFAULT_TZ, case application:get_env(qdate, default_timezone) of
|
|
|
|
undefined -> "GMT";
|
|
|
|
TZ -> TZ
|
|
|
|
end).
|
2013-01-14 13:58:12 -06:00
|
|
|
|
2013-03-25 11:52:14 -05:00
|
|
|
-define(DETERMINE_TZ, determine_timezone()).
|
|
|
|
|
|
|
|
|
2013-01-14 13:58:12 -06:00
|
|
|
to_string(Format) ->
|
|
|
|
to_string(Format, now()).
|
|
|
|
|
|
|
|
to_string(Format, Date) ->
|
2013-03-25 11:52:14 -05:00
|
|
|
to_string(Format, ?DETERMINE_TZ, Date).
|
2013-02-21 22:43:02 -06:00
|
|
|
|
|
|
|
to_string(Format, ToTZ, Date) ->
|
|
|
|
ec_date:format(Format,to_date(Date,ToTZ)).
|
2013-01-14 13:58:12 -06:00
|
|
|
|
|
|
|
format(Format) ->
|
|
|
|
to_string(Format).
|
|
|
|
|
|
|
|
format(Format, Date) ->
|
|
|
|
to_string(Format, Date).
|
|
|
|
|
|
|
|
parse(String) ->
|
|
|
|
to_date(String).
|
|
|
|
|
|
|
|
nparse(String) ->
|
2013-01-14 21:20:36 -06:00
|
|
|
to_now(String).
|
2013-01-14 13:58:12 -06:00
|
|
|
|
2013-02-21 22:43:02 -06:00
|
|
|
%% This converts dates without regard to timezone.
|
|
|
|
%% Unixtime just goes to UTC
|
|
|
|
raw_to_date(Unixtime) when is_integer(Unixtime) ->
|
2013-01-14 13:58:12 -06:00
|
|
|
unixtime_to_date(Unixtime);
|
2013-02-21 22:43:02 -06:00
|
|
|
raw_to_date(DateString) when is_list(DateString) ->
|
2013-01-14 13:58:12 -06:00
|
|
|
ec_date:parse(DateString);
|
2013-02-21 22:43:02 -06:00
|
|
|
raw_to_date(Now = {_,_,_}) ->
|
2013-01-14 13:58:12 -06:00
|
|
|
calendar:now_to_datetime(Now);
|
2013-02-21 22:43:02 -06:00
|
|
|
raw_to_date(Date = {{_,_,_},{_,_,_}}) ->
|
2013-01-14 13:58:12 -06:00
|
|
|
Date.
|
|
|
|
|
2013-02-21 22:43:02 -06:00
|
|
|
to_date(RawDate) ->
|
2013-03-25 11:52:14 -05:00
|
|
|
to_date(RawDate, ?DETERMINE_TZ).
|
2013-02-21 22:43:02 -06:00
|
|
|
|
2013-03-25 11:52:14 -05:00
|
|
|
to_date(RawDate, ToTZKey) when is_atom(ToTZKey) orelse is_tuple(ToTZKey) ->
|
|
|
|
case get_timezone(ToTZKey) of
|
|
|
|
undefined -> throw({timezone_key_not_found,ToTZKey});
|
|
|
|
ToTZ -> to_date(RawDate, ToTZ)
|
|
|
|
end;
|
2013-02-21 22:43:02 -06:00
|
|
|
to_date(RawDate, ToTZ) ->
|
|
|
|
{RawDate2,FromTZ} = extract_timezone(RawDate),
|
|
|
|
Date = raw_to_date(RawDate2),
|
|
|
|
localtime:local_to_local(Date,FromTZ,ToTZ).
|
|
|
|
|
2013-03-25 11:52:14 -05:00
|
|
|
set_timezone(TZ) ->
|
|
|
|
qdate_srv:set_timezone(TZ).
|
|
|
|
|
|
|
|
set_timezone(Key,TZ) ->
|
|
|
|
qdate_srv:set_timezone(Key, TZ).
|
|
|
|
|
|
|
|
get_timezone() ->
|
|
|
|
qdate_srv:get_timezone().
|
|
|
|
|
|
|
|
get_timezone(Key) ->
|
|
|
|
qdate_srv:get_timezone(Key).
|
|
|
|
|
|
|
|
clear_timezone() ->
|
|
|
|
qdate_srv:clear_timezone().
|
|
|
|
|
|
|
|
clear_timezone(Key) ->
|
|
|
|
qdate_srv:clear_timezone(Key).
|
|
|
|
|
2013-02-21 22:43:02 -06:00
|
|
|
extract_timezone(Unixtime) when is_integer(Unixtime) ->
|
2013-03-25 11:52:14 -05:00
|
|
|
{Unixtime, ?DETERMINE_TZ};
|
2013-02-21 22:43:02 -06:00
|
|
|
extract_timezone(DateString) when is_list(DateString) ->
|
|
|
|
AllTimezones = localtime:list_timezones(),
|
|
|
|
RevDate = lists:reverse(DateString),
|
|
|
|
extract_timezone_helper(RevDate, AllTimezones);
|
|
|
|
extract_timezone(Date={{_,_,_},{_,_,_}}) ->
|
2013-03-25 11:52:14 -05:00
|
|
|
{Date, ?DETERMINE_TZ};
|
2013-02-21 22:43:02 -06:00
|
|
|
extract_timezone(Now={_,_,_}) ->
|
2013-03-25 11:52:14 -05:00
|
|
|
{Now, ?DETERMINE_TZ};
|
2013-02-21 22:43:02 -06:00
|
|
|
extract_timezone({MiscDate,TZ}) ->
|
|
|
|
{MiscDate,TZ}.
|
|
|
|
|
|
|
|
extract_timezone_helper(RevDate, []) ->
|
2013-03-25 11:52:14 -05:00
|
|
|
{lists:reverse(RevDate), ?DETERMINE_TZ};
|
2013-02-21 22:43:02 -06:00
|
|
|
extract_timezone_helper(RevDate, [TZ | TZs]) ->
|
|
|
|
RevTZ = lists:reverse(TZ),
|
|
|
|
case lists:split(length(TZ),RevDate) of
|
|
|
|
{RevTZ," " ++ Remainder} ->
|
|
|
|
{lists:reverse(Remainder), TZ};
|
|
|
|
_ ->
|
|
|
|
extract_timezone_helper(RevDate, TZs)
|
|
|
|
end.
|
2013-01-14 13:58:12 -06:00
|
|
|
|
2013-03-25 11:52:14 -05:00
|
|
|
determine_timezone() ->
|
|
|
|
case qdate_srv:get_timezone() of
|
|
|
|
undefined -> ?DEFAULT_TZ;
|
|
|
|
TZ -> TZ
|
|
|
|
end.
|
|
|
|
|
2013-01-14 13:58:12 -06:00
|
|
|
to_unixtime(Unixtime) when is_integer(Unixtime) ->
|
|
|
|
Unixtime;
|
2013-01-15 17:33:30 -06:00
|
|
|
to_unixtime({MegaSecs,Secs,_}) ->
|
2013-03-07 00:03:05 -06:00
|
|
|
MegaSecs*1000000 + Secs;
|
2013-01-14 13:58:12 -06:00
|
|
|
to_unixtime(ToParse) ->
|
|
|
|
Date = to_date(ToParse),
|
2013-01-15 17:33:30 -06:00
|
|
|
calendar:datetime_to_gregorian_seconds(Date) - ?UNIXTIME_BASE.
|
2013-01-14 13:58:12 -06:00
|
|
|
|
2013-01-15 17:33:30 -06:00
|
|
|
unixtime() ->
|
|
|
|
to_unixtime(now()).
|
2013-01-14 13:58:12 -06:00
|
|
|
|
|
|
|
to_now(Now = {_,_,_}) ->
|
|
|
|
Now;
|
|
|
|
to_now(ToParse) ->
|
|
|
|
Unixtime = to_unixtime(ToParse),
|
|
|
|
unixtime_to_now(Unixtime).
|
|
|
|
|
|
|
|
|
|
|
|
unixtime_to_now(T) when is_integer(T) ->
|
|
|
|
MegaSec = floor(T/1000000),
|
|
|
|
Secs = T - MegaSec*1000000,
|
|
|
|
{MegaSec,Secs,0}.
|
|
|
|
|
|
|
|
unixtime_to_date(T) ->
|
|
|
|
Now = unixtime_to_now(T),
|
|
|
|
calendar:now_to_datetime(Now).
|
|
|
|
|
|
|
|
floor(N) when N >= 0 ->
|
|
|
|
trunc(N);
|
|
|
|
floor(N) when N < 0 ->
|
|
|
|
Int = trunc(N),
|
|
|
|
if
|
|
|
|
Int==N -> Int;
|
|
|
|
true -> Int-1
|
|
|
|
end.
|
2013-03-25 15:21:05 -05:00
|
|
|
|
|
|
|
tz_formatting(Date,Format,TZ) ->
|
|
|
|
%% e, I, O, P, and T, Z
|
|
|
|
%% e = "UTC, GMT, Atlantic,/Azores"
|
|
|
|
%% I = Daylight Saving on = 1, off = 0
|
|
|
|
%% O = GMT diff in hours: +0200
|
|
|
|
%% P = GMT diff in hours with color: +02:00
|
|
|
|
%% T = TZ abbreviation: EST, MDT
|
|
|
|
%% Z = TZ offset in seconds: -43200 - 50400
|
|
|
|
not_implemented.
|
2013-02-21 22:43:02 -06:00
|
|
|
|
|
|
|
%% TESTS
|
|
|
|
-include_lib("eunit/include/eunit.hrl").
|
|
|
|
|
2013-03-25 11:52:14 -05:00
|
|
|
%% emulates as if a forum-type website has a Site tz, and a user-specified tz
|
|
|
|
-define(SITE_TZ,"PST").
|
|
|
|
-define(USER_TZ,"CST").
|
|
|
|
-define(SELF_TZ,"EST"). %% Self will be the pid of the current running process
|
|
|
|
-define(SITE_KEY,test_site_key).
|
|
|
|
-define(USER_KEY,test_user_key).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tz_test_() ->
|
|
|
|
{
|
|
|
|
setup,
|
|
|
|
fun start_test/0,
|
|
|
|
fun stop_test/1,
|
|
|
|
fun(SetupData) ->
|
|
|
|
{spawn,[
|
|
|
|
simple_test(),
|
|
|
|
tz_tests(SetupData)
|
|
|
|
]}
|
|
|
|
end
|
|
|
|
}.
|
|
|
|
|
|
|
|
tz_tests(_) ->
|
|
|
|
[
|
|
|
|
?_assertEqual(?SELF_TZ,begin set_timezone(?SELF_TZ),get_timezone() end),
|
|
|
|
?_assertEqual(?USER_TZ,get_timezone(?USER_KEY)),
|
|
|
|
?_assertEqual(?SITE_TZ,get_timezone(?SITE_KEY))
|
|
|
|
].
|
|
|
|
|
|
|
|
simple_test() ->
|
2013-02-21 22:43:02 -06:00
|
|
|
[
|
|
|
|
?_assertEqual(0,to_unixtime({0,0,0})),
|
|
|
|
?_assertEqual({0,0,0},to_now(0)),
|
|
|
|
?_assertEqual(0,to_unixtime("1970-01-01 12:00am GMT")),
|
|
|
|
?_assertEqual(21600,to_unixtime("1970-01-01 12:00am CST")),
|
|
|
|
?_assertEqual(0,to_unixtime({{1970,1,1},{0,0,0}})),
|
|
|
|
?_assertEqual({{1970,1,1},{0,0,0}},to_date(0)),
|
2013-03-06 17:19:08 -06:00
|
|
|
?_assertEqual({{2013,03,07},{0,0,0}},to_date(to_unixtime("2013-03-07 12am"))),
|
2013-02-21 22:43:02 -06:00
|
|
|
?_assertEqual("2012-12-01 1:00pm", to_string("Y-m-d g:ia","EST","2012-12-01 12:00pm CST")),
|
|
|
|
?_assertEqual(to_unixtime("2012-01-01 12:00pm CST"), to_unixtime("2012-01-01 10:00am PST")),
|
|
|
|
?_assertEqual({{2012,12,31},{18,15,15}},to_date("Dec 31, 2012 6:15:15pm")),
|
|
|
|
?_assertEqual({{2013,1,1},{0,15,15}},to_date("December 31, 2012 6:15:15pm CST","GMT"))
|
|
|
|
].
|
|
|
|
|
2013-03-25 11:52:14 -05:00
|
|
|
%%tz_char_tests(_) ->
|
|
|
|
%% qdate:set_timezone(?SELF_TZ),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
start_test() ->
|
|
|
|
application:start(qdate),
|
|
|
|
qdate:set_timezone(?SITE_KEY,?SITE_TZ),
|
|
|
|
qdate:set_timezone(?USER_KEY,?USER_TZ).
|
|
|
|
|
|
|
|
stop_test(_) ->
|
|
|
|
ok.
|