separated out rule and date logic. WIP: flattening the data, absolute from fuzzy dates, comparing dates
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -3,3 +3,6 @@
|
|||||||
ebin/
|
ebin/
|
||||||
tmp/
|
tmp/
|
||||||
commit_msg
|
commit_msg
|
||||||
|
tzdata/
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
33
Makefile
33
Makefile
@@ -1,22 +1,24 @@
|
|||||||
ERLC_WARNINGS = -W1
|
ERLC_WARNINGS := -W1
|
||||||
MNESIA_DIR = db
|
MNESIA_DIR := db
|
||||||
RUN_INIT =
|
RUN_INIT :=
|
||||||
DEBUG = +debug_info -Ddebug
|
DEBUG := +debug_info -Ddebug
|
||||||
TEST =
|
TEST :=
|
||||||
|
TZSET := northamerica
|
||||||
|
SHELL := /bin/bash
|
||||||
|
|
||||||
all : clean compile
|
all : clean compile
|
||||||
|
|
||||||
nowarn : ERLC_WARNINGS = -W0
|
nowarn : ERLC_WARNINGS = -W0
|
||||||
nowarn : clean compile
|
nowarn : clean compile
|
||||||
|
|
||||||
test : ERLC_WARNINGS = -W0
|
test : ERLC_WARNINGS := -W0
|
||||||
test : TEST := -DTEST
|
test : TEST := -DTEST
|
||||||
test : all
|
test : all
|
||||||
erlc $(ERLC_WARNINGS) $(TEST) -o ./ebin ./tests/*.erl
|
erlc $(ERLC_WARNINGS) $(TEST) -o ./ebin ./test/*.erl
|
||||||
erl -noshell -pa ebin -s test_master start -s erlang halt
|
erl -noshell -pa ebin -run test all -s erlang halt
|
||||||
|
|
||||||
compile :
|
compile :
|
||||||
erlc $(DEBUG) $(ERLC_WARNINGS) $(OPTIONS) -o ./ebin ./src/*.erl
|
erlc $(DEBUG) $(TEST) $(ERLC_WARNINGS) $(OPTIONS) -o ./ebin ./src/*.erl
|
||||||
-erl -noshell -pa ebin -s erldev make_app . -s erlang halt
|
-erl -noshell -pa ebin -s erldev make_app . -s erlang halt
|
||||||
|
|
||||||
clean :
|
clean :
|
||||||
@@ -28,3 +30,16 @@ run :
|
|||||||
|
|
||||||
build : DEBUG =
|
build : DEBUG =
|
||||||
build : all
|
build : all
|
||||||
|
|
||||||
|
|
||||||
|
devstart : RUN_INIT = -s ezic dev_start
|
||||||
|
devstart : all run
|
||||||
|
|
||||||
|
|
||||||
|
tzdata :
|
||||||
|
-cat priv/tzdata/$(TZSET) | sed '/\s*\#/d' | sed '/^\s*$$/d' | less -S
|
||||||
|
|
||||||
|
|
||||||
|
diff :
|
||||||
|
-git diff > /tmp/ezic.tmp.diff
|
||||||
|
emacs /tmp/ezic.tmp.diff
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
-record(rule, {name, from, to, type, in, on, at, save, letters}).
|
-record(rule, {name, from, to, type, in, on, at, save, letters}).
|
||||||
|
|
||||||
|
|
||||||
-record(zone, {name, gmtoff, rules, format, until}).
|
-record(zone, {name, gmtoff, rule, format, until}).
|
||||||
|
|
||||||
|
|
||||||
-record(link, {from, to}).
|
-record(link, {from, to}).
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
-record(leap, {datetime, corr, rs}).
|
-record(leap, {datetime, corr, rs}).
|
||||||
|
|
||||||
|
|
||||||
-record(tztime, {time, flag}).
|
-record(tztime, {time={0,0,0}, flag}).
|
||||||
-record(tzon, {day, filter}).
|
-record(tzon, {day, filter}).
|
||||||
|
|
||||||
|
|
||||||
@@ -27,3 +27,7 @@
|
|||||||
-else.
|
-else.
|
||||||
-define(debug(F,X), void).
|
-define(debug(F,X), void).
|
||||||
-endif.
|
-endif.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,19 @@
|
|||||||
-module(ezic).
|
-module(ezic).
|
||||||
|
|
||||||
-export([load/1, time2time/3]).
|
-export([load/1, time2time/3]).
|
||||||
|
-export([dev_start/0]).
|
||||||
|
|
||||||
|
|
||||||
load(Folder) ->
|
load(Folder) ->
|
||||||
ezic_loader:load(Folder).
|
ezic_loader:load(Folder).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
time2time(_DateTime, _FromTimeZone, _ToTimeZone) ->
|
time2time(_DateTime, _FromTimeZone, _ToTimeZone) ->
|
||||||
void.
|
void.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
dev_start() ->
|
||||||
|
ezic:load(filename:join("priv","tzdata")).
|
||||||
|
|||||||
131
src/ezic_compile.erl
Normal file
131
src/ezic_compile.erl
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
-module(ezic_compile).
|
||||||
|
-include("include/ezic.hrl").
|
||||||
|
|
||||||
|
-export([flatten/2, separate/1, zone_sorter/2]).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
% @todo figure out what to do with leap seconds
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
separate(Records) ->
|
||||||
|
Zones= [Z || Z=#zone{} <- Records],
|
||||||
|
Rules= [Z || Z=#rule{} <- Records],
|
||||||
|
Leaps= [Z || Z=#leap{} <- Records],
|
||||||
|
Links= [Z || Z=#link{} <- Records],
|
||||||
|
{ok, Zones, Rules, Leaps, Links}.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
% FLATTENING PSEUDOCODE
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
% args: Zones, Rules
|
||||||
|
%
|
||||||
|
% take the first zone, get all zones with the same name
|
||||||
|
% sort them by descending date (newest first)
|
||||||
|
% foreach zone:
|
||||||
|
% find all rules between start & end(if exists) of zone
|
||||||
|
% foreach rule:
|
||||||
|
% create a #flatzone
|
||||||
|
% flatten the rest of the zones
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
|
||||||
|
% note: recursive
|
||||||
|
flatten([], Rules) ->
|
||||||
|
done;
|
||||||
|
flatten(Zones, Rules) ->
|
||||||
|
[Zone | _] = Zones,
|
||||||
|
% ?debug("Zone: ~p", [Zone]),
|
||||||
|
?debug("Flattening: ~p", [Zone#zone.name]),
|
||||||
|
|
||||||
|
{ZoneSet, RestZones} = lists:splitwith(make_zone_filter(Zone), Zones),
|
||||||
|
% ?debug("ZoneSet: ~p", [ZoneSet]),
|
||||||
|
|
||||||
|
|
||||||
|
NeededRules= lists:takewhile(make_rule_zone_filter(Zone), Rules),
|
||||||
|
% ?debug("NeededRules: ~p", [NeededRules]),
|
||||||
|
|
||||||
|
SortedZoneSet= lists:sort(fun zone_sorter/2, ZoneSet),
|
||||||
|
|
||||||
|
flatten_set(SortedZoneSet, NeededRules),
|
||||||
|
?debug("Sorted Zones: ~p", [SortedZoneSet]),
|
||||||
|
|
||||||
|
flatten(RestZones, Rules).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
zone_sorter(Z1=#zone{until=U1},#zone{until=U2}) ->
|
||||||
|
ezic_record:compare_datetimes(U1, U2).
|
||||||
|
|
||||||
|
|
||||||
|
%% case (D1 =< D2) of
|
||||||
|
%% true ->
|
||||||
|
%% true;
|
||||||
|
%% false ->
|
||||||
|
%% ezic_record:compare_time(T1, T2)
|
||||||
|
%% end.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
% INTERNAL
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
|
||||||
|
% filter generators
|
||||||
|
make_zone_filter(#zone{name=Name}) ->
|
||||||
|
fun(#zone{name=N}) when Name=:=N-> true; (_)->false end.
|
||||||
|
|
||||||
|
|
||||||
|
make_rule_zone_filter(#zone{rule=Rule}) ->
|
||||||
|
fun(#rule{name=Rule})-> true; (_)->false end.
|
||||||
|
|
||||||
|
|
||||||
|
make_rule_time_filter(D1, D2) ->
|
||||||
|
fun(#rule{from=F, to=T}) ->
|
||||||
|
GoodFrom= ezic_record:compare_datetimes(D1, F) =:= true
|
||||||
|
andalso ezic_record:compare_datetimes(F, D2) =:= true,
|
||||||
|
GoodTo= ezic_record:compare_datetimes(D1, T) =:= true
|
||||||
|
andalso ezic_record:compare_datetimes(T, D2) =:= true,
|
||||||
|
GoodFrom orelse GoodTo
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
% note: recursive
|
||||||
|
flatten_set([], Rules) ->
|
||||||
|
done;
|
||||||
|
flatten_set(ZoneSet, Rules) ->
|
||||||
|
[Zone|Rest] = ZoneSet,
|
||||||
|
NextZone= next_zone(Rest),
|
||||||
|
|
||||||
|
flatten_one(Zone, NextZone, Rules),
|
||||||
|
flatten_set(Rest, Rules).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
flatten_one(Zone=#zone{until=Until}, none, Rules) ->
|
||||||
|
NeededRules= lists:takewhile(make_rule_time_filter({0,0,0}, Until), Rules),
|
||||||
|
lists:foreach(fun(R)-> flatten_each(Zone, R) end, Rules);
|
||||||
|
flatten_one(Zone=#zone{until=UTo}, NextZone=#zone{until=UFrom}, Rules) ->
|
||||||
|
NeededRules= lists:takewhile(make_rule_time_filter(UFrom, UTo), Rules),
|
||||||
|
lists:foreach(fun(R)-> flatten_each(Zone, R) end, Rules).
|
||||||
|
|
||||||
|
|
||||||
|
flatten_each(Zone, Rule) ->
|
||||||
|
not_done.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
next_zone([]) ->
|
||||||
|
none;
|
||||||
|
next_zone([H|T]) ->
|
||||||
|
H.
|
||||||
|
|
||||||
|
|
||||||
149
src/ezic_date.erl
Normal file
149
src/ezic_date.erl
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
-module(ezic_date).
|
||||||
|
-include("include/ezic.hrl").
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-ifdef(TEST).
|
||||||
|
-compile([export_all]).
|
||||||
|
-endif.
|
||||||
|
|
||||||
|
|
||||||
|
-export([for/2]).
|
||||||
|
-export([month_to_num/1, day_to_num/1]).
|
||||||
|
-export([compare_times/2, compare_dates/2, compare_datetimes/2]).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
% returns the concrete date tuple for a given rule and year
|
||||||
|
for(#rule{in=M, on={last, D}}, Y) ->
|
||||||
|
last_day_of(D, Y,M);
|
||||||
|
for(#rule{in=M, on=#tzon{day=Day, filter=Filter}}, Y) ->
|
||||||
|
first_day_limited(Day, Filter, Y,M).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
last_day_of(Day, Y,M) ->
|
||||||
|
LastDay= calendar:last_day_of_the_month(Y,M),
|
||||||
|
previous_day(Day, {Y,M,LastDay}).
|
||||||
|
|
||||||
|
|
||||||
|
first_day_limited(Day, {geq, N}, Y,M) ->
|
||||||
|
next_day(Day, {Y,M,N});
|
||||||
|
first_day_limited(Day, {leq, N}, Y,M) ->
|
||||||
|
previous_day(Day, {Y,M,N}).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
previous_day(Day, Date={Y,M,D}) ->
|
||||||
|
Daynum= day_to_num(Day),
|
||||||
|
LeqDoW= calendar:day_of_the_week(Date),
|
||||||
|
case Daynum=:=LeqDoW of
|
||||||
|
true -> Date;
|
||||||
|
_ ->
|
||||||
|
DayDiff= case LeqDoW-Daynum < 0 of
|
||||||
|
true -> LeqDoW-Daynum+7;
|
||||||
|
_ -> LeqDoW-Daynum
|
||||||
|
end,
|
||||||
|
case D-DayDiff < 0 of
|
||||||
|
true -> erlang:error(no_previous_day, [Day, Date]);
|
||||||
|
false -> {Y,M,D-DayDiff}
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
next_day(Day, Date={Y,M,D}) ->
|
||||||
|
Daynum= day_to_num(Day),
|
||||||
|
LeqDoW= calendar:day_of_the_week(Date),
|
||||||
|
case Daynum=:=LeqDoW of
|
||||||
|
true -> Date;
|
||||||
|
_ ->
|
||||||
|
DayDiff= case Daynum-LeqDoW < 0 of
|
||||||
|
true -> Daynum-LeqDoW+7;
|
||||||
|
_ -> Daynum-LeqDoW
|
||||||
|
end,
|
||||||
|
case D+DayDiff > calendar:last_day_of_the_month(Y,M) of
|
||||||
|
true -> erlang:error(no_next_day, [Day, Date]);
|
||||||
|
false -> {Y,M,D+DayDiff}
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
month_to_num("Jan") -> 1;
|
||||||
|
month_to_num("Feb") -> 2;
|
||||||
|
month_to_num("Mar") -> 3;
|
||||||
|
month_to_num("Apr") -> 4;
|
||||||
|
month_to_num("May") -> 5;
|
||||||
|
month_to_num("Jun") -> 6;
|
||||||
|
month_to_num("Jul") -> 7;
|
||||||
|
month_to_num("Aug") -> 8;
|
||||||
|
month_to_num("Sep") -> 9;
|
||||||
|
month_to_num("Oct") -> 10;
|
||||||
|
month_to_num("Nov") -> 11;
|
||||||
|
month_to_num("Dec") -> 12;
|
||||||
|
month_to_num(X) -> erlang:error(badMonth, X).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
day_to_num("Mon") -> 1;
|
||||||
|
day_to_num("Tue") -> 2;
|
||||||
|
day_to_num("Wed") -> 3;
|
||||||
|
day_to_num("Thu") -> 4;
|
||||||
|
day_to_num("Fri") -> 5;
|
||||||
|
day_to_num("Sat") -> 6;
|
||||||
|
day_to_num("Sun") -> 7;
|
||||||
|
day_to_num(_) -> -1.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
% returns true if A =< B, false otherwise
|
||||||
|
compare_datetimes(_, current) ->
|
||||||
|
true;
|
||||||
|
compare_datetimes(current,_) ->
|
||||||
|
false;
|
||||||
|
|
||||||
|
compare_datetimes(D1={_,_,_}, D2={_,_,_}) ->
|
||||||
|
compare_dates(D1, D2);
|
||||||
|
|
||||||
|
compare_datetimes(D1={_,_,_}, DT2={_, #tztime{}}) ->
|
||||||
|
compare_datetimes({D1, #tztime{}}, DT2);
|
||||||
|
|
||||||
|
compare_datetimes(DT1={_, #tztime{}}, D2={_,_,_}) ->
|
||||||
|
compare_datetimes(DT1, {D2, #tztime{}});
|
||||||
|
|
||||||
|
compare_datetimes({D1, T1}, {D2, T2}) ->
|
||||||
|
case compare_dates(D1, D2) of
|
||||||
|
false -> % D1 > D2
|
||||||
|
false;
|
||||||
|
true -> % D1 =< D2
|
||||||
|
case D1 =:= D2 of
|
||||||
|
false -> % D1 < D2
|
||||||
|
true;
|
||||||
|
true -> % D1 = D2
|
||||||
|
compare_times(T1, T2)
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
compare_dates(D1={_,_,_}, D2={_,_,_}) ->
|
||||||
|
D1 =< D2.
|
||||||
|
|
||||||
|
|
||||||
|
compare_times(TZ1=#tztime{}, TZ2=#tztime{}) ->
|
||||||
|
{NT1, NT2} = time_normalize(TZ1, TZ2),
|
||||||
|
NT1 =< NT2;
|
||||||
|
compare_times(T1, T2) ->
|
||||||
|
T1 =< T2.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
time_normalize(#tztime{time=T1, flag=F1}, #tztime{time=T2, flag=F2}) when F1=:=F2 ->
|
||||||
|
{T1, T2};
|
||||||
|
time_normalize(T1, T2) ->
|
||||||
|
%@todo this may be difficult. gotta do it!
|
||||||
|
erlang:error(wtf_not_done, T1, T2).
|
||||||
|
|
||||||
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
-module(ezic_loader).
|
-module(ezic_loader).
|
||||||
-include("include/ezic.hrl").
|
-include("include/ezic.hrl").
|
||||||
|
|
||||||
-export([load/1]).
|
-export([load/1]).
|
||||||
|
|
||||||
|
|
||||||
@@ -12,7 +13,8 @@ load(File) ->
|
|||||||
false -> {error, {badFile, File}}
|
false -> {error, {badFile, File}}
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
flatten(Records).
|
{ok, Zones, Rules, Leaps, Links} = ezic_compile:separate(Records),
|
||||||
|
ezic_compile:flatten(Zones, Rules).
|
||||||
% @todo store in mnesia
|
% @todo store in mnesia
|
||||||
|
|
||||||
|
|
||||||
@@ -52,7 +54,7 @@ parse_lines({ok, Line}, File, Records) ->
|
|||||||
|
|
||||||
|
|
||||||
parse_lines_2(Line, File, Records) ->
|
parse_lines_2(Line, File, Records) ->
|
||||||
?debug("Line: ~p", [Line]),
|
%?debug("Line: ~p", [Line]),
|
||||||
[Type | Data] = string:tokens(Line, " \t"),
|
[Type | Data] = string:tokens(Line, " \t"),
|
||||||
{ok, PrevType, PrevName} = prev_rec_type(Records),
|
{ok, PrevType, PrevName} = prev_rec_type(Records),
|
||||||
{ok, Record} = build_record(Type, Data, {PrevType, PrevName}),
|
{ok, Record} = build_record(Type, Data, {PrevType, PrevName}),
|
||||||
@@ -94,8 +96,3 @@ build_record("Leap", Data,_) ->
|
|||||||
build_record(Type, Data, PT) ->
|
build_record(Type, Data, PT) ->
|
||||||
{error, {badLine, Type, Data, PT}}.
|
{error, {badLine, Type, Data, PT}}.
|
||||||
|
|
||||||
|
|
||||||
% converts tzdata records to flattened records
|
|
||||||
% returns list of #flatzone{}
|
|
||||||
flatten(Records) when is_list(Records) ->
|
|
||||||
Records.
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ rule([Name,FromS,ToS,Type,InS,OnS,AtS,SaveS,Letters]) ->
|
|||||||
From= parse_from(FromS),
|
From= parse_from(FromS),
|
||||||
To= parse_to(ToS),
|
To= parse_to(ToS),
|
||||||
% @todo handle year types
|
% @todo handle year types
|
||||||
In= month_to_num(InS),
|
In= ezic_date:month_to_num(InS),
|
||||||
On= parse_on(OnS),
|
On= parse_on(OnS),
|
||||||
At=parse_at(AtS),
|
At=parse_at(AtS),
|
||||||
Save=parse_save(SaveS),
|
Save=parse_save(SaveS),
|
||||||
@@ -27,13 +27,13 @@ rule([Name,FromS,ToS,Type,InS,OnS,AtS,SaveS,Letters]) ->
|
|||||||
}}.
|
}}.
|
||||||
|
|
||||||
|
|
||||||
zone([Name,GmtOffS,Rules,FormatS | UntilTokens]) ->
|
zone([Name,GmtOffS,Rule,FormatS | UntilTokens]) ->
|
||||||
GmtOff=parse_time(GmtOffS),
|
GmtOff=parse_time(GmtOffS),
|
||||||
Until = parse_until(UntilTokens),
|
Until = parse_until(UntilTokens),
|
||||||
Format= convert_format(FormatS),
|
Format= convert_format(FormatS),
|
||||||
|
|
||||||
{ok, #zone{
|
{ok, #zone{
|
||||||
name=Name, gmtoff=GmtOff, rules=Rules,
|
name=Name, gmtoff=GmtOff, rule=Rule,
|
||||||
format=Format, until=Until
|
format=Format, until=Until
|
||||||
}}.
|
}}.
|
||||||
|
|
||||||
@@ -44,13 +44,14 @@ link([From,To]) ->
|
|||||||
|
|
||||||
leap([YearS, MonthS, DayS, TimeS, Corr, RS]) ->
|
leap([YearS, MonthS, DayS, TimeS, Corr, RS]) ->
|
||||||
Y=list_to_integer(YearS),
|
Y=list_to_integer(YearS),
|
||||||
M=month_to_num(MonthS),
|
M=ezic_date:month_to_num(MonthS),
|
||||||
D=list_to_integer(DayS),
|
D=list_to_integer(DayS),
|
||||||
Time=parse_abs_time(TimeS),
|
Time=parse_abs_time(TimeS),
|
||||||
{ok, #leap{datetime={{Y,M,D}, Time}}}.
|
{ok, #leap{datetime={{Y,M,D}, Time}}}.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
% PRIVATE
|
% PRIVATE
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
@@ -73,8 +74,8 @@ parse_to(Other) ->
|
|||||||
|
|
||||||
|
|
||||||
parse_on(X=[$l,$a,$s,$t|Day]) ->
|
parse_on(X=[$l,$a,$s,$t|Day]) ->
|
||||||
case is_day(Day) of
|
case ezic_date:day_to_num(Day) > 0 of
|
||||||
true -> list_to_atom(X);
|
true -> {last, Day};
|
||||||
false -> erlang:error(badday,X)
|
false -> erlang:error(badday,X)
|
||||||
end;
|
end;
|
||||||
parse_on(X=[D,A,Y, Sign,$= | IntS]) ->
|
parse_on(X=[D,A,Y, Sign,$= | IntS]) ->
|
||||||
@@ -82,8 +83,8 @@ parse_on(X=[D,A,Y, Sign,$= | IntS]) ->
|
|||||||
Day=[D,A,Y],
|
Day=[D,A,Y],
|
||||||
{ok, FSign} =parse_on_sign(Sign),
|
{ok, FSign} =parse_on_sign(Sign),
|
||||||
|
|
||||||
case is_day(Day) of
|
case ezic_date:day_to_num(Day) > 0 of
|
||||||
true -> #tzon{day=list_to_atom(string:to_lower(Day)), filter={FSign, Int}};
|
true -> #tzon{day=Day, filter={FSign, Int}};
|
||||||
false -> erlang:error(badday, X)
|
false -> erlang:error(badday, X)
|
||||||
end;
|
end;
|
||||||
parse_on(X) ->
|
parse_on(X) ->
|
||||||
@@ -97,16 +98,16 @@ parse_until([YS]) ->
|
|||||||
{Y,1,1};
|
{Y,1,1};
|
||||||
parse_until([YS,MS]) ->
|
parse_until([YS,MS]) ->
|
||||||
Y= list_to_integer(YS),
|
Y= list_to_integer(YS),
|
||||||
M=month_to_num(MS),
|
M= ezic_date:month_to_num(MS),
|
||||||
{Y,M,1};
|
{Y,M,1};
|
||||||
parse_until([YS,MS,DS]) ->
|
parse_until([YS,MS,DS]) ->
|
||||||
Y= list_to_integer(YS),
|
Y= list_to_integer(YS),
|
||||||
M=month_to_num(MS),
|
M= ezic_date:month_to_num(MS),
|
||||||
D= parse_on(DS),
|
D= parse_on(DS),
|
||||||
{Y,M,D};
|
{Y,M,D};
|
||||||
parse_until([YS,MS,DS,TS]) ->
|
parse_until([YS,MS,DS,TS]) ->
|
||||||
Y= list_to_integer(YS),
|
Y= list_to_integer(YS),
|
||||||
M=month_to_num(MS),
|
M= ezic_date:month_to_num(MS),
|
||||||
D= parse_on(DS),
|
D= parse_on(DS),
|
||||||
{{Y,M,D},parse_time(TS)}.
|
{{Y,M,D},parse_time(TS)}.
|
||||||
|
|
||||||
@@ -198,25 +199,3 @@ convert_format(Format, Pos) ->
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
month_to_num("Jan") -> 1;
|
|
||||||
month_to_num("Feb") -> 2;
|
|
||||||
month_to_num("Mar") -> 3;
|
|
||||||
month_to_num("Apr") -> 4;
|
|
||||||
month_to_num("May") -> 5;
|
|
||||||
month_to_num("Jun") -> 6;
|
|
||||||
month_to_num("Jul") -> 7;
|
|
||||||
month_to_num("Aug") -> 8;
|
|
||||||
month_to_num("Sep") -> 9;
|
|
||||||
month_to_num("Oct") -> 10;
|
|
||||||
month_to_num("Nov") -> 11;
|
|
||||||
month_to_num("Dec") -> 12;
|
|
||||||
month_to_num(X) -> erlang:error(badMonth, X).
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
is_day(X) when X=:="Mon";X=:="Tue";X=:="Wed";X=:="Thu";X=:="Fri";X=:="Sat";X=:="Sun" ->
|
|
||||||
true;
|
|
||||||
is_day(_) ->
|
|
||||||
false.
|
|
||||||
|
|
||||||
|
|||||||
13
src/ezic_rule.erl
Normal file
13
src/ezic_rule.erl
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
-module(ezic_rule).
|
||||||
|
-include("include/ezic.hrl").
|
||||||
|
|
||||||
|
|
||||||
|
-export([]).
|
||||||
|
|
||||||
|
|
||||||
|
% returns a list of all {datetime,offset} sets that must be
|
||||||
|
% projected for this Rule.
|
||||||
|
project(Rule=#rule{from=F, to=only}) ->
|
||||||
|
not_done;
|
||||||
|
project(Rule=#rule{from=F, to=T}) ->
|
||||||
|
Dates= lists:map(fun(Y)-> ezic_date:for(Rule, Y) end, lists:seq(F, T)).
|
||||||
35
test/ezic_date_tests.erl
Normal file
35
test/ezic_date_tests.erl
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
-module(ezic_date_tests).
|
||||||
|
-include("include/ezic.hrl").
|
||||||
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
|
||||||
|
prevnext_day_test_() ->
|
||||||
|
[
|
||||||
|
?_assertEqual({2010,11,3}, ezic_date:previous_day("Wed", {2010, 11, 5}))
|
||||||
|
, ?_assertEqual({2010,11,10}, ezic_date:next_day("Wed", {2010, 11, 5}))
|
||||||
|
|
||||||
|
, ?_assertEqual({2010,11,5}, ezic_date:previous_day("Fri", {2010, 11, 5}))
|
||||||
|
, ?_assertEqual({2010,11,5}, ezic_date:next_day("Fri", {2010, 11, 5}))
|
||||||
|
|
||||||
|
, ?_assertEqual({2010,11,5}, ezic_date:previous_day("Fri", {2010, 11, 10}))
|
||||||
|
, ?_assertEqual({2010,11,12}, ezic_date:next_day("Fri", {2010, 11, 10}))
|
||||||
|
|
||||||
|
, ?_assertError(no_previous_day, ezic_date:previous_day("Wed", {2010, 11, 2}))
|
||||||
|
, ?_assertError(no_next_day, ezic_date:next_day("Wed", {2010, 11, 25}))
|
||||||
|
].
|
||||||
|
|
||||||
|
firstlast_day_of_test_() ->
|
||||||
|
[
|
||||||
|
?_assertEqual({2010,11,24}, ezic_date:last_day_of("Wed", 2010, 11))
|
||||||
|
, ?_assertEqual({2010,11,30}, ezic_date:last_day_of("Tue", 2010, 11))
|
||||||
|
|
||||||
|
, ?_assertEqual({2010,11,14}, ezic_date:first_day_limited("Sun", {geq, 8}, 2010, 11))
|
||||||
|
, ?_assertEqual({2010,11,21}, ezic_date:first_day_limited("Sun", {leq, 25}, 2010, 11))
|
||||||
|
].
|
||||||
|
|
||||||
|
|
||||||
|
compare_datetimes_test_() ->
|
||||||
|
[
|
||||||
|
?_assertEqual(false, ezic_date:compare_datetimes(
|
||||||
|
{{1997,3,lastSun},{tztime,{1,0,0},u}}
|
||||||
|
, {1997,1,1} ))
|
||||||
|
].
|
||||||
@@ -70,12 +70,12 @@ parse_on_test_() ->
|
|||||||
[
|
[
|
||||||
?_assertEqual(5, ezic_record:parse_on("5"))
|
?_assertEqual(5, ezic_record:parse_on("5"))
|
||||||
|
|
||||||
, ?_assertEqual(lastSun, ezic_record:parse_on("lastSun"))
|
, ?_assertEqual({last, "Sun"}, ezic_record:parse_on("lastSun"))
|
||||||
, ?_assertEqual(lastMon, ezic_record:parse_on("lastMon"))
|
, ?_assertEqual({last, "Mon"}, ezic_record:parse_on("lastMon"))
|
||||||
, ?_assertError(badday, ezic_record:parse_on("lastFoo"))
|
, ?_assertError(badday, ezic_record:parse_on("lastFoo"))
|
||||||
|
|
||||||
, ?_assertEqual(#tzon{day=sun, filter={geq, 8}}, ezic_record:parse_on("Sun>=8"))
|
, ?_assertEqual(#tzon{day="Sun", filter={geq, 8}}, ezic_record:parse_on("Sun>=8"))
|
||||||
, ?_assertEqual(#tzon{day=sun, filter={leq, 25}}, ezic_record:parse_on("Sun<=25"))
|
, ?_assertEqual(#tzon{day="Sun", filter={leq, 25}}, ezic_record:parse_on("Sun<=25"))
|
||||||
, ?_assertError(badday, ezic_record:parse_on("Foo<=25"))
|
, ?_assertError(badday, ezic_record:parse_on("Foo<=25"))
|
||||||
].
|
].
|
||||||
|
|
||||||
@@ -85,3 +85,6 @@ convert_format_test_() ->
|
|||||||
?_assertEqual("POS", ezic_record:convert_format("POS"))
|
?_assertEqual("POS", ezic_record:convert_format("POS"))
|
||||||
, ?_assertEqual("P~sS", ezic_record:convert_format("P%sS"))
|
, ?_assertEqual("P~sS", ezic_record:convert_format("P%sS"))
|
||||||
].
|
].
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
7
test/test.erl
Normal file
7
test/test.erl
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
-module(test).
|
||||||
|
-export([all/0]).
|
||||||
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
|
||||||
|
all() ->
|
||||||
|
eunit:test(ezic_record),
|
||||||
|
eunit:test(ezic_date).
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
-module(test_master).
|
|
||||||
-export([start/0]).
|
|
||||||
|
|
||||||
start() ->
|
|
||||||
ezic_record:test().
|
|
||||||
Reference in New Issue
Block a user