Merge remote-tracking branch 'canonical/next'
This commit is contained in:
commit
fd505767e5
5 changed files with 280 additions and 67 deletions
|
@ -1,4 +1,4 @@
|
|||
=nlanguage: erlang
|
||||
language: erlang
|
||||
otp_release:
|
||||
- R15B02
|
||||
- R15B01
|
||||
|
|
45
Makefile
45
Makefile
|
@ -3,6 +3,7 @@
|
|||
# BSD License see COPYING
|
||||
|
||||
ERL = $(shell which erl)
|
||||
ERL_VER = $(shell erl -eval 'erlang:display(erlang:system_info(otp_release)), halt().' -noshell)
|
||||
|
||||
ERLFLAGS= -pa $(CURDIR)/.eunit -pa $(CURDIR)/ebin -pa $(CURDIR)/*/ebin
|
||||
|
||||
|
@ -14,10 +15,9 @@ endif
|
|||
|
||||
ERLWARE_COMMONS_PLT=$(CURDIR)/.erlware_commons_plt
|
||||
|
||||
.PHONY: all compile doc clean test dialyzer typer shell distclean pdf get-deps \
|
||||
rebuild
|
||||
.PHONY: all compile doc clean test shell distclean pdf get-deps rebuild #dialyzer typer #fail on Travis.
|
||||
|
||||
all: compile dialyzer doc test
|
||||
all: compile doc test #dialyzer #fail on travis
|
||||
|
||||
get-deps:
|
||||
$(REBAR) get-deps
|
||||
|
@ -27,22 +27,41 @@ compile:
|
|||
$(REBAR) skip_deps=true compile
|
||||
|
||||
doc: compile
|
||||
$(REBAR) skip_deps=true doc
|
||||
- $(REBAR) skip_deps=true doc
|
||||
|
||||
test: compile
|
||||
$(REBAR) skip_deps=true eunit
|
||||
|
||||
$(ERLWARE_COMMONS_PLT):
|
||||
@echo Building local plt at $(ERLWARE_COMMONS_PLT)
|
||||
$(ERLWARE_COMMONS_PLT).$(ERL_VER).erts:
|
||||
@echo Building local plt at $(ERLWARE_COMMONS_PLT).$(ERL_VER).base
|
||||
@echo
|
||||
- dialyzer --fullpath --output_plt $(ERLWARE_COMMONS_PLT) --build_plt \
|
||||
--apps erts kernel stdlib eunit -r deps
|
||||
|
||||
dialyzer: $(ERLWARE_COMMONS_PLT)
|
||||
dialyzer --fullpath --plt $(ERLWARE_COMMONS_PLT) -Wrace_conditions -r ./ebin
|
||||
- dialyzer --fullpath --verbose --output_plt $(ERLWARE_COMMONS_PLT).$(ERL_VER).base --build_plt \
|
||||
--apps erts
|
||||
|
||||
typer:
|
||||
typer --plt $(ERLWARE_COMMONS_PLT) -r ./src
|
||||
$(ERLWARE_COMMONS_PLT).$(ERL_VER).kernel:$(ERLWARE_COMMONS_PLT).$(ERL_VER).erts
|
||||
@echo Building local plt at $(ERLWARE_COMMONS_PLT).$(ERL_VER).base
|
||||
@echo
|
||||
- dialyzer --fullpath --verbose --output_plt $(ERLWARE_COMMONS_PLT).$(ERL_VER).base --build_plt \
|
||||
--apps kernel
|
||||
|
||||
$(ERLWARE_COMMONS_PLT).$(ERL_VER).base:$(ERLWARE_COMMONS_PLT).$(ERL_VER).kernel
|
||||
@echo Building local plt at $(ERLWARE_COMMONS_PLT).$(ERL_VER).base
|
||||
@echo
|
||||
- dialyzer --fullpath --verbose --output_plt $(ERLWARE_COMMONS_PLT).$(ERL_VER).base --build_plt \
|
||||
--apps stdlib
|
||||
|
||||
$(ERLWARE_COMMONS_PLT).$(ERL_VER): $(ERLWARE_COMMONS_PLT).$(ERL_VER).base
|
||||
@echo Building local plt at $(ERLWARE_COMMONS_PLT).$(ERL_VER)
|
||||
@echo
|
||||
- dialyzer --fullpath --verbose --output_plt $(ERLWARE_COMMONS_PLT).$(ERL_VER) --add_to_plt --plt $(ERLWARE_COMMONS_PLT).$(ERL_VER).base \
|
||||
--apps eunit -r deps
|
||||
|
||||
dialyzer: $(ERLWARE_COMMONS_PLT).$(ERL_VER)
|
||||
dialyzer --fullpath --plt $(ERLWARE_COMMONS_PLT).$(ERL_VER) -Wrace_conditions -r ./ebin
|
||||
|
||||
typer: $(ERLWARE_COMMONS_PLT).$(ERL)VER(
|
||||
typer --plt $(ERLWARE_COMMONS_PLT).$(ERL_VER) -r ./src
|
||||
|
||||
shell: compile
|
||||
# You often want *rebuilt* rebar tests to be available to the
|
||||
|
@ -61,7 +80,7 @@ clean:
|
|||
- rm $(CURDIR)/doc/edoc-info
|
||||
|
||||
distclean: clean
|
||||
rm -rf $(ERLWARE_COMMONS_PLT)
|
||||
rm -rf $(ERLWARE_COMMONS_PLT).$(ERL_VER)
|
||||
rm -rvf $(CURDIR)/deps/*
|
||||
|
||||
rebuild: distclean get-deps all
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{match, [ErtsNumber]} = re:run("R15B02", "R(\\d+).+", [{capture, [1], list}]),
|
||||
{match, [ErtsNumber]} = re:run(erlang:system_info(otp_release), "R(\\d+).+", [{capture, [1], list}]),
|
||||
ErtsVsn = erlang:list_to_integer(ErtsNumber),
|
||||
Opts1 = case lists:keysearch(erl_opts, 1, CONFIG) of
|
||||
{value, {erl_opts, Opts0}} ->
|
||||
|
@ -8,8 +8,8 @@ Opts1 = case lists:keysearch(erl_opts, 1, CONFIG) of
|
|||
end,
|
||||
Opts2 = if
|
||||
ErtsVsn >= 15 ->
|
||||
[{d, have_callback_support} | Opts1];
|
||||
true ->
|
||||
[{d, have_callback_support} | Opts1];
|
||||
true ->
|
||||
Opts1
|
||||
end,
|
||||
lists:keystore(erl_opts, 1, CONFIG, {erl_opts, Opts2}).
|
||||
|
|
251
src/ec_date.erl
251
src/ec_date.erl
|
@ -34,10 +34,16 @@
|
|||
-define( is_us_sep(X), ( X==$/) ).
|
||||
-define( is_world_sep(X), ( X==$-) ).
|
||||
|
||||
-define( MONTH_TAG, month ).
|
||||
-define( is_year(X), (is_integer(X) andalso X > 31) ).
|
||||
-define( is_day(X), (is_integer(X) andalso X =< 31) ).
|
||||
-define( is_hinted_month(X), (is_tuple(X) andalso size(X)=:=2 andalso element(1,X)=:=?MONTH_TAG) ).
|
||||
-define( is_month(X), ( (is_integer(X) andalso X =< 12) orelse ?is_hinted_month(X) ) ).
|
||||
|
||||
-define(GREGORIAN_SECONDS_1970, 62167219200).
|
||||
|
||||
-type year() :: non_neg_integer().
|
||||
-type month() :: 1..12.
|
||||
-type month() :: 1..12 | {?MONTH_TAG, 1..12}.
|
||||
-type day() :: 1..31.
|
||||
-type hour() :: 0..23.
|
||||
-type minute() :: 0..59.
|
||||
|
@ -81,7 +87,7 @@ parse(Date, Now) ->
|
|||
do_parse(Date, Now, []).
|
||||
|
||||
do_parse(Date, Now, Opts) ->
|
||||
case parse(tokenise(string:to_upper(Date), []), Now, Opts) of
|
||||
case filter_hints(parse(tokenise(string:to_upper(Date), []), Now, Opts)) of
|
||||
{error, bad_date} ->
|
||||
erlang:throw({?MODULE, {bad_date, Date}});
|
||||
{D1, T1} = {{Y, M, D}, {H, M1, S}}
|
||||
|
@ -96,7 +102,7 @@ do_parse(Date, Now, Opts) ->
|
|||
when is_number(Y), is_number(M),
|
||||
is_number(D), is_number(H),
|
||||
is_number(M1), is_number(S),
|
||||
is_number(Ms) ->
|
||||
is_number(Ms) ->
|
||||
case calendar:valid_date(D1) of
|
||||
true -> {D1, {H,M1,S,Ms}};
|
||||
false -> erlang:throw({?MODULE, {bad_date, Date}})
|
||||
|
@ -104,63 +110,120 @@ do_parse(Date, Now, Opts) ->
|
|||
Unknown -> erlang:throw({?MODULE, {bad_date, Date, Unknown }})
|
||||
end.
|
||||
|
||||
filter_hints({{Y, {?MONTH_TAG, M}, D}, {H, M1, S}}) ->
|
||||
filter_hints({{Y, M, D}, {H, M1, S}});
|
||||
filter_hints({{Y, {?MONTH_TAG, M}, D}, {H, M1, S}, {Ms}}) ->
|
||||
filter_hints({{Y, M, D}, {H, M1, S}, {Ms}});
|
||||
filter_hints(Other) ->
|
||||
Other.
|
||||
|
||||
-spec nparse(string()) -> now().
|
||||
%% @doc parses the datetime from a string into 'now' format
|
||||
nparse(Date) ->
|
||||
case parse(Date) of
|
||||
{DateS, {H, M, S, Ms} } ->
|
||||
GSeconds = calendar:datetime_to_gregorian_seconds({DateS, {H, M, S} }),
|
||||
ESeconds = GSeconds - ?GREGORIAN_SECONDS_1970,
|
||||
{ESeconds div 1000000, ESeconds rem 1000000, Ms};
|
||||
DateTime ->
|
||||
GSeconds = calendar:datetime_to_gregorian_seconds(DateTime),
|
||||
ESeconds = GSeconds - ?GREGORIAN_SECONDS_1970,
|
||||
{ESeconds div 1000000, ESeconds rem 1000000, 0}
|
||||
{DateS, {H, M, S, Ms} } ->
|
||||
GSeconds = calendar:datetime_to_gregorian_seconds({DateS, {H, M, S} }),
|
||||
ESeconds = GSeconds - ?GREGORIAN_SECONDS_1970,
|
||||
{ESeconds div 1000000, ESeconds rem 1000000, Ms};
|
||||
DateTime ->
|
||||
GSeconds = calendar:datetime_to_gregorian_seconds(DateTime),
|
||||
ESeconds = GSeconds - ?GREGORIAN_SECONDS_1970,
|
||||
{ESeconds div 1000000, ESeconds rem 1000000, 0}
|
||||
end.
|
||||
|
||||
%%
|
||||
%% LOCAL FUNCTIONS
|
||||
%%
|
||||
|
||||
parse([Year, X, Month, X, Day, Hour, $:, Min, $:, Sec, $Z ], _Now, _Opts)
|
||||
when (?is_us_sep(X) orelse ?is_world_sep(X))
|
||||
andalso Year > 31 ->
|
||||
{{Year, Month, Day}, {hour(Hour, []), Min, Sec}, { 0}};
|
||||
|
||||
parse([Year, X, Month, X, Day, Hour, $:, Min, $:, Sec, $+, Off | _Rest ], _Now, _Opts)
|
||||
when (?is_us_sep(X) orelse ?is_world_sep(X))
|
||||
andalso Year > 31 ->
|
||||
{{Year, Month, Day}, {hour(Hour, []) - Off, Min, Sec}, {0}};
|
||||
|
||||
parse([Year, X, Month, X, Day, Hour, $:, Min, $:, Sec, $-, Off | _Rest ], _Now, _Opts)
|
||||
when (?is_us_sep(X) orelse ?is_world_sep(X))
|
||||
andalso Year > 31 ->
|
||||
{{Year, Month, Day}, {hour(Hour, []) + Off, Min, Sec}, {0}};
|
||||
|
||||
%% Date/Times 22 Aug 2008 6:35.0001 PM
|
||||
parse([Year,X,Month,X,Day,Hour,$:,Min,$:,Sec,$., Ms | PAM], _Now, _Opts)
|
||||
when ?is_meridian(PAM) andalso
|
||||
(?is_us_sep(X) orelse ?is_world_sep(X))
|
||||
andalso Year > 31 ->
|
||||
andalso ?is_year(Year) ->
|
||||
{{Year, Month, Day}, {hour(Hour, PAM), Min, Sec}, {Ms}};
|
||||
parse([Month,X,Day,X,Year,Hour,$:,Min,$:,Sec,$., Ms | PAM], _Now, _Opts)
|
||||
when ?is_meridian(PAM) andalso ?is_us_sep(X) ->
|
||||
when ?is_meridian(PAM) andalso ?is_us_sep(X)
|
||||
andalso ?is_year(Year) ->
|
||||
{{Year, Month, Day}, {hour(Hour, PAM), Min, Sec}, {Ms}};
|
||||
parse([Day,X,Month,X,Year,Hour,$:,Min,$:,Sec,$., Ms | PAM], _Now, _Opts)
|
||||
when ?is_meridian(PAM) andalso ?is_world_sep(X) ->
|
||||
when ?is_meridian(PAM) andalso ?is_world_sep(X)
|
||||
andalso ?is_year(Year) ->
|
||||
{{Year, Month, Day}, {hour(Hour, PAM), Min, Sec}, {Ms}};
|
||||
|
||||
parse([Year,X,Month,X,Day,Hour,$:,Min,$:,Sec,$., Ms], _Now, _Opts)
|
||||
when (?is_us_sep(X) orelse ?is_world_sep(X))
|
||||
andalso Year > 31 ->
|
||||
andalso ?is_year(Year) ->
|
||||
{{Year, Month, Day}, {hour(Hour,[]), Min, Sec}, {Ms}};
|
||||
parse([Month,X,Day,X,Year,Hour,$:,Min,$:,Sec,$., Ms], _Now, _Opts)
|
||||
when ?is_us_sep(X) ->
|
||||
when ?is_us_sep(X) andalso ?is_month(Month) ->
|
||||
{{Year, Month, Day}, {hour(Hour, []), Min, Sec}, {Ms}};
|
||||
parse([Day,X,Month,X,Year,Hour,$:,Min,$:,Sec,$., Ms ], _Now, _Opts)
|
||||
when ?is_world_sep(X) ->
|
||||
when ?is_world_sep(X) andalso ?is_month(Month) ->
|
||||
{{Year, Month, Day}, {hour(Hour, []), Min, Sec}, {Ms}};
|
||||
|
||||
%% Date/Times Dec 1st, 2012 6:25 PM
|
||||
parse([Month,Day,Year,Hour,$:,Min,$:,Sec | PAM], _Now, _Opts)
|
||||
when ?is_meridian(PAM) andalso ?is_hinted_month(Month) andalso ?is_day(Day) ->
|
||||
{{Year, Month, Day}, {hour(Hour, PAM), Min, Sec}};
|
||||
parse([Month,Day,Year,Hour,$:,Min | PAM], _Now, _Opts)
|
||||
when ?is_meridian(PAM) andalso ?is_hinted_month(Month) andalso ?is_day(Day) ->
|
||||
{{Year, Month, Day}, {hour(Hour, PAM), Min, 0}};
|
||||
parse([Month,Day,Year,Hour | PAM], _Now, _Opts)
|
||||
when ?is_meridian(PAM) andalso ?is_hinted_month(Month) andalso ?is_day(Day) ->
|
||||
{{Year, Month, Day}, {hour(Hour, PAM), 0, 0}};
|
||||
|
||||
%% Date/Times Dec 1st, 2012 18:25:15 (no AM/PM)
|
||||
parse([Month,Day,Year,Hour,$:,Min,$:,Sec], _Now, _Opts)
|
||||
when ?is_hinted_month(Month) andalso ?is_day(Day) ->
|
||||
{{Year, Month, Day}, {hour(Hour, []), Min, Sec}};
|
||||
parse([Month,Day,Year,Hour,$:,Min], _Now, _Opts)
|
||||
when ?is_hinted_month(Month) andalso ?is_day(Day) ->
|
||||
{{Year, Month, Day}, {hour(Hour, []), Min, 0}};
|
||||
|
||||
%% Times - 21:45, 13:45:54, 13:15PM etc
|
||||
parse([Hour,$:,Min,$:,Sec | PAM], {Date, _Time}, _O) when ?is_meridian(PAM) ->
|
||||
{Date, {hour(Hour, PAM), Min, Sec}};
|
||||
parse([Hour,$:,Min | PAM], {Date, _Time}, _Opts) when ?is_meridian(PAM) ->
|
||||
{Date, {hour(Hour, PAM), Min, 0}};
|
||||
parse([Hour | PAM],{Date,_Time}, _Opts) when ?is_meridian(PAM) ->
|
||||
{Date, {hour(Hour,PAM), 0, 0}};
|
||||
{Date, {hour(Hour,PAM), 0, 0}};
|
||||
|
||||
%% Dates (Any combination with word month "aug 8th, 2008", "8 aug 2008", "2008 aug 21" "2008 5 aug" )
|
||||
%% Will work because of the "Hinted month"
|
||||
parse([Day,Month,Year], {_Date, Time}, _Opts)
|
||||
when ?is_day(Day) andalso ?is_hinted_month(Month) andalso ?is_year(Year) ->
|
||||
{{Year, Month, Day}, Time};
|
||||
parse([Month,Day,Year], {_Date, Time}, _Opts)
|
||||
when ?is_day(Day) andalso ?is_hinted_month(Month) andalso ?is_year(Year) ->
|
||||
{{Year, Month, Day}, Time};
|
||||
parse([Year,Day,Month], {_Date, Time}, _Opts)
|
||||
when ?is_day(Day) andalso ?is_hinted_month(Month) andalso ?is_year(Year) ->
|
||||
{{Year, Month, Day}, Time};
|
||||
parse([Year,Month,Day], {_Date, Time}, _Opts)
|
||||
when ?is_day(Day) andalso ?is_hinted_month(Month) andalso ?is_year(Year) ->
|
||||
{{Year, Month, Day}, Time};
|
||||
|
||||
%% Dates 23/april/1963
|
||||
parse([Day,Month,Year], {_Date, Time}, _Opts) ->
|
||||
{{Year, Month, Day}, Time};
|
||||
parse([Year,X,Month,X,Day], {_Date, Time}, _Opts)
|
||||
when (?is_us_sep(X) orelse ?is_world_sep(X))
|
||||
andalso Year > 31 ->
|
||||
andalso ?is_year(Year) ->
|
||||
{{Year, Month, Day}, Time};
|
||||
parse([Month,X,Day,X,Year], {_Date, Time}, _Opts) when ?is_us_sep(X) ->
|
||||
{{Year, Month, Day}, Time};
|
||||
|
@ -172,7 +235,7 @@ parse([Day,X,Month,X,Year], {_Date, Time}, _Opts) when ?is_world_sep(X) ->
|
|||
parse([Year,X,Month,X,Day,Hour | PAM], _Date, _Opts)
|
||||
when ?is_meridian(PAM) andalso
|
||||
(?is_us_sep(X) orelse ?is_world_sep(X))
|
||||
andalso Year > 31 ->
|
||||
andalso ?is_year(Year) ->
|
||||
{{Year, Month, Day}, {hour(Hour, PAM), 0, 0}};
|
||||
parse([Day,X,Month,X,Year,Hour | PAM], _Date, _Opts)
|
||||
when ?is_meridian(PAM) andalso ?is_world_sep(X) ->
|
||||
|
@ -186,7 +249,7 @@ parse([Month,X,Day,X,Year,Hour | PAM], _Date, _Opts)
|
|||
parse([Year,X,Month,X,Day,Hour,$:,Min | PAM], _Date, _Opts)
|
||||
when ?is_meridian(PAM) andalso
|
||||
(?is_us_sep(X) orelse ?is_world_sep(X))
|
||||
andalso Year > 31 ->
|
||||
andalso ?is_year(Year) ->
|
||||
{{Year, Month, Day}, {hour(Hour, PAM), Min, 0}};
|
||||
parse([Day,X,Month,X,Year,Hour,$:,Min | PAM], _Date, _Opts)
|
||||
when ?is_meridian(PAM) andalso ?is_world_sep(X) ->
|
||||
|
@ -199,7 +262,7 @@ parse([Month,X,Day,X,Year,Hour,$:,Min | PAM], _Date, _Opts)
|
|||
parse([Year,X,Month,X,Day,Hour,$:,Min,$:,Sec | PAM], _Now, _Opts)
|
||||
when ?is_meridian(PAM) andalso
|
||||
(?is_us_sep(X) orelse ?is_world_sep(X))
|
||||
andalso Year > 31 ->
|
||||
andalso ?is_year(Year) ->
|
||||
{{Year, Month, Day}, {hour(Hour, PAM), Min, Sec}};
|
||||
parse([Month,X,Day,X,Year,Hour,$:,Min,$:,Sec | PAM], _Now, _Opts)
|
||||
when ?is_meridian(PAM) andalso ?is_us_sep(X) ->
|
||||
|
@ -243,32 +306,37 @@ tokenise([N1 | Rest], Acc)
|
|||
when ?is_num(N1) ->
|
||||
tokenise(Rest, [ ltoi([N1]) | Acc]);
|
||||
|
||||
tokenise("JANUARY"++Rest, Acc) -> tokenise(Rest, [1 | Acc]);
|
||||
tokenise("JAN"++Rest, Acc) -> tokenise(Rest, [1 | Acc]);
|
||||
tokenise("FEBRUARY"++Rest, Acc) -> tokenise(Rest, [2 | Acc]);
|
||||
tokenise("FEB"++Rest, Acc) -> tokenise(Rest, [2 | Acc]);
|
||||
tokenise("MARCH"++Rest, Acc) -> tokenise(Rest, [3 | Acc]);
|
||||
tokenise("MAR"++Rest, Acc) -> tokenise(Rest, [3 | Acc]);
|
||||
tokenise("APRIL"++Rest, Acc) -> tokenise(Rest, [4 | Acc]);
|
||||
tokenise("APR"++Rest, Acc) -> tokenise(Rest, [4 | Acc]);
|
||||
tokenise("MAY"++Rest, Acc) -> tokenise(Rest, [5 | Acc]);
|
||||
tokenise("JUNE"++Rest, Acc) -> tokenise(Rest, [6 | Acc]);
|
||||
tokenise("JUN"++Rest, Acc) -> tokenise(Rest, [6 | Acc]);
|
||||
tokenise("JULY"++Rest, Acc) -> tokenise(Rest, [7 | Acc]);
|
||||
tokenise("JUL"++Rest, Acc) -> tokenise(Rest, [7 | Acc]);
|
||||
tokenise("AUGUST"++Rest, Acc) -> tokenise(Rest, [8 | Acc]);
|
||||
tokenise("AUG"++Rest, Acc) -> tokenise(Rest, [8 | Acc]);
|
||||
tokenise("SEPTEMBER"++Rest, Acc) -> tokenise(Rest, [9 | Acc]);
|
||||
tokenise("SEPT"++Rest, Acc) -> tokenise(Rest, [9 | Acc]);
|
||||
tokenise("SEP"++Rest, Acc) -> tokenise(Rest, [9 | Acc]);
|
||||
tokenise("OCTOBER"++Rest, Acc) -> tokenise(Rest, [10 | Acc]);
|
||||
tokenise("OCT"++Rest, Acc) -> tokenise(Rest, [10 | Acc]);
|
||||
tokenise("NOVEMBER"++Rest, Acc) -> tokenise(Rest, [11 | Acc]);
|
||||
tokenise("NOVEM"++Rest, Acc) -> tokenise(Rest, [11 | Acc]);
|
||||
tokenise("NOV"++Rest, Acc) -> tokenise(Rest, [11 | Acc]);
|
||||
tokenise("DECEMBER"++Rest, Acc) -> tokenise(Rest, [12 | Acc]);
|
||||
tokenise("DECEM"++Rest, Acc) -> tokenise(Rest, [12 | Acc]);
|
||||
tokenise("DEC"++Rest, Acc) -> tokenise(Rest, [12 | Acc]);
|
||||
|
||||
%% Worded Months get tagged with ?MONTH_TAG to let the parser know that these
|
||||
%% are unambiguously declared to be months. This was there's no confusion
|
||||
%% between, for example: "Aug 12" and "12 Aug"
|
||||
%% These hint tags are filtered in filter_hints/1 above.
|
||||
tokenise("JANUARY"++Rest, Acc) -> tokenise(Rest, [{?MONTH_TAG,1} | Acc]);
|
||||
tokenise("JAN"++Rest, Acc) -> tokenise(Rest, [{?MONTH_TAG,1} | Acc]);
|
||||
tokenise("FEBRUARY"++Rest, Acc) -> tokenise(Rest, [{?MONTH_TAG,2} | Acc]);
|
||||
tokenise("FEB"++Rest, Acc) -> tokenise(Rest, [{?MONTH_TAG,2} | Acc]);
|
||||
tokenise("MARCH"++Rest, Acc) -> tokenise(Rest, [{?MONTH_TAG,3} | Acc]);
|
||||
tokenise("MAR"++Rest, Acc) -> tokenise(Rest, [{?MONTH_TAG,3} | Acc]);
|
||||
tokenise("APRIL"++Rest, Acc) -> tokenise(Rest, [{?MONTH_TAG,4} | Acc]);
|
||||
tokenise("APR"++Rest, Acc) -> tokenise(Rest, [{?MONTH_TAG,4} | Acc]);
|
||||
tokenise("MAY"++Rest, Acc) -> tokenise(Rest, [{?MONTH_TAG,5} | Acc]);
|
||||
tokenise("JUNE"++Rest, Acc) -> tokenise(Rest, [{?MONTH_TAG,6} | Acc]);
|
||||
tokenise("JUN"++Rest, Acc) -> tokenise(Rest, [{?MONTH_TAG,6} | Acc]);
|
||||
tokenise("JULY"++Rest, Acc) -> tokenise(Rest, [{?MONTH_TAG,7} | Acc]);
|
||||
tokenise("JUL"++Rest, Acc) -> tokenise(Rest, [{?MONTH_TAG,7} | Acc]);
|
||||
tokenise("AUGUST"++Rest, Acc) -> tokenise(Rest, [{?MONTH_TAG,8} | Acc]);
|
||||
tokenise("AUG"++Rest, Acc) -> tokenise(Rest, [{?MONTH_TAG,8} | Acc]);
|
||||
tokenise("SEPTEMBER"++Rest, Acc) -> tokenise(Rest, [{?MONTH_TAG,9} | Acc]);
|
||||
tokenise("SEPT"++Rest, Acc) -> tokenise(Rest, [{?MONTH_TAG,9} | Acc]);
|
||||
tokenise("SEP"++Rest, Acc) -> tokenise(Rest, [{?MONTH_TAG,9} | Acc]);
|
||||
tokenise("OCTOBER"++Rest, Acc) -> tokenise(Rest, [{?MONTH_TAG,10} | Acc]);
|
||||
tokenise("OCT"++Rest, Acc) -> tokenise(Rest, [{?MONTH_TAG,10} | Acc]);
|
||||
tokenise("NOVEMBER"++Rest, Acc) -> tokenise(Rest, [{?MONTH_TAG,11} | Acc]);
|
||||
tokenise("NOVEM"++Rest, Acc) -> tokenise(Rest, [{?MONTH_TAG,11} | Acc]);
|
||||
tokenise("NOV"++Rest, Acc) -> tokenise(Rest, [{?MONTH_TAG,11} | Acc]);
|
||||
tokenise("DECEMBER"++Rest, Acc) -> tokenise(Rest, [{?MONTH_TAG,12} | Acc]);
|
||||
tokenise("DECEM"++Rest, Acc) -> tokenise(Rest, [{?MONTH_TAG,12} | Acc]);
|
||||
tokenise("DEC"++Rest, Acc) -> tokenise(Rest, [{?MONTH_TAG,12} | Acc]);
|
||||
|
||||
tokenise([$: | Rest], Acc) -> tokenise(Rest, [ $: | Acc]);
|
||||
tokenise([$/ | Rest], Acc) -> tokenise(Rest, [ $/ | Acc]);
|
||||
|
@ -317,7 +385,9 @@ tokenise("ND"++Rest, Acc) -> tokenise(Rest, Acc);
|
|||
tokenise("ST"++Rest, Acc) -> tokenise(Rest, Acc);
|
||||
tokenise("OF"++Rest, Acc) -> tokenise(Rest, Acc);
|
||||
tokenise("T"++Rest, Acc) -> tokenise(Rest, Acc); % 2012-12-12T12:12:12 ISO formatting.
|
||||
tokenise([$. | Rest], Acc) -> tokenise(Rest, [$. | Acc]); % 2012-12-12T12:12:12.xxxx ISO formatting.
|
||||
tokenise([$Z | Rest], Acc) -> tokenise(Rest, [$Z | Acc]); % 2012-12-12T12:12:12Zulu
|
||||
tokenise([$. | Rest], Acc) -> tokenise(Rest, [$. | Acc]); % 2012-12-12T12:12:12.xxxx ISO formatting.
|
||||
tokenise([$+| Rest], Acc) -> tokenise(Rest, [$+ | Acc]); % 2012-12-12T12:12:12.xxxx+ ISO formatting.
|
||||
|
||||
tokenise([Else | Rest], Acc) ->
|
||||
tokenise(Rest, [{bad_token, Else} | Acc]).
|
||||
|
@ -489,6 +559,10 @@ to_w(X) -> X.
|
|||
suffix(1) -> "st";
|
||||
suffix(2) -> "nd";
|
||||
suffix(3) -> "rd";
|
||||
suffix(21) -> "st";
|
||||
suffix(22) -> "nd";
|
||||
suffix(23) -> "rd";
|
||||
suffix(31) -> "st";
|
||||
suffix(_) -> "th".
|
||||
|
||||
-spec sdayd(date()) -> string().
|
||||
|
@ -611,6 +685,11 @@ ltoi(X) ->
|
|||
basic_format_test_() ->
|
||||
[
|
||||
?_assertEqual(format("F j, Y, g:i a",?DATE), "March 10, 2001, 5:16 pm"),
|
||||
?_assertEqual(format("F jS, Y, g:i a",?DATE), "March 10th, 2001, 5:16 pm"),
|
||||
?_assertEqual(format("F jS",{{2011,3,21},{0,0,0}}), "March 21st"),
|
||||
?_assertEqual(format("F jS",{{2011,3,22},{0,0,0}}), "March 22nd"),
|
||||
?_assertEqual(format("F jS",{{2011,3,23},{0,0,0}}), "March 23rd"),
|
||||
?_assertEqual(format("F jS",{{2011,3,31},{0,0,0}}), "March 31st"),
|
||||
?_assertEqual(format("m.d.y",?DATE), "03.10.01"),
|
||||
?_assertEqual(format("j, n, Y",?DATE), "10, 3, 2001"),
|
||||
?_assertEqual(format("Ymd",?DATE), "20010310"),
|
||||
|
@ -656,6 +735,64 @@ basic_parse_test_() ->
|
|||
parse("22 Aug 2008 6:35 PM", ?DATE)),
|
||||
?_assertEqual({{2008,8,22}, {18,0,0}},
|
||||
parse("22 Aug 2008 6 PM", ?DATE)),
|
||||
?_assertEqual({{2008,8,22}, {18,0,0}},
|
||||
parse("Aug 22, 2008 6 PM", ?DATE)),
|
||||
?_assertEqual({{2008,8,22}, {18,0,0}},
|
||||
parse("August 22nd, 2008 6:00 PM", ?DATE)),
|
||||
?_assertEqual({{2008,8,22}, {18,15,15}},
|
||||
parse("August 22nd 2008, 6:15:15pm", ?DATE)),
|
||||
?_assertEqual({{2008,8,22}, {18,15,15}},
|
||||
parse("August 22nd, 2008, 6:15:15pm", ?DATE)),
|
||||
?_assertEqual({{2008,8,22}, {18,15,0}},
|
||||
parse("Aug 22nd 2008, 18:15", ?DATE)),
|
||||
?_assertEqual({{2008,8,2}, {17,16,17}},
|
||||
parse("2nd of August 2008", ?DATE)),
|
||||
?_assertEqual({{2008,8,2}, {17,16,17}},
|
||||
parse("August 2nd, 2008", ?DATE)),
|
||||
?_assertEqual({{2008,8,2}, {17,16,17}},
|
||||
parse("2nd August, 2008", ?DATE)),
|
||||
?_assertEqual({{2008,8,2}, {17,16,17}},
|
||||
parse("2008 August 2nd", ?DATE)),
|
||||
?_assertEqual({{2008,8,2}, {6,0,0}},
|
||||
parse("2-Aug-2008 6 AM", ?DATE)),
|
||||
?_assertEqual({{2008,8,2}, {6,35,0}},
|
||||
parse("2-Aug-2008 6:35 AM", ?DATE)),
|
||||
?_assertEqual({{2008,8,2}, {6,35,12}},
|
||||
parse("2-Aug-2008 6:35:12 AM", ?DATE)),
|
||||
?_assertEqual({{2008,8,2}, {6,0,0}},
|
||||
parse("August/2/2008 6 AM", ?DATE)),
|
||||
?_assertEqual({{2008,8,2}, {6,35,0}},
|
||||
parse("August/2/2008 6:35 AM", ?DATE)),
|
||||
?_assertEqual({{2008,8,2}, {6,35,0}},
|
||||
parse("2 August 2008 6:35 AM", ?DATE)),
|
||||
?_assertEqual({{2008,8,2}, {6,0,0}},
|
||||
parse("2 Aug 2008 6AM", ?DATE)),
|
||||
?_assertEqual({{2008,8,2}, {6,35,0}},
|
||||
parse("2 Aug 2008 6:35AM", ?DATE)),
|
||||
?_assertEqual({{2008,8,2}, {6,35,0}},
|
||||
parse("2 Aug 2008 6:35 AM", ?DATE)),
|
||||
?_assertEqual({{2008,8,2}, {6,0,0}},
|
||||
parse("2 Aug 2008 6", ?DATE)),
|
||||
?_assertEqual({{2008,8,2}, {6,35,0}},
|
||||
parse("2 Aug 2008 6:35", ?DATE)),
|
||||
?_assertEqual({{2008,8,2}, {18,35,0}},
|
||||
parse("2 Aug 2008 6:35 PM", ?DATE)),
|
||||
?_assertEqual({{2008,8,2}, {18,0,0}},
|
||||
parse("2 Aug 2008 6 PM", ?DATE)),
|
||||
?_assertEqual({{2008,8,2}, {18,0,0}},
|
||||
parse("Aug 2, 2008 6 PM", ?DATE)),
|
||||
?_assertEqual({{2008,8,2}, {18,0,0}},
|
||||
parse("August 2nd, 2008 6:00 PM", ?DATE)),
|
||||
?_assertEqual({{2008,8,2}, {18,15,15}},
|
||||
parse("August 2nd 2008, 6:15:15pm", ?DATE)),
|
||||
?_assertEqual({{2008,8,2}, {18,15,15}},
|
||||
parse("August 2nd, 2008, 6:15:15pm", ?DATE)),
|
||||
?_assertEqual({{2008,8,2}, {18,15,0}},
|
||||
parse("Aug 2nd 2008, 18:15", ?DATE)),
|
||||
?_assertEqual({{2012,12,10}, {0,0,0}},
|
||||
parse("Dec 10th, 2012, 12:00 AM", ?DATE)),
|
||||
?_assertEqual({{2012,12,10}, {0,0,0}},
|
||||
parse("10 Dec 2012 12:00 AM", ?DATE)),
|
||||
?_assertEqual({{2001,3,10}, {11,15,0}},
|
||||
parse("11:15", ?DATE)),
|
||||
?_assertEqual({{2001,3,10}, {1,15,0}},
|
||||
|
@ -778,3 +915,19 @@ ms_test_() ->
|
|||
"2001-03-10T15:16:17.123456"),
|
||||
?_assertEqual(Now, nparse(format("Y-m-d\\TH:i:s.f", Now)))
|
||||
].
|
||||
|
||||
zulu_test_() ->
|
||||
[
|
||||
?_assertEqual(format("Y-m-d\\TH:i:sZ",nparse("2001-03-10T15:16:17.123456")),
|
||||
"2001-03-10T15:16:17Z"),
|
||||
?_assertEqual(format("Y-m-d\\TH:i:s",nparse("2001-03-10T15:16:17Z")),
|
||||
"2001-03-10T15:16:17"),
|
||||
?_assertEqual(format("Y-m-d\\TH:i:s",nparse("2001-03-10T15:16:17+04")),
|
||||
"2001-03-10T11:16:17"),
|
||||
?_assertEqual(format("Y-m-d\\TH:i:s",nparse("2001-03-10T15:16:17+04:00")),
|
||||
"2001-03-10T11:16:17"),
|
||||
?_assertEqual(format("Y-m-d\\TH:i:s",nparse("2001-03-10T15:16:17-04")),
|
||||
"2001-03-10T19:16:17"),
|
||||
?_assertEqual(format("Y-m-d\\TH:i:s",nparse("2001-03-10T15:16:17-04:00")),
|
||||
"2001-03-10T19:16:17")
|
||||
].
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
mkdir_p/1,
|
||||
find/2,
|
||||
is_symlink/1,
|
||||
type/1,
|
||||
real_dir_path/1,
|
||||
remove/1,
|
||||
remove/2,
|
||||
md5sum/1,
|
||||
|
@ -115,7 +117,31 @@ is_symlink(Path) ->
|
|||
_ ->
|
||||
false
|
||||
end.
|
||||
|
||||
%% @doc returns the type of the file.
|
||||
-spec type(file:name()) -> file | symlink | directory.
|
||||
type(Path) ->
|
||||
case filelib:is_regular(Path) of
|
||||
true ->
|
||||
file;
|
||||
false ->
|
||||
case is_symlink(Path) of
|
||||
true ->
|
||||
symlink;
|
||||
false ->
|
||||
directory
|
||||
end
|
||||
end.
|
||||
%% @doc gets the real path of a directory. This is mostly useful for
|
||||
%% resolving symlinks. Be aware that this temporarily changes the
|
||||
%% current working directory to figure out what the actual path
|
||||
%% is. That means that it can be quite slow.
|
||||
-spec real_dir_path(file:name()) -> file:name().
|
||||
real_dir_path(Path) ->
|
||||
{ok, CurCwd} = file:get_cwd(),
|
||||
ok = file:set_cwd(Path),
|
||||
{ok, RealPath} = file:get_cwd(),
|
||||
ok = file:set_cwd(CurCwd),
|
||||
filename:absname(RealPath).
|
||||
|
||||
%% @doc make a unique temorory directory. Similar function to BSD stdlib
|
||||
%% function of the same name.
|
||||
|
@ -334,6 +360,21 @@ exists_test() ->
|
|||
?assertMatch(true, exists(Name1)),
|
||||
?assertMatch(false, exists(NoName)).
|
||||
|
||||
real_path_test() ->
|
||||
BaseDir = "foo",
|
||||
Dir = filename:absname(filename:join(BaseDir, "source1")),
|
||||
LinkDir = filename:join([BaseDir, "link"]),
|
||||
ok = mkdir_p(Dir),
|
||||
file:make_symlink(Dir, LinkDir),
|
||||
?assertEqual(Dir, real_dir_path(LinkDir)),
|
||||
?assertEqual(directory, type(Dir)),
|
||||
?assertEqual(symlink, type(LinkDir)),
|
||||
TermFile = filename:join(BaseDir, "test_file"),
|
||||
ok = write_term(TermFile, foo),
|
||||
?assertEqual(file, type(TermFile)),
|
||||
?assertEqual(true, is_symlink(LinkDir)),
|
||||
?assertEqual(false, is_symlink(Dir)).
|
||||
|
||||
find_test() ->
|
||||
%% Create a directory in /tmp for the test. Clean everything afterwards
|
||||
{BaseDir, _SourceDir, {Name1, Name2, Name3, _NoName}} = setup_base_and_target(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue