Add License and copyright to each page. Retab

This commit is contained in:
Jesse Gumm 2013-04-24 01:07:16 -05:00
parent c7cd5b6800
commit 7c55a6e8bf
4 changed files with 440 additions and 425 deletions

View file

@ -1,39 +1,43 @@
% vim: ts=4 sw=4 et
% Copyright (c) 2013 Jesse Gumm
% See LICENSE for licensing information.
%
-module(qdate). -module(qdate).
-export([ -export([
to_string/1, to_string/1,
to_string/2, to_string/2,
to_string/3, to_string/3,
to_date/1, to_date/1,
to_date/2, to_date/2,
to_now/1, to_now/1,
to_unixtime/1, to_unixtime/1,
unixtime/0 unixtime/0
]). ]).
-export([ -export([
register_parser/2, register_parser/2,
register_parser/1, register_parser/1,
deregister_parser/1, deregister_parser/1,
deregister_parsers/0, deregister_parsers/0,
register_format/2, register_format/2,
deregister_format/1, deregister_format/1,
set_timezone/1, set_timezone/1,
set_timezone/2, set_timezone/2,
get_timezone/0, get_timezone/0,
get_timezone/1, get_timezone/1,
clear_timezone/0, clear_timezone/0,
clear_timezone/1 clear_timezone/1
]). ]).
%% Exported for API compatibility with ec_date %% Exported for API compatibility with ec_date
-export([ -export([
format/1,format/2, format/1,format/2,
nparse/1, nparse/1,
parse/1 parse/1
]). ]).
%% This the value in gregorian seconds for jan 1st 1970, 12am %% This the value in gregorian seconds for jan 1st 1970, 12am
@ -45,312 +49,312 @@
%% "default_timezone" isn't set or is set to undefined. %% "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 %% It's recommended that your app sets the var in a config, or at least using
%% %%
%% application:set_env(qdate, default_timezone, "GMT"). %% application:set_env(qdate, default_timezone, "GMT").
%% %%
-define(DEFAULT_TZ, case application:get_env(qdate, default_timezone) of -define(DEFAULT_TZ, case application:get_env(qdate, default_timezone) of
undefined -> "GMT"; undefined -> "GMT";
TZ -> TZ TZ -> TZ
end). end).
-define(DETERMINE_TZ, determine_timezone()). -define(DETERMINE_TZ, determine_timezone()).
to_string(Format) -> to_string(Format) ->
to_string(Format, now()). to_string(Format, now()).
to_string(Format, Date) -> to_string(Format, Date) ->
to_string(Format, ?DETERMINE_TZ, Date). to_string(Format, ?DETERMINE_TZ, Date).
to_string(FormatKey, ToTZ, Date) when is_atom(FormatKey) orelse is_tuple(FormatKey) -> to_string(FormatKey, ToTZ, Date) when is_atom(FormatKey) orelse is_tuple(FormatKey) ->
Format = case qdate_srv:get_format(FormatKey) of Format = case qdate_srv:get_format(FormatKey) of
undefined -> throw({undefined_format_key,FormatKey}); undefined -> throw({undefined_format_key,FormatKey});
F -> F F -> F
end, end,
to_string(Format, ToTZ, Date); to_string(Format, ToTZ, Date);
to_string(Format, ToTZ, Date) when is_binary(Format) -> to_string(Format, ToTZ, Date) when is_binary(Format) ->
list_to_binary(to_string(binary_to_list(Format), ToTZ, Date)); list_to_binary(to_string(binary_to_list(Format), ToTZ, Date));
to_string(Format, ToTZ, Date) when is_list(Format) -> to_string(Format, ToTZ, Date) when is_list(Format) ->
%% it may seem odd that we're ensuring it here, and then again %% it may seem odd that we're ensuring it here, and then again
%% as one of the last steps of the to_date process, but we need %% as one of the last steps of the to_date process, but we need
%% the actual name for the strings for the PHP "T" and "e", so %% the actual name for the strings for the PHP "T" and "e", so
%% we extract the Timezone in case ToTZ is actually a timezone key %% we extract the Timezone in case ToTZ is actually a timezone key
%% Then we can pass it on to to_date as well. That way we don't have %% Then we can pass it on to to_date as well. That way we don't have
%% to do it twice, since it's already ensured. %% to do it twice, since it's already ensured.
ActualToTZ = ensure_timezone(ToTZ), ActualToTZ = ensure_timezone(ToTZ),
to_string_worker(Format, ActualToTZ, to_date(Date,ActualToTZ)). to_string_worker(Format, ActualToTZ, to_date(Date,ActualToTZ)).
to_string_worker([], _, _) -> to_string_worker([], _, _) ->
""; "";
to_string_worker([$e|RestFormat], ToTZ, Date) -> to_string_worker([$e|RestFormat], ToTZ, Date) ->
ToTZ ++ to_string_worker(RestFormat, ToTZ, Date); ToTZ ++ to_string_worker(RestFormat, ToTZ, Date);
to_string_worker([$I|RestFormat], ToTZ, Date) -> to_string_worker([$I|RestFormat], ToTZ, Date) ->
I = case localtime_dst:check(Date, ToTZ) of I = case localtime_dst:check(Date, ToTZ) of
is_in_dst -> "1"; is_in_dst -> "1";
is_not_in_dst -> "0"; is_not_in_dst -> "0";
ambiguous_time -> "?" ambiguous_time -> "?"
end, end,
I ++ to_string_worker(RestFormat, ToTZ, Date); I ++ to_string_worker(RestFormat, ToTZ, Date);
to_string_worker([H | RestFormat], ToTZ, Date) when H==$O orelse H==$P -> to_string_worker([H | RestFormat], ToTZ, Date) when H==$O orelse H==$P ->
Shift = get_timezone_shift(Date, ToTZ), Shift = get_timezone_shift(Date, ToTZ),
Separator = case H of Separator = case H of
$O -> ""; $O -> "";
$P -> ":" $P -> ":"
end, end,
format_shift(Shift,Separator) ++ to_string_worker(RestFormat, ToTZ, Date); format_shift(Shift,Separator) ++ to_string_worker(RestFormat, ToTZ, Date);
to_string_worker([$T | RestFormat], ToTZ, Date) -> to_string_worker([$T | RestFormat], ToTZ, Date) ->
{ShortName,_} = localtime:tz_name(Date, ToTZ), {ShortName,_} = localtime:tz_name(Date, ToTZ),
ShortName ++ to_string_worker(RestFormat, ToTZ, Date); ShortName ++ to_string_worker(RestFormat, ToTZ, Date);
to_string_worker([$Z | RestFormat], ToTZ, Date) -> to_string_worker([$Z | RestFormat], ToTZ, Date) ->
{Sign, Hours, Mins} = get_timezone_shift(Date, ToTZ), {Sign, Hours, Mins} = get_timezone_shift(Date, ToTZ),
Seconds = (Hours * 3600) + (Mins * 60), Seconds = (Hours * 3600) + (Mins * 60),
atom_to_list(Sign) ++ integer_to_list(Seconds) ++ to_string_worker(RestFormat, ToTZ, Date); atom_to_list(Sign) ++ integer_to_list(Seconds) ++ to_string_worker(RestFormat, ToTZ, Date);
to_string_worker([$r | RestFormat], ToTZ, Date) -> to_string_worker([$r | RestFormat], ToTZ, Date) ->
NewFormat = "D, d M Y H:i:s O", NewFormat = "D, d M Y H:i:s O",
to_string_worker(NewFormat, ToTZ, Date) ++ to_string_worker(RestFormat, ToTZ, Date); to_string_worker(NewFormat, ToTZ, Date) ++ to_string_worker(RestFormat, ToTZ, Date);
to_string_worker([$c | RestFormat], ToTZ, Date) -> to_string_worker([$c | RestFormat], ToTZ, Date) ->
Format1 = "Y-m-d", Format1 = "Y-m-d",
Format2 = "H:i:sP", Format2 = "H:i:sP",
to_string_worker(Format1, ToTZ, Date) to_string_worker(Format1, ToTZ, Date)
++ "T" ++ "T"
++ to_string_worker(Format2, ToTZ, Date) ++ to_string_worker(Format2, ToTZ, Date)
++ to_string_worker(RestFormat, ToTZ, Date); ++ to_string_worker(RestFormat, ToTZ, Date);
to_string_worker([H | RestFormat], ToTZ, Date) -> to_string_worker([H | RestFormat], ToTZ, Date) ->
ec_date:format([H], Date) ++ to_string_worker(RestFormat, ToTZ, Date). ec_date:format([H], Date) ++ to_string_worker(RestFormat, ToTZ, Date).
format_shift({Sign,Hours,Mins},Separator) -> format_shift({Sign,Hours,Mins},Separator) ->
SignStr = atom_to_list(Sign), SignStr = atom_to_list(Sign),
MinStr = leading_zero(Mins), MinStr = leading_zero(Mins),
HourStr = leading_zero(Hours), HourStr = leading_zero(Hours),
SignStr ++ HourStr ++ Separator ++ MinStr. SignStr ++ HourStr ++ Separator ++ MinStr.
leading_zero(I) when I < 10 -> leading_zero(I) when I < 10 ->
"0" ++ integer_to_list(I); "0" ++ integer_to_list(I);
leading_zero(I) -> leading_zero(I) ->
integer_to_list(I). integer_to_list(I).
get_timezone_shift(Date, TZ) -> get_timezone_shift(Date, TZ) ->
case localtime:tz_shift(Date, TZ) of case localtime:tz_shift(Date, TZ) of
unable_to_detect -> {error,unable_to_detect}; unable_to_detect -> {error,unable_to_detect};
{error,T} -> {error,T}; {error,T} -> {error,T};
{Sh, _DstSh} -> Sh; {Sh, _DstSh} -> Sh;
Sh -> Sh Sh -> Sh
end. end.
format(Format) -> format(Format) ->
to_string(Format). to_string(Format).
format(Format, Date) -> format(Format, Date) ->
to_string(Format, Date). to_string(Format, Date).
parse(String) -> parse(String) ->
to_date(String). to_date(String).
nparse(String) -> nparse(String) ->
to_now(String). to_now(String).
to_date(RawDate) -> to_date(RawDate) ->
to_date(RawDate, ?DETERMINE_TZ). to_date(RawDate, ?DETERMINE_TZ).
to_date(RawDate, ToTZ) when is_binary(RawDate) -> to_date(RawDate, ToTZ) when is_binary(RawDate) ->
to_date(binary_to_list(RawDate), ToTZ); to_date(binary_to_list(RawDate), ToTZ);
to_date(RawDate, ToTZ) -> to_date(RawDate, ToTZ) ->
{ExtractedDate, ExtractedTZ} = extract_timezone(RawDate), {ExtractedDate, ExtractedTZ} = extract_timezone(RawDate),
{RawDate3, FromTZ} = case try_registered_parsers(RawDate) of {RawDate3, FromTZ} = case try_registered_parsers(RawDate) of
undefined -> undefined ->
{ExtractedDate, ExtractedTZ}; {ExtractedDate, ExtractedTZ};
{ParsedDate,undefined} -> {ParsedDate,undefined} ->
{ParsedDate,ExtractedTZ}; {ParsedDate,ExtractedTZ};
{ParsedDate,ParsedTZ} -> {ParsedDate,ParsedTZ} ->
{ParsedDate,ParsedTZ} {ParsedDate,ParsedTZ}
end, end,
Date = raw_to_date(RawDate3), Date = raw_to_date(RawDate3),
date_tz_to_tz(Date, FromTZ, ToTZ). date_tz_to_tz(Date, FromTZ, ToTZ).
extract_timezone(Unixtime) when is_integer(Unixtime) -> extract_timezone(Unixtime) when is_integer(Unixtime) ->
{Unixtime, "GMT"}; {Unixtime, "GMT"};
extract_timezone(DateString) when is_list(DateString) -> extract_timezone(DateString) when is_list(DateString) ->
case extract_gmt_relative_timezone(DateString) of case extract_gmt_relative_timezone(DateString) of
undefined -> undefined ->
AllTimezones = localtime:list_timezones(), AllTimezones = localtime:list_timezones(),
RevDate = lists:reverse(DateString), RevDate = lists:reverse(DateString),
extract_timezone_helper(RevDate, AllTimezones); extract_timezone_helper(RevDate, AllTimezones);
{Date, GMTRel} -> {Date, GMTRel} ->
{Date, GMTRel} {Date, GMTRel}
end; end;
extract_timezone(Date={{_,_,_},{_,_,_}}) -> extract_timezone(Date={{_,_,_},{_,_,_}}) ->
{Date, ?DETERMINE_TZ}; {Date, ?DETERMINE_TZ};
extract_timezone(Now={_,_,_}) -> extract_timezone(Now={_,_,_}) ->
{Now, "GMT"}; {Now, "GMT"};
extract_timezone({MiscDate,TZ}) -> extract_timezone({MiscDate,TZ}) ->
{MiscDate,TZ}. {MiscDate,TZ}.
extract_gmt_relative_timezone(DateString) -> extract_gmt_relative_timezone(DateString) ->
RE = "^(.*?)(?:GMT|UTC)?([+-])(\\d{1,2}):?(\\d{2})?$", RE = "^(.*?)(?:GMT|UTC)?([+-])(\\d{1,2}):?(\\d{2})?$",
case re:run(DateString,RE,[{capture,all_but_first,list},caseless]) of case re:run(DateString,RE,[{capture,all_but_first,list},caseless]) of
{match, [NewDateStr, Sign, HourStr, MinStr]} -> {match, [NewDateStr, Sign, HourStr, MinStr]} ->
{NewDateStr, minutes_from_gmt_relative_timezone(Sign, HourStr, MinStr)}; {NewDateStr, minutes_from_gmt_relative_timezone(Sign, HourStr, MinStr)};
{match, [NewDateStr, Sign, HourStr]} -> {match, [NewDateStr, Sign, HourStr]} ->
{NewDateStr, minutes_from_gmt_relative_timezone(Sign, HourStr, "0")}; {NewDateStr, minutes_from_gmt_relative_timezone(Sign, HourStr, "0")};
nomatch -> nomatch ->
undefined undefined
end. end.
%% The number of minutes a the timezone is behind gmt %% The number of minutes a the timezone is behind gmt
minutes_from_gmt_relative_timezone("+", HourStr, MinStr) -> minutes_from_gmt_relative_timezone("+", HourStr, MinStr) ->
-minutes_from_gmt_relative_timezone("-", HourStr, MinStr); -minutes_from_gmt_relative_timezone("-", HourStr, MinStr);
minutes_from_gmt_relative_timezone("-", HourStr, MinStr) -> minutes_from_gmt_relative_timezone("-", HourStr, MinStr) ->
list_to_integer(HourStr)*60 + list_to_integer(MinStr). list_to_integer(HourStr)*60 + list_to_integer(MinStr).
extract_timezone_helper(RevDate, []) -> extract_timezone_helper(RevDate, []) ->
{lists:reverse(RevDate), ?DETERMINE_TZ}; {lists:reverse(RevDate), ?DETERMINE_TZ};
extract_timezone_helper(RevDate, [TZ | TZs]) -> extract_timezone_helper(RevDate, [TZ | TZs]) ->
RevTZ = lists:reverse(TZ), RevTZ = lists:reverse(TZ),
case lists:split(length(TZ),RevDate) of case lists:split(length(TZ),RevDate) of
{RevTZ," " ++ Remainder} -> {RevTZ," " ++ Remainder} ->
{lists:reverse(Remainder), TZ}; {lists:reverse(Remainder), TZ};
_ -> _ ->
extract_timezone_helper(RevDate, TZs) extract_timezone_helper(RevDate, TZs)
end. end.
determine_timezone() -> determine_timezone() ->
case qdate_srv:get_timezone() of case qdate_srv:get_timezone() of
undefined -> ?DEFAULT_TZ; undefined -> ?DEFAULT_TZ;
TZ -> TZ TZ -> TZ
end. end.
%% This converts dates without regard to timezone. %% This converts dates without regard to timezone.
%% Unixtime just goes to UTC %% Unixtime just goes to UTC
raw_to_date(Unixtime) when is_integer(Unixtime) -> raw_to_date(Unixtime) when is_integer(Unixtime) ->
unixtime_to_date(Unixtime); unixtime_to_date(Unixtime);
raw_to_date(DateString) when is_list(DateString) -> raw_to_date(DateString) when is_list(DateString) ->
ec_date:parse(DateString); ec_date:parse(DateString);
raw_to_date(Now = {_,_,_}) -> raw_to_date(Now = {_,_,_}) ->
calendar:now_to_datetime(Now); calendar:now_to_datetime(Now);
raw_to_date(Date = {{_,_,_},{_,_,_}}) -> raw_to_date(Date = {{_,_,_},{_,_,_}}) ->
Date. Date.
%% If FromTZ is an integer, then it's an integer that represents the number of minutes %% If FromTZ is an integer, then it's an integer that represents the number of minutes
%% relative to GMT. So we convert the date to GMT based on that number, then we can %% relative to GMT. So we convert the date to GMT based on that number, then we can
%% do the other timezone conversion. %% do the other timezone conversion.
date_tz_to_tz(Date, FromTZ, ToTZ) when is_integer(FromTZ) -> date_tz_to_tz(Date, FromTZ, ToTZ) when is_integer(FromTZ) ->
NewDate = localtime:adjust_datetime(Date, FromTZ), NewDate = localtime:adjust_datetime(Date, FromTZ),
date_tz_to_tz(NewDate, "GMT", ToTZ); date_tz_to_tz(NewDate, "GMT", ToTZ);
date_tz_to_tz(Date, FromTZ, ToTZ) -> date_tz_to_tz(Date, FromTZ, ToTZ) ->
ActualToTZ = ensure_timezone(ToTZ), ActualToTZ = ensure_timezone(ToTZ),
localtime:local_to_local(Date,FromTZ,ActualToTZ). localtime:local_to_local(Date,FromTZ,ActualToTZ).
try_registered_parsers(RawDate) -> try_registered_parsers(RawDate) ->
Parsers = qdate_srv:get_parsers(), Parsers = qdate_srv:get_parsers(),
try_parsers(RawDate,Parsers). try_parsers(RawDate,Parsers).
try_parsers(_RawDate,[]) -> try_parsers(_RawDate,[]) ->
undefined; undefined;
try_parsers(RawDate,[{ParserKey,Parser}|Parsers]) -> try_parsers(RawDate,[{ParserKey,Parser}|Parsers]) ->
try Parser(RawDate) of try Parser(RawDate) of
{{_,_,_},{_,_,_}} = DateTime -> {{_,_,_},{_,_,_}} = DateTime ->
{DateTime,undefined}; {DateTime,undefined};
{DateTime={{_,_,_},{_,_,_}},Timezone} -> {DateTime={{_,_,_},{_,_,_}},Timezone} ->
{DateTime,Timezone}; {DateTime,Timezone};
undefined -> undefined ->
try_parsers(RawDate, Parsers); try_parsers(RawDate, Parsers);
Other -> Other ->
throw({invalid_parser_return_value,[{parser_key,ParserKey},{return,Other}]}) throw({invalid_parser_return_value,[{parser_key,ParserKey},{return,Other}]})
catch catch
Error:Reason -> Error:Reason ->
throw({error_in_parser,[{error,{Error,Reason}},{parser_key,ParserKey}]}) throw({error_in_parser,[{error,{Error,Reason}},{parser_key,ParserKey}]})
end. end.
set_timezone(TZ) -> set_timezone(TZ) ->
qdate_srv:set_timezone(TZ). qdate_srv:set_timezone(TZ).
set_timezone(Key,TZ) -> set_timezone(Key,TZ) ->
qdate_srv:set_timezone(Key, TZ). qdate_srv:set_timezone(Key, TZ).
get_timezone() -> get_timezone() ->
qdate_srv:get_timezone(). qdate_srv:get_timezone().
get_timezone(Key) -> get_timezone(Key) ->
qdate_srv:get_timezone(Key). qdate_srv:get_timezone(Key).
ensure_timezone(Key) when is_atom(Key) orelse is_tuple(Key) -> ensure_timezone(Key) when is_atom(Key) orelse is_tuple(Key) ->
case get_timezone(Key) of case get_timezone(Key) of
undefined -> throw({timezone_key_not_found,Key}); undefined -> throw({timezone_key_not_found,Key});
ToTZ -> ToTZ ToTZ -> ToTZ
end; end;
ensure_timezone(TZ) when is_binary(TZ) -> ensure_timezone(TZ) when is_binary(TZ) ->
binary_to_list(TZ); binary_to_list(TZ);
ensure_timezone(TZ) when is_list(TZ) -> ensure_timezone(TZ) when is_list(TZ) ->
TZ. TZ.
clear_timezone() -> clear_timezone() ->
qdate_srv:clear_timezone(). qdate_srv:clear_timezone().
clear_timezone(Key) -> clear_timezone(Key) ->
qdate_srv:clear_timezone(Key). qdate_srv:clear_timezone(Key).
to_unixtime(Unixtime) when is_integer(Unixtime) -> to_unixtime(Unixtime) when is_integer(Unixtime) ->
Unixtime; Unixtime;
to_unixtime({MegaSecs,Secs,_}) -> to_unixtime({MegaSecs,Secs,_}) ->
MegaSecs*1000000 + Secs; MegaSecs*1000000 + Secs;
to_unixtime(ToParse) -> to_unixtime(ToParse) ->
%% We want to treat all unixtimes as GMT %% We want to treat all unixtimes as GMT
Date = to_date(ToParse, "GMT"), Date = to_date(ToParse, "GMT"),
calendar:datetime_to_gregorian_seconds(Date) - ?UNIXTIME_BASE. calendar:datetime_to_gregorian_seconds(Date) - ?UNIXTIME_BASE.
unixtime() -> unixtime() ->
to_unixtime(now()). to_unixtime(now()).
to_now(Now = {_,_,_}) -> to_now(Now = {_,_,_}) ->
Now; Now;
to_now(ToParse) -> to_now(ToParse) ->
Unixtime = to_unixtime(ToParse), Unixtime = to_unixtime(ToParse),
unixtime_to_now(Unixtime). unixtime_to_now(Unixtime).
register_parser(Key, Parser) when is_function(Parser,1) -> register_parser(Key, Parser) when is_function(Parser,1) ->
qdate_srv:register_parser(Key,Parser). qdate_srv:register_parser(Key,Parser).
register_parser(Parser) when is_function(Parser,1) -> register_parser(Parser) when is_function(Parser,1) ->
qdate_srv:register_parser(Parser). qdate_srv:register_parser(Parser).
deregister_parser(Key) -> deregister_parser(Key) ->
qdate_srv:deregister_parser(Key). qdate_srv:deregister_parser(Key).
deregister_parsers() -> deregister_parsers() ->
qdate_srv:deregister_parsers(). qdate_srv:deregister_parsers().
register_format(Key, Format) -> register_format(Key, Format) ->
qdate_srv:register_format(Key, Format). qdate_srv:register_format(Key, Format).
deregister_format(Key) -> deregister_format(Key) ->
qdate_srv:deregister_format(Key). qdate_srv:deregister_format(Key).
unixtime_to_now(T) when is_integer(T) -> unixtime_to_now(T) when is_integer(T) ->
MegaSec = floor(T/1000000), MegaSec = floor(T/1000000),
Secs = T - MegaSec*1000000, Secs = T - MegaSec*1000000,
{MegaSec,Secs,0}. {MegaSec,Secs,0}.
unixtime_to_date(T) -> unixtime_to_date(T) ->
Now = unixtime_to_now(T), Now = unixtime_to_now(T),
calendar:now_to_datetime(Now). calendar:now_to_datetime(Now).
floor(N) when N >= 0 -> floor(N) when N >= 0 ->
trunc(N); trunc(N);
floor(N) when N < 0 -> floor(N) when N < 0 ->
Int = trunc(N), Int = trunc(N),
if if
Int==N -> Int; Int==N -> Int;
true -> Int-1 true -> Int-1
end. end.
%% TESTS %% TESTS
@ -364,169 +368,169 @@ floor(N) when N < 0 ->
-define(USER_KEY,test_user_key). -define(USER_KEY,test_user_key).
tz_test_() -> tz_test_() ->
{ {
setup, setup,
fun start_test/0, fun start_test/0,
fun stop_test/1, fun stop_test/1,
fun(SetupData) -> fun(SetupData) ->
{inorder,[ {inorder,[
simple_test(SetupData), simple_test(SetupData),
tz_tests(SetupData), tz_tests(SetupData),
test_process_die(SetupData), test_process_die(SetupData),
parser_format_test(SetupData) parser_format_test(SetupData)
]} ]}
end end
}. }.
tz_tests(_) -> tz_tests(_) ->
{inorder,[ {inorder,[
?_assertEqual(ok,set_timezone(?SELF_TZ)), ?_assertEqual(ok,set_timezone(?SELF_TZ)),
?_assertEqual(?SELF_TZ,get_timezone()), ?_assertEqual(?SELF_TZ,get_timezone()),
?_assertEqual(?USER_TZ,get_timezone(?USER_KEY)), ?_assertEqual(?USER_TZ,get_timezone(?USER_KEY)),
?_assertEqual(?SITE_TZ,get_timezone(?SITE_KEY)), ?_assertEqual(?SITE_TZ,get_timezone(?SITE_KEY)),
?_assertEqual({{2013,3,7},{0,0,0}}, to_date("3/7/2013 1:00am EST",?USER_KEY)), ?_assertEqual({{2013,3,7},{0,0,0}}, to_date("3/7/2013 1:00am EST",?USER_KEY)),
?_assertEqual({{2013,3,7},{0,0,0}}, to_date("3/7/2013 3:00am EST",?SITE_KEY)), ?_assertEqual({{2013,3,7},{0,0,0}}, to_date("3/7/2013 3:00am EST",?SITE_KEY)),
?_assertEqual({{2013,3,7},{2,0,0}}, to_date("3/7/2013 1:00am CST")), %% will use the current pid's setting ?_assertEqual({{2013,3,7},{2,0,0}}, to_date("3/7/2013 1:00am CST")), %% will use the current pid's setting
?_assertEqual("America/Chicago",to_string("e","America/Chicago","3/7/2013 1:00am")), ?_assertEqual("America/Chicago",to_string("e","America/Chicago","3/7/2013 1:00am")),
?_assertEqual("-0500",to_string("O","EST","3/7/2013 1:00am CST")), ?_assertEqual("-0500",to_string("O","EST","3/7/2013 1:00am CST")),
?_assertEqual("-05:00",to_string("P","EST","3/7/2013 1:00am CST")), ?_assertEqual("-05:00",to_string("P","EST","3/7/2013 1:00am CST")),
?_assertEqual("EST",to_string("T","America/New York","3/7/2013 1:00am CST")), ?_assertEqual("EST",to_string("T","America/New York","3/7/2013 1:00am CST")),
?_assertEqual(?SITE_TZ,to_string("T",?SITE_KEY,"3/7/2013 1:00am CST")), ?_assertEqual(?SITE_TZ,to_string("T",?SITE_KEY,"3/7/2013 1:00am CST")),
?_assertEqual(integer_to_list(-5 * 3600), to_string("Z","EST","3/7/2013 1:00am CST")), ?_assertEqual(integer_to_list(-5 * 3600), to_string("Z","EST","3/7/2013 1:00am CST")),
?_assertEqual("Thu, 07 Mar 2013 13:15:00 -0500", to_string("r","EST", "3/7/2013 1:15:00pm")), ?_assertEqual("Thu, 07 Mar 2013 13:15:00 -0500", to_string("r","EST", "3/7/2013 1:15:00pm")),
?_assertEqual("2013-03-07T13:15:00-05:00", to_string("c", "EST", "3/7/2013 1:15:00pm")), ?_assertEqual("2013-03-07T13:15:00-05:00", to_string("c", "EST", "3/7/2013 1:15:00pm")),
?_assertEqual({{2013,3,7},{6,0,0}}, to_date("3/7/2013 12:00am -0600","GMT")), ?_assertEqual({{2013,3,7},{6,0,0}}, to_date("3/7/2013 12:00am -0600","GMT")),
?_assertEqual({{2013,3,7},{6,0,0}}, to_date("3/7/2013 12:00am -600","GMT")), ?_assertEqual({{2013,3,7},{6,0,0}}, to_date("3/7/2013 12:00am -600","GMT")),
?_assertEqual({{2013,3,7},{6,0,0}}, to_date("3/7/2013 12:00am GMT-0600","GMT")), ?_assertEqual({{2013,3,7},{6,0,0}}, to_date("3/7/2013 12:00am GMT-0600","GMT")),
?_assertEqual({{2013,3,7},{6,0,0}}, to_date("3/7/2013 12:00am utc-0600","GMT")), ?_assertEqual({{2013,3,7},{6,0,0}}, to_date("3/7/2013 12:00am utc-0600","GMT")),
?_assertEqual({{2013,3,7},{1,0,0}}, to_date("3/7/2013 12:00am utc-0600","EST")), ?_assertEqual({{2013,3,7},{1,0,0}}, to_date("3/7/2013 12:00am utc-0600","EST")),
?_assertEqual({{2013,3,6},{18,0,0}}, to_date("3/7/2013 12:00am +0600","GMT")), ?_assertEqual({{2013,3,6},{18,0,0}}, to_date("3/7/2013 12:00am +0600","GMT")),
?_assertEqual({{2013,3,6},{12,0,0}}, to_date("3/7/2013 12:00am +0600","CST")), ?_assertEqual({{2013,3,6},{12,0,0}}, to_date("3/7/2013 12:00am +0600","CST")),
%% parsing, then reformatting the same time with a different timezone using the php "r" (rfc2822) %% parsing, then reformatting the same time with a different timezone using the php "r" (rfc2822)
?_assertEqual("Thu, 07 Mar 2013 12:15:00 -0600", ?_assertEqual("Thu, 07 Mar 2013 12:15:00 -0600",
to_string("r","CST",to_string("r","EST",{{2013,3,7},{13,15,0}}))), to_string("r","CST",to_string("r","EST",{{2013,3,7},{13,15,0}}))),
%% A bunch of unixtime and now tests with timezones %% A bunch of unixtime and now tests with timezones
?_assertEqual("1987-08-10 00:59:15 GMT",to_string("Y-m-d H:i:s T","GMT",555555555)), ?_assertEqual("1987-08-10 00:59:15 GMT",to_string("Y-m-d H:i:s T","GMT",555555555)),
?_assertEqual("1987-08-09 19:59:15 CDT",to_string("Y-m-d H:i:s T","CDT",555555555)), ?_assertEqual("1987-08-09 19:59:15 CDT",to_string("Y-m-d H:i:s T","CDT",555555555)),
?_assertEqual("1987-08-09 20:59:15 EDT",to_string("Y-m-d H:i:s T","America/New York",555555555)), ?_assertEqual("1987-08-09 20:59:15 EDT",to_string("Y-m-d H:i:s T","America/New York",555555555)),
?_assertEqual(ok, set_timezone("GMT")), ?_assertEqual(ok, set_timezone("GMT")),
?_assertEqual(555555555,to_unixtime("1987-08-10 00:59:15 GMT")), ?_assertEqual(555555555,to_unixtime("1987-08-10 00:59:15 GMT")),
?_assertEqual({555,555555,0},to_now("1987-08-10 00:59:15 GMT")), ?_assertEqual({555,555555,0},to_now("1987-08-10 00:59:15 GMT")),
?_assertEqual(ok, set_timezone("EST")), ?_assertEqual(ok, set_timezone("EST")),
?_assertEqual(555555555,to_unixtime("1987-08-10 00:59:15 GMT")), ?_assertEqual(555555555,to_unixtime("1987-08-10 00:59:15 GMT")),
?_assertEqual({555,555555,0},to_now("1987-08-10 00:59:15 GMT")), ?_assertEqual({555,555555,0},to_now("1987-08-10 00:59:15 GMT")),
?_assertEqual(ok, set_timezone("GMT")) ?_assertEqual(ok, set_timezone("GMT"))
]}. ]}.
simple_test(_) -> simple_test(_) ->
{inorder,[ {inorder,[
?_assertEqual(ok,clear_timezone()), ?_assertEqual(ok,clear_timezone()),
?_assertEqual(0,to_unixtime({0,0,0})), ?_assertEqual(0,to_unixtime({0,0,0})),
?_assertEqual({0,0,0},to_now(0)), ?_assertEqual({0,0,0},to_now(0)),
?_assertEqual(0,to_unixtime("1970-01-01 12:00am GMT")), ?_assertEqual(0,to_unixtime("1970-01-01 12:00am GMT")),
?_assertEqual(21600,to_unixtime("1970-01-01 12:00am CST")), ?_assertEqual(21600,to_unixtime("1970-01-01 12:00am CST")),
?_assertEqual(0,to_unixtime({{1970,1,1},{0,0,0}})), ?_assertEqual(0,to_unixtime({{1970,1,1},{0,0,0}})),
?_assertEqual({{1970,1,1},{0,0,0}},to_date(0)), ?_assertEqual({{1970,1,1},{0,0,0}},to_date(0)),
?_assertEqual({{2013,3,7},{0,0,0}},to_date(to_unixtime("2013-03-07 12am"))), ?_assertEqual({{2013,3,7},{0,0,0}},to_date(to_unixtime("2013-03-07 12am"))),
?_assertEqual("2013-12-21 12:24pm",to_string("Y-m-d g:ia",{{2013,12,21},{12,24,21}})), ?_assertEqual("2013-12-21 12:24pm",to_string("Y-m-d g:ia",{{2013,12,21},{12,24,21}})),
?_assertEqual("2012-12-01 1:00pm", to_string("Y-m-d g:ia","EST","2012-12-01 12:00pm CST")), ?_assertEqual("2012-12-01 1:00pm", to_string("Y-m-d g:ia","EST","2012-12-01 12:00pm CST")),
?_assertEqual(<<"2012-12-01 1:00pm">>, to_string(<<"Y-m-d g:ia">>,"EST","2012-12-01 12:00pm CST")), ?_assertEqual(<<"2012-12-01 1:00pm">>, to_string(<<"Y-m-d g:ia">>,"EST","2012-12-01 12:00pm CST")),
?_assertEqual(<<"2012-12-01 1:00pm">>, to_string(<<"Y-m-d g:ia">>,"EST",<<"2012-12-01 12:00pm CST">>)), ?_assertEqual(<<"2012-12-01 1:00pm">>, to_string(<<"Y-m-d g:ia">>,"EST",<<"2012-12-01 12:00pm CST">>)),
?_assertEqual("2012-12-01 1:00pm", to_string("Y-m-d g:ia","EST",<<"2012-12-01 12:00pm CST">>)), ?_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(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({{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")) ?_assertEqual({{2013,1,1},{0,15,15}},to_date("December 31, 2012 6:15:15pm CST","GMT"))
]}. ]}.
parser_format_test(_) -> parser_format_test(_) ->
{inorder,[ {inorder,[
?_assertEqual({{2008,2,8},{0,0,0}},to_date("20080208")), ?_assertEqual({{2008,2,8},{0,0,0}},to_date("20080208")),
?_assertThrow({ec_date,{bad_date,_}},to_date("20111232")), %% invalid_date with custom format ?_assertThrow({ec_date,{bad_date,_}},to_date("20111232")), %% invalid_date with custom format
?_assertEqual("2/8/2008",to_string(shortdate,{{2008,2,8},{0,0,0}})), ?_assertEqual("2/8/2008",to_string(shortdate,{{2008,2,8},{0,0,0}})),
?_assertEqual("2/8/2008",to_string(shortdate,"20080208")), %% both regged format and parser ?_assertEqual("2/8/2008",to_string(shortdate,"20080208")), %% both regged format and parser
?_assertEqual("2/8/2008 12:00am",to_string(longdate,"2008-02-08 12:00am")), ?_assertEqual("2/8/2008 12:00am",to_string(longdate,"2008-02-08 12:00am")),
?_assertEqual("2/8/2008 12:00am",to_string(longdate,"20080208")) ?_assertEqual("2/8/2008 12:00am",to_string(longdate,"20080208"))
]}. ]}.
test_process_die(_) -> test_process_die(_) ->
TZ = "MST", TZ = "MST",
Caller = self(), Caller = self(),
Pid = spawn(fun() -> Pid = spawn(fun() ->
set_timezone(TZ), set_timezone(TZ),
Caller ! tz_set, Caller ! tz_set,
receive tz_set_ack -> ok end, receive tz_set_ack -> ok end,
Caller ! get_timezone() Caller ! get_timezone()
end), end),
PidTZFromOtherProc = receive PidTZFromOtherProc = receive
tz_set -> tz_set ->
T = get_timezone(Pid), T = get_timezone(Pid),
Pid ! tz_set_ack, Pid ! tz_set_ack,
T T
after 1000 -> fail after 1000 -> fail
end, end,
ReceivedTZ = receive ReceivedTZ = receive
TZ -> TZ TZ -> TZ
after 2000 -> after 2000 ->
fail fail
end, end,
[ [
%% Verify we can read the spawned process's TZ from another proc %% Verify we can read the spawned process's TZ from another proc
?_assertEqual(TZ,PidTZFromOtherProc), ?_assertEqual(TZ,PidTZFromOtherProc),
%% Verify the spawned process properly set the TZ %% Verify the spawned process properly set the TZ
?_assertEqual(TZ,ReceivedTZ), ?_assertEqual(TZ,ReceivedTZ),
%% Verify the now-dead spawned process's TZ is cleared %% Verify the now-dead spawned process's TZ is cleared
?_assertEqual(undefined,get_timezone(Pid)) ?_assertEqual(undefined,get_timezone(Pid))
]. ].
start_test() -> start_test() ->
application:start(qdate), application:start(qdate),
set_timezone(?SELF_TZ), set_timezone(?SELF_TZ),
set_timezone(?SITE_KEY,?SITE_TZ), set_timezone(?SITE_KEY,?SITE_TZ),
set_timezone(?USER_KEY,?USER_TZ), set_timezone(?USER_KEY,?USER_TZ),
register_parser(compressed,fun compressed_parser/1), register_parser(compressed,fun compressed_parser/1),
register_parser(microsoft_date,fun microsoft_parser/1), register_parser(microsoft_date,fun microsoft_parser/1),
register_format(shortdate,"n/j/Y"), register_format(shortdate,"n/j/Y"),
register_format(longdate,"n/j/Y g:ia"). register_format(longdate,"n/j/Y g:ia").
compressed_parser(List) when length(List)==8 -> compressed_parser(List) when length(List)==8 ->
try re:run(List,"^(\\d{4})(\\d{2})(\\d{2})$",[{capture,all_but_first,list}]) of try re:run(List,"^(\\d{4})(\\d{2})(\\d{2})$",[{capture,all_but_first,list}]) of
nomatch -> undefined; nomatch -> undefined;
{match, [Y,M,D]} -> {match, [Y,M,D]} ->
Date = {list_to_integer(Y),list_to_integer(M),list_to_integer(D)}, Date = {list_to_integer(Y),list_to_integer(M),list_to_integer(D)},
case calendar:valid_date(Date) of case calendar:valid_date(Date) of
true -> true ->
{Date,{0,0,0}}; {Date,{0,0,0}};
false -> undefined false -> undefined
end end
catch catch
_:_ -> undefined _:_ -> undefined
end; end;
compressed_parser(_) -> compressed_parser(_) ->
undefined. undefined.
microsoft_parser(FloatDate) when is_float(FloatDate) -> microsoft_parser(FloatDate) when is_float(FloatDate) ->
try try
DaysSince1900 = floor(FloatDate), DaysSince1900 = floor(FloatDate),
Days0to1900 = calendar:date_to_gregorian_days(1900,1,1), Days0to1900 = calendar:date_to_gregorian_days(1900,1,1),
GregorianDays = Days0to1900 + DaysSince1900, GregorianDays = Days0to1900 + DaysSince1900,
Date = calendar:gregorian_days_to_date(GregorianDays), Date = calendar:gregorian_days_to_date(GregorianDays),
Seconds = round(86400 * (FloatDate - DaysSince1900)), Seconds = round(86400 * (FloatDate - DaysSince1900)),
Time = calendar:seconds_to_time(Seconds), Time = calendar:seconds_to_time(Seconds),
{Date,Time} {Date,Time}
catch catch
_:_ -> undefined _:_ -> undefined
end; end;
microsoft_parser(_) -> microsoft_parser(_) ->
undefined. undefined.
stop_test(_) -> stop_test(_) ->
ok. ok.

View file

@ -1,3 +1,7 @@
% vim: ts=4 sw=4 et
% Copyright (c) 2013 Jesse Gumm
% See LICENSE for licensing information.
-module(qdate_app). -module(qdate_app).
-behaviour(application). -behaviour(application).

View file

@ -1,161 +1,165 @@
% vim: ts=4 sw=4 et
% Copyright (c) 2013 Jesse Gumm
% See LICENSE for licensing information.
-module(qdate_srv). -module(qdate_srv).
-behaviour(gen_server). -behaviour(gen_server).
-define(SRV, ?MODULE). -define(SRV, ?MODULE).
-export([ -export([
start_link/0, start_link/0,
init/1, init/1,
handle_call/3, handle_call/3,
handle_cast/2, handle_cast/2,
handle_info/2, handle_info/2,
code_change/3, code_change/3,
terminate/2 terminate/2
]). ]).
-export([ -export([
set_timezone/1, set_timezone/1,
set_timezone/2, set_timezone/2,
get_timezone/0, get_timezone/0,
get_timezone/1, get_timezone/1,
clear_timezone/0, clear_timezone/0,
clear_timezone/1, clear_timezone/1,
register_parser/1, register_parser/1,
register_parser/2, register_parser/2,
get_parsers/0, get_parsers/0,
deregister_parsers/0, deregister_parsers/0,
deregister_parser/1, deregister_parser/1,
register_format/2, register_format/2,
get_format/1, get_format/1,
deregister_format/1 deregister_format/1
]). ]).
%% PUBLIC API FUNCTIONS %% PUBLIC API FUNCTIONS
start_link() -> start_link() ->
gen_server:start_link({local, ?SRV}, ?MODULE, [], []). gen_server:start_link({local, ?SRV}, ?MODULE, [], []).
set_timezone(TZ) -> set_timezone(TZ) ->
set_timezone(self(),TZ). set_timezone(self(),TZ).
set_timezone(Key,TZ) -> set_timezone(Key,TZ) ->
ok = gen_server:call(?SRV,{set_timezone,Key,TZ}). ok = gen_server:call(?SRV,{set_timezone,Key,TZ}).
get_timezone() -> get_timezone() ->
get_timezone(self()). get_timezone(self()).
get_timezone(Key) -> get_timezone(Key) ->
gen_server:call(?SRV,{get_timezone,Key}). gen_server:call(?SRV,{get_timezone,Key}).
clear_timezone() -> clear_timezone() ->
clear_timezone(self()). clear_timezone(self()).
clear_timezone(Key) -> clear_timezone(Key) ->
ok = gen_server:call(?SRV, {clear_timezone, Key}). ok = gen_server:call(?SRV, {clear_timezone, Key}).
register_parser(Parser) when is_function(Parser,1) -> register_parser(Parser) when is_function(Parser,1) ->
register_parser(erlang:make_ref(),Parser). register_parser(erlang:make_ref(),Parser).
register_parser(Key,Parser) when is_function(Parser,1) -> register_parser(Key,Parser) when is_function(Parser,1) ->
Key = gen_server:call(?SRV,{register_parser,Key,Parser}). Key = gen_server:call(?SRV,{register_parser,Key,Parser}).
deregister_parser(Key) -> deregister_parser(Key) ->
ok = gen_server:call(?SRV,{deregister_parser,Key}). ok = gen_server:call(?SRV,{deregister_parser,Key}).
deregister_parsers() -> deregister_parsers() ->
ok = gen_server:call(?SRV,{deregister_parsers}). ok = gen_server:call(?SRV,{deregister_parsers}).
get_parsers() -> get_parsers() ->
gen_server:call(?SRV,{get_parsers}). gen_server:call(?SRV,{get_parsers}).
register_format(Key,Format) -> register_format(Key,Format) ->
ok = gen_server:call(?SRV,{register_format,Key,Format}). ok = gen_server:call(?SRV,{register_format,Key,Format}).
get_format(Key) -> get_format(Key) ->
gen_server:call(?SRV,{get_format,Key}). gen_server:call(?SRV,{get_format,Key}).
deregister_format(Key) -> deregister_format(Key) ->
ok = gen_server:call(?SRV,{deregister_format,Key}). ok = gen_server:call(?SRV,{deregister_format,Key}).
%% SERVER FUNCTIONS %% SERVER FUNCTIONS
-record(state, {tz, parsers, formats}). -record(state, {tz, parsers, formats}).
init(_) -> init(_) ->
State = #state{tz=dict:new(),parsers=dict:new(),formats=dict:new()}, State = #state{tz=dict:new(),parsers=dict:new(),formats=dict:new()},
{ok, State}. {ok, State}.
handle_cast(_,State) -> handle_cast(_,State) ->
{noreply, State}. {noreply, State}.
handle_info({'DOWN', MonitorRef, process, Pid, _Reason}, State) -> handle_info({'DOWN', MonitorRef, process, Pid, _Reason}, State) ->
erlang:demonitor(MonitorRef), erlang:demonitor(MonitorRef),
NewTZ = dict:erase(Pid, State#state.tz), NewTZ = dict:erase(Pid, State#state.tz),
NewParsers = dict:erase(Pid, State#state.parsers), NewParsers = dict:erase(Pid, State#state.parsers),
NewFormats = dict:erase(Pid, State#state.formats), NewFormats = dict:erase(Pid, State#state.formats),
NewState = State#state{tz=NewTZ, parsers=NewParsers, formats=NewFormats}, NewState = State#state{tz=NewTZ, parsers=NewParsers, formats=NewFormats},
{noreply, NewState }; {noreply, NewState };
handle_info(_, State) -> handle_info(_, State) ->
{noreply, State}. {noreply, State}.
handle_call({set_timezone,Key,TZ}, _From, State) -> handle_call({set_timezone,Key,TZ}, _From, State) ->
monitor_if_pid(Key), monitor_if_pid(Key),
NewTZ = dict:store(Key, TZ, State#state.tz), NewTZ = dict:store(Key, TZ, State#state.tz),
NewState = State#state{tz=NewTZ}, NewState = State#state{tz=NewTZ},
{reply, ok, NewState}; {reply, ok, NewState};
handle_call({clear_timezone,Key},_From, State) -> handle_call({clear_timezone,Key},_From, State) ->
NewTZ = dict:erase(Key, State#state.tz), NewTZ = dict:erase(Key, State#state.tz),
NewState = State#state{tz=NewTZ}, NewState = State#state{tz=NewTZ},
{reply, ok, NewState}; {reply, ok, NewState};
handle_call({get_timezone,Key},_From, State) -> handle_call({get_timezone,Key},_From, State) ->
Reply = case dict:find(Key, State#state.tz) of Reply = case dict:find(Key, State#state.tz) of
error -> undefined; error -> undefined;
{ok,TZ} -> TZ {ok,TZ} -> TZ
end, end,
{reply, Reply, State}; {reply, Reply, State};
handle_call({register_parser,Key,Parser},_From,State) -> handle_call({register_parser,Key,Parser},_From,State) ->
NewParsers = dict:store(Key, Parser, State#state.parsers), NewParsers = dict:store(Key, Parser, State#state.parsers),
NewState = State#state{parsers=NewParsers}, NewState = State#state{parsers=NewParsers},
{reply, Key, NewState}; {reply, Key, NewState};
handle_call({get_parsers},_From,State) -> handle_call({get_parsers},_From,State) ->
Reply = dict:to_list(State#state.parsers), Reply = dict:to_list(State#state.parsers),
{reply, Reply, State}; {reply, Reply, State};
handle_call({deregister_parser,Key},_From,State) -> handle_call({deregister_parser,Key},_From,State) ->
NewParsers = dict:erase(Key, State#state.parsers), NewParsers = dict:erase(Key, State#state.parsers),
NewState = State#state{parsers=NewParsers}, NewState = State#state{parsers=NewParsers},
{reply, ok, NewState}; {reply, ok, NewState};
handle_call({deregister_parsers},_From,State) -> handle_call({deregister_parsers},_From,State) ->
NewState = State#state{parsers=dict:new()}, NewState = State#state{parsers=dict:new()},
{reply, ok, NewState}; {reply, ok, NewState};
handle_call({register_format,Key,Format},_From,State) -> handle_call({register_format,Key,Format},_From,State) ->
NewFormats = dict:store(Key, Format, State#state.formats), NewFormats = dict:store(Key, Format, State#state.formats),
NewState = State#state{formats=NewFormats}, NewState = State#state{formats=NewFormats},
{reply, ok, NewState}; {reply, ok, NewState};
handle_call({get_format,Key},_From,State) -> handle_call({get_format,Key},_From,State) ->
Reply = case dict:find(Key, State#state.formats) of Reply = case dict:find(Key, State#state.formats) of
error -> undefined; error -> undefined;
{ok, Format} -> Format {ok, Format} -> Format
end, end,
{reply, Reply,State}; {reply, Reply,State};
handle_call({deregister_format,Key},_From,State) -> handle_call({deregister_format,Key},_From,State) ->
NewFormats = dict:erase(Key, State#state.formats), NewFormats = dict:erase(Key, State#state.formats),
NewState = State#state{formats=NewFormats}, NewState = State#state{formats=NewFormats},
{reply, ok, NewState}. {reply, ok, NewState}.
terminate(_Reason, _State) -> terminate(_Reason, _State) ->
ok. ok.
code_change(_OldVersion, State, _Extra) -> code_change(_OldVersion, State, _Extra) ->
{ok, State}. {ok, State}.
%% PRIVATE TOOLS %% PRIVATE TOOLS
monitor_if_pid(Key) when is_pid(Key) -> monitor_if_pid(Key) when is_pid(Key) ->
erlang:monitor(process,Key); erlang:monitor(process,Key);
monitor_if_pid(_) -> monitor_if_pid(_) ->
do_nothing. do_nothing.

View file

@ -1,3 +1,6 @@
% vim: ts=4 sw=4 et
% Copyright (c) 2013 Jesse Gumm
% See LICENSE for licensing information.
-module(qdate_sup). -module(qdate_sup).
@ -24,6 +27,6 @@ start_link() ->
%% =================================================================== %% ===================================================================
init([]) -> init([]) ->
Server = ?CHILD(qdate_srv, worker), Server = ?CHILD(qdate_srv, worker),
{ok, { {one_for_one, 5, 10}, [Server]} }. {ok, { {one_for_one, 5, 10}, [Server]} }.