Parsing and Formatting Server working with tests
This commit is contained in:
parent
a9d87c0a9e
commit
9a68dbd9d1
2 changed files with 189 additions and 37 deletions
135
src/qdate.erl
135
src/qdate.erl
|
@ -11,17 +11,15 @@
|
||||||
unixtime/0
|
unixtime/0
|
||||||
]).
|
]).
|
||||||
|
|
||||||
%% -export([
|
|
||||||
%% register_parser/2,
|
|
||||||
%% register_parser/1
|
|
||||||
%% ]).
|
|
||||||
%%
|
|
||||||
%% -export([
|
|
||||||
%% register_format/2,
|
|
||||||
%% register_format/1
|
|
||||||
%% ]).
|
|
||||||
%%
|
|
||||||
-export([
|
-export([
|
||||||
|
register_parser/2,
|
||||||
|
register_parser/1,
|
||||||
|
deregister_parser/1,
|
||||||
|
deregister_parsers/0,
|
||||||
|
|
||||||
|
register_format/2,
|
||||||
|
deregister_format/1,
|
||||||
|
|
||||||
set_timezone/1,
|
set_timezone/1,
|
||||||
set_timezone/2,
|
set_timezone/2,
|
||||||
get_timezone/0,
|
get_timezone/0,
|
||||||
|
@ -63,7 +61,15 @@ to_string(Format) ->
|
||||||
to_string(Format, Date) ->
|
to_string(Format, Date) ->
|
||||||
to_string(Format, ?DETERMINE_TZ, Date).
|
to_string(Format, ?DETERMINE_TZ, Date).
|
||||||
|
|
||||||
to_string(Format, ToTZ, Date) ->
|
to_string(FormatKey, ToTZ, Date) when is_atom(FormatKey) orelse is_tuple(FormatKey) ->
|
||||||
|
Format = case qdate_srv:get_format(FormatKey) of
|
||||||
|
undefined -> throw({undefined_format_key,FormatKey});
|
||||||
|
F -> F
|
||||||
|
end,
|
||||||
|
to_string(Format, ToTZ, Date);
|
||||||
|
to_string(Format, ToTZ, Date) when is_binary(Format) ->
|
||||||
|
list_to_binary(to_string(binary_to_list(Format), ToTZ, Date));
|
||||||
|
to_string(Format, ToTZ, Date) when is_list(Format) ->
|
||||||
ec_date:format(Format,to_date(Date,ToTZ)).
|
ec_date:format(Format,to_date(Date,ToTZ)).
|
||||||
|
|
||||||
format(Format) ->
|
format(Format) ->
|
||||||
|
@ -98,10 +104,39 @@ to_date(RawDate, ToTZKey) when is_atom(ToTZKey) orelse is_tuple(ToTZKey) ->
|
||||||
ToTZ -> to_date(RawDate, ToTZ)
|
ToTZ -> to_date(RawDate, ToTZ)
|
||||||
end;
|
end;
|
||||||
to_date(RawDate, ToTZ) ->
|
to_date(RawDate, ToTZ) ->
|
||||||
{RawDate2,FromTZ} = extract_timezone(RawDate),
|
{ExtractedDate, ExtractedTZ} = extract_timezone(RawDate),
|
||||||
Date = raw_to_date(RawDate2),
|
{RawDate3, FromTZ} = case try_registered_parsers(RawDate) of
|
||||||
|
undefined ->
|
||||||
|
{ExtractedDate, ExtractedTZ};
|
||||||
|
{ParsedDate,undefined} ->
|
||||||
|
{ParsedDate,ExtractedTZ};
|
||||||
|
{ParsedDate,ParsedTZ} ->
|
||||||
|
{ParsedDate,ParsedTZ}
|
||||||
|
end,
|
||||||
|
Date = raw_to_date(RawDate3),
|
||||||
localtime:local_to_local(Date,FromTZ,ToTZ).
|
localtime:local_to_local(Date,FromTZ,ToTZ).
|
||||||
|
|
||||||
|
try_registered_parsers(RawDate) ->
|
||||||
|
Parsers = qdate_srv:get_parsers(),
|
||||||
|
try_parsers(RawDate,Parsers).
|
||||||
|
|
||||||
|
try_parsers(_RawDate,[]) ->
|
||||||
|
undefined;
|
||||||
|
try_parsers(RawDate,[{ParserKey,Parser}|Parsers]) ->
|
||||||
|
try Parser(RawDate) of
|
||||||
|
{{_,_,_},{_,_,_}} = DateTime ->
|
||||||
|
{DateTime,undefined};
|
||||||
|
{DateTime={{_,_,_},{_,_,_}},Timezone} ->
|
||||||
|
{DateTime,Timezone};
|
||||||
|
undefined ->
|
||||||
|
try_parsers(RawDate, Parsers);
|
||||||
|
Other ->
|
||||||
|
throw({invalid_parser_return_value,[{parser_key,ParserKey},{return,Other}]})
|
||||||
|
catch
|
||||||
|
Error:Reason ->
|
||||||
|
throw({error_in_parser,[{error,{Error,Reason}},{parser_key,ParserKey}]})
|
||||||
|
end.
|
||||||
|
|
||||||
set_timezone(TZ) ->
|
set_timezone(TZ) ->
|
||||||
qdate_srv:set_timezone(TZ).
|
qdate_srv:set_timezone(TZ).
|
||||||
|
|
||||||
|
@ -168,6 +203,26 @@ to_now(ToParse) ->
|
||||||
unixtime_to_now(Unixtime).
|
unixtime_to_now(Unixtime).
|
||||||
|
|
||||||
|
|
||||||
|
register_parser(Key, Parser) when is_function(Parser,1) ->
|
||||||
|
qdate_srv:register_parser(Key,Parser).
|
||||||
|
|
||||||
|
register_parser(Parser) when is_function(Parser,1) ->
|
||||||
|
qdate_srv:register_parser(Parser).
|
||||||
|
|
||||||
|
deregister_parser(Key) ->
|
||||||
|
qdate_srv:deregister_parser(Key).
|
||||||
|
|
||||||
|
deregister_parsers() ->
|
||||||
|
qdate_srv:deregister_parsers().
|
||||||
|
|
||||||
|
register_format(Key, Format) ->
|
||||||
|
qdate_srv:register_format(Key, Format).
|
||||||
|
|
||||||
|
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,
|
||||||
|
@ -196,6 +251,8 @@ tz_formatting(Date,Format,TZ) ->
|
||||||
%% Z = TZ offset in seconds: -43200 - 50400
|
%% Z = TZ offset in seconds: -43200 - 50400
|
||||||
not_implemented.
|
not_implemented.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
%% TESTS
|
%% TESTS
|
||||||
-include_lib("eunit/include/eunit.hrl").
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
|
||||||
|
@ -217,7 +274,8 @@ tz_test_() ->
|
||||||
{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)
|
||||||
]}
|
]}
|
||||||
end
|
end
|
||||||
}.
|
}.
|
||||||
|
@ -252,6 +310,16 @@ simple_test(_) ->
|
||||||
%%tz_char_tests(_) ->
|
%%tz_char_tests(_) ->
|
||||||
%% qdate:set_timezone(?SELF_TZ),
|
%% qdate:set_timezone(?SELF_TZ),
|
||||||
|
|
||||||
|
parser_format_test(_) ->
|
||||||
|
{inorder,[
|
||||||
|
?_assertEqual({{2008,2,8},{0,0,0}},to_date("20080208")),
|
||||||
|
?_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,"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,"20080208"))
|
||||||
|
]}.
|
||||||
|
|
||||||
test_process_die(_) ->
|
test_process_die(_) ->
|
||||||
TZ = "MST",
|
TZ = "MST",
|
||||||
Caller = self(),
|
Caller = self(),
|
||||||
|
@ -289,7 +357,44 @@ 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(microsoft_date,fun microsoft_parser/1),
|
||||||
|
register_format(shortdate,"n/j/Y"),
|
||||||
|
register_format(longdate,"n/j/Y g:ia").
|
||||||
|
|
||||||
|
compressed_parser(List) when length(List)==8 ->
|
||||||
|
try re:run(List,"^(\\d{4})(\\d{2})(\\d{2})$",[{capture,all_but_first,list}]) of
|
||||||
|
nomatch -> undefined;
|
||||||
|
{match, [Y,M,D]} ->
|
||||||
|
Date = {list_to_integer(Y),list_to_integer(M),list_to_integer(D)},
|
||||||
|
case calendar:valid_date(Date) of
|
||||||
|
true ->
|
||||||
|
{Date,{0,0,0}};
|
||||||
|
false -> undefined
|
||||||
|
end
|
||||||
|
catch
|
||||||
|
_:_ -> undefined
|
||||||
|
end;
|
||||||
|
compressed_parser(_) ->
|
||||||
|
undefined.
|
||||||
|
|
||||||
|
microsoft_parser(FloatDate) when is_float(FloatDate) ->
|
||||||
|
try
|
||||||
|
DaysSince1900 = floor(FloatDate),
|
||||||
|
Days0to1900 = calendar:date_to_gregorian_days(1900,1,1),
|
||||||
|
GregorianDays = Days0to1900 + DaysSince1900,
|
||||||
|
Date = calendar:gregorian_days_to_date(GregorianDays),
|
||||||
|
Seconds = round(86400 * (FloatDate - DaysSince1900)),
|
||||||
|
Time = calendar:seconds_to_time(Seconds),
|
||||||
|
{Date,Time}
|
||||||
|
catch
|
||||||
|
_:_ -> undefined
|
||||||
|
end;
|
||||||
|
microsoft_parser(_) ->
|
||||||
|
undefined.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
stop_test(_) ->
|
stop_test(_) ->
|
||||||
ok.
|
ok.
|
||||||
|
|
|
@ -16,24 +16,20 @@
|
||||||
-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,
|
||||||
%% deregister_parsers/0,
|
deregister_parsers/0,
|
||||||
%% deregister_parsers/1,
|
deregister_parser/1,
|
||||||
%%
|
|
||||||
%% register_format/1,
|
register_format/2,
|
||||||
%% register_format/2,
|
get_format/1,
|
||||||
%%
|
deregister_format/1
|
||||||
%% deregister_format/0,
|
|
||||||
%% deregister_format/1
|
|
||||||
]).
|
]).
|
||||||
|
|
||||||
%% PUBLIC API FUNCTIONS
|
%% PUBLIC API FUNCTIONS
|
||||||
|
@ -45,7 +41,7 @@ set_timezone(TZ) ->
|
||||||
set_timezone(self(),TZ).
|
set_timezone(self(),TZ).
|
||||||
|
|
||||||
set_timezone(Key,TZ) ->
|
set_timezone(Key,TZ) ->
|
||||||
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()).
|
||||||
|
@ -57,7 +53,32 @@ clear_timezone() ->
|
||||||
clear_timezone(self()).
|
clear_timezone(self()).
|
||||||
|
|
||||||
clear_timezone(Key) ->
|
clear_timezone(Key) ->
|
||||||
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(erlang:make_ref(),Parser).
|
||||||
|
|
||||||
|
register_parser(Key,Parser) when is_function(Parser,1) ->
|
||||||
|
Key = gen_server:call(?SRV,{register_parser,Key,Parser}).
|
||||||
|
|
||||||
|
deregister_parser(Key) ->
|
||||||
|
ok = gen_server:call(?SRV,{deregister_parser,Key}).
|
||||||
|
|
||||||
|
deregister_parsers() ->
|
||||||
|
ok = gen_server:call(?SRV,{deregister_parsers}).
|
||||||
|
|
||||||
|
get_parsers() ->
|
||||||
|
gen_server:call(?SRV,{get_parsers}).
|
||||||
|
|
||||||
|
register_format(Key,Format) ->
|
||||||
|
ok = gen_server:call(?SRV,{register_format,Key,Format}).
|
||||||
|
|
||||||
|
get_format(Key) ->
|
||||||
|
gen_server:call(?SRV,{get_format,Key}).
|
||||||
|
|
||||||
|
deregister_format(Key) ->
|
||||||
|
ok = gen_server:call(?SRV,{deregister_format,Key}).
|
||||||
|
|
||||||
|
|
||||||
%% SERVER FUNCTIONS
|
%% SERVER FUNCTIONS
|
||||||
|
|
||||||
|
@ -92,13 +113,39 @@ handle_call({clear_timezone,Key},_From, State) ->
|
||||||
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, Value} -> Value
|
{ok,TZ} -> TZ
|
||||||
end,
|
end,
|
||||||
{reply, Reply, State}.
|
{reply, Reply, State};
|
||||||
%% handle_call({register_parser,Key,Parser}) ->
|
|
||||||
%% handle_call({deregister_parsers,Key}) ->
|
handle_call({register_parser,Key,Parser},_From,State) ->
|
||||||
%% handle_call({register_format,Key,Format}) ->
|
NewParsers = dict:store(Key, Parser, State#state.parsers),
|
||||||
%% handle_call({deregister_formats,Key}) ->
|
NewState = State#state{parsers=NewParsers},
|
||||||
|
{reply, Key, NewState};
|
||||||
|
handle_call({get_parsers},_From,State) ->
|
||||||
|
Reply = dict:to_list(State#state.parsers),
|
||||||
|
{reply, Reply, State};
|
||||||
|
handle_call({deregister_parser,Key},_From,State) ->
|
||||||
|
NewParsers = dict:erase(Key, State#state.parsers),
|
||||||
|
NewState = State#state{parsers=NewParsers},
|
||||||
|
{reply, ok, NewState};
|
||||||
|
handle_call({deregister_parsers},_From,State) ->
|
||||||
|
NewState = State#state{parsers=dict:new()},
|
||||||
|
{reply, ok, NewState};
|
||||||
|
|
||||||
|
handle_call({register_format,Key,Format},_From,State) ->
|
||||||
|
NewFormats = dict:store(Key, Format, State#state.formats),
|
||||||
|
NewState = State#state{formats=NewFormats},
|
||||||
|
{reply, ok, NewState};
|
||||||
|
handle_call({get_format,Key},_From,State) ->
|
||||||
|
Reply = case dict:find(Key, State#state.formats) of
|
||||||
|
error -> undefined;
|
||||||
|
{ok, Format} -> Format
|
||||||
|
end,
|
||||||
|
{reply, Reply,State};
|
||||||
|
handle_call({deregister_format,Key},_From,State) ->
|
||||||
|
NewFormats = dict:erase(Key, State#state.formats),
|
||||||
|
NewState = State#state{formats=NewFormats},
|
||||||
|
{reply, ok, NewState}.
|
||||||
|
|
||||||
terminate(_Reason, _State) ->
|
terminate(_Reason, _State) ->
|
||||||
ok.
|
ok.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue