Add License and copyright to each page. Retab
This commit is contained in:
parent
c7cd5b6800
commit
7c55a6e8bf
4 changed files with 440 additions and 425 deletions
684
src/qdate.erl
684
src/qdate.erl
|
@ -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.
|
||||||
|
|
|
@ -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).
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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]} }.
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue