From d00937c3e914022447f4cdcaa79255c39bd3fca1 Mon Sep 17 00:00:00 2001 From: aj Date: Mon, 8 Nov 2010 01:29:15 -0800 Subject: [PATCH] lots of gutting. purposes, input, and output were unclear in many places. still broken. --- notes/flatten_pseudocode.svg | 340 +++++++++++++++++++++++++++++++++++ src/ezic.erl | 40 +---- src/ezic_date.erl | 315 ++++++++++++++------------------ src/ezic_flatten.erl | 12 +- src/ezic_loader.erl | 32 ++-- src/ezic_parse.erl | 162 +++++++++++++++++ src/ezic_record.erl | 190 +------------------- src/ezic_rule.erl | 32 +++- src/ezic_zone.erl | 38 +++- test/ezic_date_tests.erl | 48 ++--- test/ezic_parse_tests.erl | 76 ++++++++ test/ezic_record_tests.erl | 86 --------- test/test.erl | 9 +- 13 files changed, 828 insertions(+), 552 deletions(-) create mode 100644 notes/flatten_pseudocode.svg create mode 100644 src/ezic_parse.erl create mode 100644 test/ezic_parse_tests.erl diff --git a/notes/flatten_pseudocode.svg b/notes/flatten_pseudocode.svg new file mode 100644 index 0000000..1fdb68b --- /dev/null +++ b/notes/flatten_pseudocode.svg @@ -0,0 +1,340 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + All Zones + + + One Zone + + Its Rules + foreach zone get its rules + + + + + + + + + + + + + + One Rule + foreach rule and zone convert datetime to UTC -using zoneinfo + + + + diff --git a/src/ezic.erl b/src/ezic.erl index 385f95c..52f5dcc 100644 --- a/src/ezic.erl +++ b/src/ezic.erl @@ -4,22 +4,16 @@ -export([ localtime/1 , utc_to_local/2 -% , local_to_utc/2 -% , zone_convert/3 , next_timechange/1 - , next_timechange/2 + , next_timechange_after/2 ]). -export([load/1, dev_start/0, test/0]). --define(gs2dt(X), calendar:gregorian_seconds_to_datetime(X)). --define(dt2gs(X), calendar:datetime_to_gregorian_seconds(X)). - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% API +% PUBLIC API %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -27,30 +21,17 @@ localtime(TzName) -> utc_to_local(erlang:universaltime(), TzName). - utc_to_local(UTCDatetime, TzName) -> {ok, Zone, Rule}= current_as_of_utc(UTCDatetime, TzName), SecDiff= time_offset(Zone, Rule), - date_add(UTCDatetime, SecDiff). + ezic_date:add_seconds(UTCDatetime, SecDiff). -%% local_to_utc(Datetime, TzName) -> -%% {ok, Zone, Rule}= current_as_of_local(Datetime, TzName), -%% SecDiff= time_offset(Zone, Rule), -%% date_subtract(Datetime, SecDiff). - - -%% zone_convert(Datetime, FromTimeZone, ToTimeZone) -> -%% UTC= local_to_utc(Datetime, FromTimeZone), -%% utc_to_local(UTC, ToTimeZone). - - next_timechange(TzName) -> - next_timechange(erlang:universaltime(), TzName). + next_timechange_after(erlang:universaltime(), TzName). -next_timechange(UTCDatetime, TzName) -> - UTCDatetime, TzName, +next_timechange_after(_UTCDatetime, _TzName) -> not_done. @@ -64,8 +45,7 @@ next_timechange(UTCDatetime, TzName) -> load(Folder) -> - ezic_loader:load(Folder), - ezic_flatten:flatten(). + ezic_loader:load(Folder). dev_start() -> @@ -103,11 +83,3 @@ time_offset(Zone, Rule) -> DSTSec= ezic_rule:dst_sec(Rule), OffsetSec + DSTSec. - - -date_add(Datetime, SecDiff) -> - ?gs2dt(?dt2gs(Datetime) + SecDiff). - -%% date_subtract(Datetime, SecDiff) -> -%% ?gs2dt(?dt2gs(Datetime) - SecDiff). - diff --git a/src/ezic_date.erl b/src/ezic_date.erl index 34730e0..f1675b6 100644 --- a/src/ezic_date.erl +++ b/src/ezic_date.erl @@ -1,86 +1,52 @@ -module(ezic_date). -include("include/ezic.hrl"). +-include_lib("eunit/include/eunit.hrl"). --ifdef(TEST). --compile([export_all]). --endif. +-export([ + % rule-specific + for_rule/2 + , for_rule_zone/3 + + + % converters + , month_to_num/1 + , day_to_num/1 + + + % date math + , add_seconds/2 + , all_times/3 + ]). - --export([for/2]). --export([month_to_num/1, day_to_num/1]). --export([compare_times/2, compare_datetimes/2, normalize/1, overlap/2, date_between/2]). - --export([add_seconds/2, all_times/3]). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% PUBLIC API +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - - -% returns the date tuple for a given rule and year -% same for all timezones. -% e.g. -> {Y,M,D} -for(#rule{in=M, on={last, D}}, Y) -> +% returns {Y,M,D} for a rule and Year +for_rule(#rule{in=M, on={last, D}}, Y) -> last_day_of(D, Y,M); -for(#rule{in=M, on=#tzon{day=Day, filter=Filter}}, Y) -> +for_rule(#rule{in=M, on=#tzon{day=Day, filter=Filter}}, Y) -> first_day_limited(Day, Filter, Y,M). -% returns the date on which the last Day (sun,mon,tue,etc.) occurs in a given month/year -% same for all timezones -last_day_of(Day, Y,M) -> - LastDay= calendar:last_day_of_the_month(Y,M), - previous_day(Day, {Y,M,LastDay}). -% returns a date tuple {Y,M,D} representing the first available date, given the filter -% same for all timezones -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}). +% for_rule(#rule{}, Zone, Year) -> {WallTime, STDTime, UTCTime} +% returns the date set for a given rule and year +% same for all timezones. +for_rule_zone(#rule{in=M, on={last, D}, at=_Time, save=_DSTOffset}, _Zone=#zone{gmtoff=_Offset}, Y) -> + _LDO= last_day_of(D, Y,M), + not_done; +for_rule_zone(#rule{in=M, on=#tzon{day=Day, filter=Filter}}, _Zone, Y) -> + first_day_limited(Day, Filter, Y,M), - -% Returns the soonest date on which Day (sun/mon/tue/etc.) occurs BEFORE the given date. -% same for all timezones -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. - - -% Returns the soonest date on which Day (sun/mon/tue/etc.) occurs AFTER the given date. -% same for all timezones -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. + not_done. @@ -107,127 +73,18 @@ day_to_num("Thu") -> 4; day_to_num("Fri") -> 5; day_to_num("Sat") -> 6; day_to_num("Sun") -> 7; -day_to_num(_) -> -1. +day_to_num(X) -> erlang:error(badday, X). -compare_datetimes(DT1, DT2) -> - NDT1= normalize(DT1), - NDT2= normalize(DT2), - compare_datetimes_normal(NDT1, NDT2). - - -compare_datetimes_normal(minimum, _) -> true; -compare_datetimes_normal(_, maximum) -> true; - - -compare_datetimes_normal(current, current) -> true; -compare_datetimes_normal(current, _) -> false; -compare_datetimes_normal(_,current) -> true; - -% @bug this is not true if the times are from different time zones -% @todo check types for D1 and D2 -compare_datetimes_normal({D1, _}, {D2, _}) when D1 < D2 -> - true; -compare_datetimes_normal({D1, _}, {D2, _}) when D1 > D2 -> - false; -compare_datetimes_normal({_, T1}, {_, T2}) -> - compare_times(T1, T2). - - -compare_times(TZ1=#tztime{}, TZ2=#tztime{}) -> - {NT1, NT2} = time_equalize(TZ1, TZ2), - NT1 =< NT2; -compare_times(Tz1, Tz2) -> - erlang:error(wtf_not_done, [Tz1, Tz2]). - - - -time_equalize(#tztime{time=T1, flag=F1}, #tztime{time=T2, flag=F2}) when F1=:=F2 -> - {T1, T2}; -time_equalize(T1, T2) -> - %@todo this may be difficult. gotta do it! - erlang:error(wtf_not_done, T1, T2). - - - -normalize(current) -> current; -normalize(only) -> only; -normalize(maximum) -> maximum; -normalize(minimum) -> minimum; - - -normalize(Y) when is_integer(Y) -> - {{Y,1,1}, #tztime{}}; -normalize(Date={_,_,D}) when is_integer(D) -> - {Date, #tztime{}}; -normalize({Y,M,{last, D}}) -> - Date=last_day_of(D, Y,M), - {Date, #tztime{}}; - - -normalize({Date={_,_,_},Time={H,_,_}}) when is_integer(H) -> - {Date, #tztime{time=Time}}; - -normalize({Date={_,_,D}, Tz=#tztime{}}) when is_integer(D) -> - {Date, Tz}; -normalize({{Y,M,#tzon{day=Day, filter=Filter}}, Tz=#tztime{}}) -> - Date= first_day_limited(Day, Filter, Y,M), - {Date, Tz}; -normalize({{Y,M,{last, D}}, Tz=#tztime{}}) -> - Date=last_day_of(D, Y,M), - {Date, Tz}; -normalize(X) -> - ?debug("normalize: ~p", [X]), - erlang:error(wtf_not_done, X). - - - - -overlap({D1s,D1e}, {D2s,D2e}) -> - D1sN= normalize(D1s), - D1eN= normalize(D1e), - D2sN= normalize(D2s), - D2eN= normalize(D2e), - dates_overlap_normal({D1sN,D1eN}, {D2sN,D2eN}). - - -dates_overlap_normal({D1s,D1e}, {D2s,D2e}) -> - date_between_normal(D1s, {D2s,D2e}) - orelse date_between_normal(D1e, {D2s,D2e}). - - -date_between(D1, {D2s, D2e}) -> - D1N= normalize(D1), - D2sN= normalize(D2s), - D2eN= normalize(D2e), - date_between_normal(D1N, {D2sN, D2eN}). - - -date_between_normal(minimum, {minimum,_}) -> true; -date_between_normal(minimum, {_,_}) -> false; - -date_between_normal(maximum, {_, maximum}) -> true; -date_between_normal(maximum, {_,_}) -> false; - -date_between_normal(only, _) -> false; -date_between_normal(current, {_, current}) -> true; -date_between_normal(current, {_, End}) when End =/= current -> false; -date_between_normal(D1, {D2, only}) -> - {{Y1,_,_},_}=D1, - {{Y2,_,_},_}=D2, - Y1 =:= Y2; -date_between_normal(D1, {D2s, D2e}) -> - compare_datetimes_normal(D2s, D1) - andalso compare_datetimes_normal(D1, D2e). - - - - add_seconds(Datetime, Seconds) -> + try calendar:gregorian_seconds_to_datetime( - calendar:date_to_gregorian_seconds(Datetime) + Seconds - ). + calendar:datetime_to_gregorian_seconds(Datetime) + Seconds + ) + catch + error:Reason -> erlang:error(baddate, Datetime) + end. @@ -237,7 +94,7 @@ add_seconds(Datetime, Seconds) -> % where each is a datetime tuple: {{Y,M,D}{HH,MM,SS}} % universal time given -all_times(Datetime=#tztime{time=UTCTime, flag=Flag}, Offset, DSTOffset) +all_times(#tztime{time=UTCTime, flag=Flag}, Offset, DSTOffset) when Flag=:=u; Flag=:=g; Flag=:=z -> OSec= calendar:time_to_seconds(Offset), DSTSec= calendar:time_to_seconds(DSTOffset), @@ -249,7 +106,7 @@ all_times(Datetime=#tztime{time=UTCTime, flag=Flag}, Offset, DSTOffset) % standard time given -all_times(Datetime=#tztime{time=STDTime, flag=s}, Offset, DSTOffset) -> +all_times(#tztime{time=STDTime, flag=s}, Offset, DSTOffset) -> OSec= calendar:time_to_seconds(Offset), DSTSec= calendar:time_to_seconds(DSTOffset), @@ -260,7 +117,7 @@ all_times(Datetime=#tztime{time=STDTime, flag=s}, Offset, DSTOffset) -> % wall time given -all_times(Datetime=#tztime{time=WallTime, flag=Flag}, Offset, DSTOffset) +all_times(#tztime{time=WallTime, flag=Flag}, Offset, DSTOffset) when Flag=:=w, Flag=:=undefined -> OSec= calendar:time_to_seconds(Offset), DSTSec= calendar:time_to_seconds(DSTOffset), @@ -271,3 +128,93 @@ all_times(Datetime=#tztime{time=WallTime, flag=Flag}, Offset, DSTOffset) {WallTime, STDTime, UTCTime}. + + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% PRIVATE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +% last_day_of(Day, Y,M) -> {Y,M,D} +% returns the date on which the last Day (sun,mon,tue,etc.) occurs in a given month/year +% same for all timezones +last_day_of(Day, Y,M) -> + LastDay= calendar:last_day_of_the_month(Y,M), + previous_day(Day, {Y,M,LastDay}). + + +% returns a date tuple {Y,M,D} representing the first available date, given the filter +% same for all timezones +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}). + + + +% Returns the soonest date on which Day (sun/mon/tue/etc.) occurs BEFORE the given date. +% same for all timezones +previous_day(Day, Date) -> + Daynum= day_to_num(Day), + LeqDoW= calendar:day_of_the_week(Date), + case Daynum=:=LeqDoW of + true -> Date; + _ -> + DayDiff= day_diff(LeqDoW, Daynum), + add_days_in_month(-DayDiff, Date) + end. + + +% Returns the soonest date on which Day (sun/mon/tue/etc.) occurs AFTER the given date. +% same for all timezones +next_day(Day, Date) -> + Daynum= day_to_num(Day), + LeqDoW= calendar:day_of_the_week(Date), + case Daynum=:=LeqDoW of + true -> Date; + _ -> + DayDiff= day_diff(Daynum, LeqDoW), + add_days_in_month(DayDiff, Date) + end. + + +% returns absolute number of days until the next day-of-the-week, +% given some current day-of-the-week. +day_diff(From, To) -> + case From - To < 0 of + true -> From - To + 7; + _ -> From - To + end. + + +% adds/subtracts days within a month +% errors-out if arguments require change of month +add_days_in_month(Days, Date={Y,M,D}) -> + case D+Days < 1 of + true -> erlang:error(no_previous_day, {Days, Date}); + _ -> + case D+Days > calendar:last_day_of_the_month(Y,M) of + true -> erlang:error(no_next_day, {Days, Date}); + _ -> {Y,M,D+Days} + end + end. + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% INTERNAL +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +normalize(_Datetime) -> + not_done. + +compare_normal(_DT1, _DT2) -> + not_done. + diff --git a/src/ezic_flatten.erl b/src/ezic_flatten.erl index de519ba..e4be16c 100644 --- a/src/ezic_flatten.erl +++ b/src/ezic_flatten.erl @@ -74,11 +74,7 @@ flatten_zones([Z1|_]= AllZones, Flats) -> - - - - -% takes zones one-by-one, gathering relevant rules and create flat periods of the same gmt offset (#flatzone) +% takes zones one-by-one, gathering relevant rules and creating flat periods of the same gmt offset (#flatzone) flatten_zone_set(Zones) -> flatten_zone_set(?MINFLAT, Zones, []). @@ -91,20 +87,20 @@ flatten_zone_set(Zones) -> % assumes a new zone every time it is called flatten_zone_set(_, [], Flats) -> Flats; -flatten_zone_set(FromTimeStub, [Z1=#zone{rule=RuleName, until=UntilTime, gmtoff=Offset} | RestZones] = Zones, Flats) -> +flatten_zone_set(FromTimeStub, [Z1=#zone{rule=RuleName, until=UntilTime, gmtoff=Offset} | _RestZones] = _Zones, _Flats) -> %% we have a flatzone with start times, we populate the base offset FromTime= FromTimeStub#flatzone{offset=Offset}, - %% we gather all rules that _may_ apply (same year) Rules= ezic_db:rules(RuleName), RelevantRules= ezic_rule:filter(FromTime, UntilTime, Rules), SortedRules= lists:sort(fun ezic_rule:sort_ascending/2, RelevantRules), + %% Then we plot points, bouncing from rule to rule, ending when the zone ends - {ok, NextFromTimeStub, NewFlats}= flatten_zone(FromTime, Z1, SortedRules), + {ok, _NextFromTimeStub, _NewFlats}= flatten_zone(FromTime, Z1, SortedRules), not_done. diff --git a/src/ezic_loader.erl b/src/ezic_loader.erl index d895381..c3ceadd 100644 --- a/src/ezic_loader.erl +++ b/src/ezic_loader.erl @@ -10,10 +10,10 @@ load(File) -> true -> {ok, parse_dir(File)}; false -> case filelib:is_regular(File) of true -> {ok, parse_file(File)}; - false -> {error, {badFile, File}} + false -> erlang:error(badFile, File) end end, - {ok, Zones, Rules, Leaps, Links} = ezic_compile:separate(Records), + {ok, Zones, Rules, Leaps, Links} = ezic_record:separate(Records), ezic_db:wipe(), ezic_db:init(), @@ -27,12 +27,11 @@ load(File) -> +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% PRIVATE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% INTERNAL -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - % returns a list of tzdata records for all files in folder @@ -56,21 +55,18 @@ parse_lines(eof, _, Records) -> parse_lines({ok, Line}, File, Records) -> StrLine= clean_line(Line), NewRecords= case length(StrLine) > 0 of - false -> Records; - true -> [parse_to_record(StrLine, File, Records) | Records] + true -> [parse_to_record(StrLine, File, Records) | Records]; + false -> Records end, parse_lines(file:read_line(File), File, NewRecords). % the Line has data, so we parse it, build a record, and return it -parse_to_record(Line, File, Records) -> +parse_to_record(Line, _, Records) -> [Type | Data] = string:tokens(Line, " \t"), {ok, PrevType, PrevName} = prev_rec_type(Records), {ok, Record} = build_record(Type, Data, {PrevType, PrevName}), - -% parse_lines(file:read_line(File), File, [Record|Records]). - Record. @@ -88,10 +84,12 @@ prev_rec_type(List) when is_list(List) -> clean_line(Line) -> + %% remove spaces, newlines, and tabs Line1= string:strip(Line), Line2= string:strip(Line1, both, $\n), Line3= string:strip(Line2, both, $\t), + %% remove comments and return FinalLine=Line3, CPos= string:chr(FinalLine, $#), case CPos of @@ -102,18 +100,18 @@ clean_line(Line) -> build_record("Rule", Data,_) -> - ezic_record:rule(Data); + ezic_rule:parse(Data); build_record("Zone", Data,_) -> - ezic_record:zone(Data); + ezic_zone:parse(Data); build_record("Link", Data,_) -> ezic_record:link(Data); -build_record(GmtOff, Data, {"Zone", PrevName}) -> - ezic_record:zone([PrevName,GmtOff|Data]); build_record("Leap", Data,_) -> ezic_record:leap(Data); +build_record(GmtOff, Data, {"Zone", PrevName}) -> + ezic_zone:parse([PrevName,GmtOff|Data]); build_record(Type, Data, PT) -> - {error, {badLine, Type, Data, PT}}. + erlang:error(badLine, {Type, Data, PT}). diff --git a/src/ezic_parse.erl b/src/ezic_parse.erl new file mode 100644 index 0000000..74d9e8b --- /dev/null +++ b/src/ezic_parse.erl @@ -0,0 +1,162 @@ +-module(ezic_parse). +-include("include/ezic.hrl"). + + +-export([ + year/1 + , day_pattern/1 + , time/1 + , time_val/1 + , until/1 + , tz_abbr/1 + ]). + + + +% year(string) to year(int|atom) +year("minimum") -> minimum; +year("min") -> minimum; +year("maximum") -> maximum; +year("max") -> maximum; +year("only") -> only; +year(X) -> + list_to_integer(X). + + + +% X=last(Mon,Tue,Wed,...,Sun) -> {last, (Mon,Tue,Web,...,Sun)} +day_pattern(X=[$l,$a,$s,$t|Day]) -> + case ezic_date:day_to_num(Day) > 0 of + true -> {last, Day}; + false -> erlang:error(badday,X) + end; +% X=(Mon,Tue,Wed,...,Sun)[<>]=int(). +day_pattern(X=[D,A,Y, Sign,$= | IntS]) -> + Int=list_to_integer(IntS), + Day=[D,A,Y], + {ok, FSign}= sign(Sign), + + case ezic_date:day_to_num(Day) > 0 of + true -> #tzon{day=Day, filter={FSign, Int}}; + false -> erlang:error(badday, X) + end; +% X=int() +day_pattern(X) -> + list_to_integer(X). + + + + +time_val(Str) -> + #tztime{time=Time}= time(Str), + Time. + +time("-") -> + #tztime{time={0,0,0}}; +time(TS) -> + {Flag, RTime} = time_flag(TS), + Time= time_abs(RTime), + #tztime{time=Time, flag=Flag}. + + + +until([]) -> + current; +until([YS]) -> + Y= list_to_integer(YS), + {Y,1,1}; +until([YS,MS]) -> + Y= list_to_integer(YS), + M= ezic_date:month_to_num(MS), + {Y,M,1}; +until([YS,MS,DS]) -> + Y= list_to_integer(YS), + M= ezic_date:month_to_num(MS), + D= day_pattern(DS), + {Y,M,D}; +until([YS,MS,DS,TS]) -> + Y= list_to_integer(YS), + M= ezic_date:month_to_num(MS), + D= day_pattern(DS), + {{Y,M,D},ezic_parse:time(TS)}. + + + + +tz_abbr(Format) -> + tz_abbr(Format, string:str(Format, "%s")). + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% PRIVATE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +time_flag(TS) -> + {F, RTime}= time_flag_rev(lists:reverse(TS)), + {F, lists:reverse(RTime)}. + + +% absolute time string (no relativity modifiers) +% e.g. 08:01:03 +time_abs(Time) -> + TTok= string:tokens(Time, ":"), + time_tokens(TTok). + + +time_tokens([HS]) -> + H= list_to_integer(HS), + {H,0,0}; +time_tokens([HS,MS]) -> + H= list_to_integer(HS), + M= list_to_integer(MS), + {H,M,0}; +time_tokens([HS,MS,SS]) -> + H= list_to_integer(HS), + M= list_to_integer(MS), + S= list_to_integer(SS), + {H,M,S}; +time_tokens(X) -> + erlang:error(badtime, X). + + + + +sign($>) -> {ok, geq}; +sign($<) -> {ok, leq}. + + + + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% INTERNAL +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +time_flag_rev([F|RTime]) when F =:= $s; F =:= $w; F =:= $u -> + {list_to_atom([F]), RTime}; +time_flag_rev([F|RTime]) when F =:= $g; F =:= $z -> + {u, RTime}; +time_flag_rev(X=[F|_]) when F-48 < 0; F-48 > 9 -> + erlang:error(badtime, lists:reverse(X)); +time_flag_rev(RTime) -> + {undefined, RTime}. + + + +tz_abbr(Format, 0) -> + Format; +tz_abbr(Format, Pos) -> + First=string:substr(Format, 1, Pos-1), + Last=string:substr(Format, Pos+2), + string:concat(First, [$~, $s|Last]). + + + + + diff --git a/src/ezic_record.erl b/src/ezic_record.erl index 0189ed2..a85eb49 100644 --- a/src/ezic_record.erl +++ b/src/ezic_record.erl @@ -8,46 +8,24 @@ -endif. --export([rule/1,zone/1,link/1,leap/1, separate/1]). +-export([ + link/1 + , leap/1 + , separate/1 + ]). -rule([Name,FromS,ToS,Type,InS,OnS,AtS,SaveS,Letters]) -> - From= parse_from(FromS), - To= parse_to(ToS), - % @todo handle year types - In= ezic_date:month_to_num(InS), - On= parse_on(OnS), - At=parse_at(AtS), - Save=parse_save(SaveS), - - {ok, #rule{ - name=Name, from=From, to=To, type=Type, - in=In, on=On, at=At, save=Save, letters=Letters - }}. - - -zone([Name,GmtOffS,Rule,FormatS | UntilTokens]) -> - GmtOff=parse_time(GmtOffS), - Until = parse_until(UntilTokens), - Format= convert_format(FormatS), - - {ok, #zone{ - name=Name, gmtoff=GmtOff, rule=Rule, - format=Format, until=Until - }}. - - link([From,To]) -> {ok, #link{from=From, to=To}}. % @todo figure out what must be done with leap seconds leap([YearS, MonthS, DayS, TimeS, Corr, RS]) -> - Y=list_to_integer(YearS), - M=ezic_date:month_to_num(MonthS), - D=list_to_integer(DayS), - Time=parse_abs_time(TimeS), + Y= list_to_integer(YearS), + M= ezic_date:month_to_num(MonthS), + D= list_to_integer(DayS), + Time= ezic_parse:time_val(TimeS), {ok, #leap{datetime={{Y,M,D}, Time}, corr=Corr, rs=RS}}. @@ -61,153 +39,3 @@ separate(Records) -> {ok, Zones, Rules, Leaps, Links}. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% PRIVATE -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - -parse_from(X) when X=:="maximum";X=:="max" -> - maximum; -parse_from(X) when X=:="minimum";X=:="min" -> - minimum; -parse_from(Year) -> - list_to_integer(Year). - - - -parse_to("only") -> - only; -parse_to(Other) -> - parse_from(Other). - - - -parse_on(X=[$l,$a,$s,$t|Day]) -> - case ezic_date:day_to_num(Day) > 0 of - true -> {last, Day}; - false -> erlang:error(badday,X) - end; -parse_on(X=[D,A,Y, Sign,$= | IntS]) -> - Int=list_to_integer(IntS), - Day=[D,A,Y], - {ok, FSign} =parse_on_sign(Sign), - - case ezic_date:day_to_num(Day) > 0 of - true -> #tzon{day=Day, filter={FSign, Int}}; - false -> erlang:error(badday, X) - end; -parse_on(X) -> - list_to_integer(X). - - -parse_until([]) -> - current; -parse_until([YS]) -> - Y= list_to_integer(YS), - {Y,1,1}; -parse_until([YS,MS]) -> - Y= list_to_integer(YS), - M= ezic_date:month_to_num(MS), - {Y,M,1}; -parse_until([YS,MS,DS]) -> - Y= list_to_integer(YS), - M= ezic_date:month_to_num(MS), - D= parse_on(DS), - {Y,M,D}; -parse_until([YS,MS,DS,TS]) -> - Y= list_to_integer(YS), - M= ezic_date:month_to_num(MS), - D= parse_on(DS), - {{Y,M,D},parse_time(TS)}. - - - -parse_at(X) -> - parse_time(X). - - - -parse_save("-") -> - parse_time("-"); -parse_save(X) -> - XRev=lists:reverse(X), - parse_save_rev(XRev). - - - -parse_time("-") -> - #tztime{time={0,0,0}}; -parse_time(TS) -> - parse_time_rev(lists:reverse(TS)). - - -parse_abs_time(T) -> - Tokez= string:tokens(T, ":"), - parse_abs_time_2(Tokez). - - - -convert_format(Format) -> - convert_format(Format, string:str(Format, "%s")). - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% INTERNAL -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - -parse_on_sign($>) -> {ok, geq}; -parse_on_sign($<) -> {ok, leq}. - - - - -parse_time_rev([F|RTime]) when F =:= $s; F =:= $w; F =:= $u -> - Time=lists:reverse(RTime), - #tztime{time=parse_abs_time(Time), flag=list_to_atom([F])}; -parse_time_rev(X=[F|_]) when F-48 < 0; F-48 > 9 -> - erlang:error(badtime, X); -parse_time_rev(RTime) -> - Time=lists:reverse(RTime), - #tztime{time=parse_abs_time(Time)}. - - - - -parse_abs_time_2([HS]) -> - H= list_to_integer(HS), - {H,0,0}; -parse_abs_time_2([HS,MS]) -> - H= list_to_integer(HS), - M= list_to_integer(MS), - {H,M,0}; -parse_abs_time_2([HS,MS,SS]) -> - H= list_to_integer(HS), - M= list_to_integer(MS), - S= list_to_integer(SS), - {H,M,S}; -parse_abs_time_2(X) -> - erlang:error(badtime, X). - - - -parse_save_rev(X=[F|_]) when F-48 < 0; F-48 > 9 -> - erlang:error(badsave, lists:reverse(X)); -parse_save_rev(X) -> - parse_time(lists:reverse(X)). - - - -convert_format(Format, 0) -> - Format; -convert_format(Format, Pos) -> - First=string:substr(Format, 1, Pos-1), - Last=string:substr(Format, Pos+2), - string:concat(First, [$~, $s|Last]). - - - - diff --git a/src/ezic_rule.erl b/src/ezic_rule.erl index dc66fa0..b34dc60 100644 --- a/src/ezic_rule.erl +++ b/src/ezic_rule.erl @@ -2,22 +2,40 @@ -include("include/ezic.hrl"). +-export([parse/1]). -export([next_event/4]). +parse([Name,FromS,ToS,_Type,InS,OnS,AtS,SaveS,Letters]) -> + From= ezic_parse:year(FromS), + To= ezic_parse:year(ToS), + + % @todo handle year types + + In= ezic_date:month_to_num(InS), + On= ezic_parse:day_pattern(OnS), + At= ezic_parse:time(AtS), + + Save= ezic_parse:time_val(SaveS), + + Rule= #rule{name=Name, from=From, to=To, type=not_done, + in=In, on=On, at=At, save=Save, letters=Letters}, + {ok, Rule}. + + % determines the next zone or dst change event % returns the latest possible times the previous period is in effect (`Until -1sec` in most cases) % Rules are sorted -next_event(BaseFlat, ZoneEnd, Offset, []) -> +next_event(_BaseFlat, ZoneEnd, Offset, []) -> {end_until, make_times(ZoneEnd, Offset)}; % BaseFlat has offset defined % @todo ensure offset defined on BaseFlat % Rules are sorted in ascending order (oldest first) -next_event(BaseFlat=#flatzone{utc_from=#tztime{time={{Year,_,_},_}}}, - ZoneEnd, ZoneOffset, [Rule|RestRules]) -> +next_event(_BaseFlat=#flatzone{utc_from=#tztime{time={{_Year,_,_},_}}}, + _ZoneEnd, _ZoneOffset, [_Rule|_RestRules]) -> not_done. @@ -38,3 +56,11 @@ make_times(Until, Offset, DSTOffset) -> + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% INTERNAL +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + + diff --git a/src/ezic_zone.erl b/src/ezic_zone.erl index 54abd78..3c43718 100644 --- a/src/ezic_zone.erl +++ b/src/ezic_zone.erl @@ -3,7 +3,8 @@ -include_lib("eunit/include/eunit.hrl"). -export([ - current/1 + parse/1 + , current/1 , current_as_of_utc/2 , split_by_name/2 , sort_ascending/2 @@ -14,6 +15,26 @@ +parse([Name,GmtOffS,Rule,FormatS | UntilTokens]) -> +% ?debugVal(GmtOffS), + GmtOff= ezic_parse:time_val(GmtOffS), + Until = ezic_parse:until(UntilTokens), + Format= ezic_parse:tz_abbr(FormatS), + + {ok, #zone{ + name=Name, gmtoff=GmtOff, rule=Rule, + format=Format, until=Until + }}. + + + + + + + + + + current(TzName) -> current_as_of_utc(erlang:universaltime(), TzName). @@ -21,10 +42,6 @@ current_as_of_utc(UTCDatetime, TzName) -> Zones= ezic_db:zones(TzName), get_zone_utc(UTCDatetime, Zones). -%%current_as_of_local(_Datetime, _TzName) -> -%% not_done. - - @@ -58,7 +75,7 @@ split_by_name(#zone{name=N}, Zones) -> sort_descending(#zone{until=U1}, #zone{until=U2}) -> - ezic_date:compare_datetimes(U2, U1). + ezic_date:compare(U2, U1). sort_ascending(Z1=#zone{}, Z2=#zone{}) -> not sort_descending(Z1, Z2). @@ -67,9 +84,16 @@ sort_ascending(Z1=#zone{}, Z2=#zone{}) -> % @bug doesn't normalize times. Times are self-relative (to standard time), and Now may come from any timezone unless we're careful about that. %% older_zone(#zone{until=Until}, UTCDatetime) -> -%% ezic_date:compare_datetimes(Until, UTCDatetime). +%% ezic_date:compare(Until, UTCDatetime). offset_sec(Zone) -> calendar:time_to_seconds((Zone#zone.gmtoff)#tztime.time). + + + + + + + diff --git a/test/ezic_date_tests.erl b/test/ezic_date_tests.erl index 75414ba..dddc24f 100644 --- a/test/ezic_date_tests.erl +++ b/test/ezic_date_tests.erl @@ -2,42 +2,32 @@ -include("include/ezic.hrl"). -include_lib("eunit/include/eunit.hrl"). -prevnext_day_test_() -> + +for_rule_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})) + % last days of months + ?_assertEqual({2010, 03, 28}, ezic_date:for_rule(#rule{in=3, on={last, "Sun"}}, 2010)) + , ?_assertEqual({2010, 11, 30}, ezic_date:for_rule(#rule{in=11, on={last, "Tue"}}, 2010)) + , ?_assertEqual({2010, 11, 24}, ezic_date:for_rule(#rule{in=11, on={last, "Wed"}}, 2010)) - , ?_assertEqual({2010,11,5}, ezic_date:previous_day("Fri", {2010, 11, 5})) - , ?_assertEqual({2010,11,5}, ezic_date:next_day("Fri", {2010, 11, 5})) + % days =< or >= absolute dates in given month + , ?_assertEqual({2010, 11, 14}, ezic_date:for_rule(#rule{in=11, on=#tzon{day="Sun", filter={geq, 9}}}, 2010)) + , ?_assertEqual({2010, 11, 7}, ezic_date:for_rule(#rule{in=11, on=#tzon{day="Sun", filter={leq, 9}}}, 2010)) - , ?_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)) + % these should fail + , ?_assertError(no_previous_day, ezic_date:for_rule(#rule{in=11, on=#tzon{day="Sun", filter={leq, 1}}}, 2010)) + , ?_assertError(no_next_day, ezic_date:for_rule(#rule{in=11, on=#tzon{day="Sun", filter={geq, 29}}}, 2010)) ]. -compare_datetimes_test_() -> +add_seconds_test_() -> [ - ?_assertNot(ezic_date:compare_datetimes( - {{1997,3,{last, "Sun"}},{tztime,{1,0,0},u}} - , {1997,1,1} )) + ?_assertEqual({{2010,11,7},{9,38,01}}, ezic_date:add_seconds({{2010,11,7},{9,38,00}}, 1)) + , ?_assertEqual({{2010,11,7},{9,38,00}}, ezic_date:add_seconds({{2010,11,7},{9,37,59}}, 1)) + + , ?_assertEqual({{2010,11,7},{9,37,59}}, ezic_date:add_seconds({{2010,11,7},{9,38,00}}, -1)) + , ?_assertError(baddate, ezic_date:add_seconds({{2010,11,nope},{9,38,00}}, -1)) + , ?_assertError(baddate, ezic_date:add_seconds({2010,11,nope}, -1)) ]. -overlap_test_() -> - [ - ?_assert(ezic_date:overlap({1978,only},{{{1977,1,1},#tztime{}}, {{1978,1,1},#tztime{}}})) - , ?_assert(ezic_date:overlap({1978,only},{{{1971,1,1},#tztime{}}, {{1978,1,1},#tztime{}}})) - , ?_assertNot(ezic_date:overlap({1978,only},{{{1971,1,1},#tztime{}}, {{1977,12,31},#tztime{}}})) - ]. diff --git a/test/ezic_parse_tests.erl b/test/ezic_parse_tests.erl new file mode 100644 index 0000000..e0eafdb --- /dev/null +++ b/test/ezic_parse_tests.erl @@ -0,0 +1,76 @@ +-module(ezic_parse_tests). +-include("include/ezic.hrl"). +-include_lib("eunit/include/eunit.hrl"). + + +year_test_() -> + [ + ?_assertEqual(minimum, ezic_parse:year("minimum")) + , ?_assertEqual(maximum, ezic_parse:year("maximum")) + , ?_assertEqual(only, ezic_parse:year("only")) + , ?_assertEqual(1978, ezic_parse:year("1978")) + , ?_assertError(badarg, ezic_parse:year("asdf")) + ]. + + + +time_test_() -> + [ + ?_assertEqual(#tztime{time={0,0,0}}, ezic_parse:time("-")) + , ?_assertEqual(#tztime{time={2,0,0}}, ezic_parse:time("2:00")) + , ?_assertEqual(#tztime{time={15,0,0}}, ezic_parse:time("15:00")) + , ?_assertEqual(#tztime{time={1,28,14}}, ezic_parse:time("1:28:14")) + , ?_assertEqual(#tztime{time={1,28,14}, flag=w}, ezic_parse:time("1:28:14w")) + , ?_assertEqual(#tztime{time={1,28,14}, flag=s}, ezic_parse:time("1:28:14s")) + , ?_assertEqual(#tztime{time={1,28,14}, flag=u}, ezic_parse:time("1:28:14u")) + , ?_assertEqual(#tztime{time={1,28,14}, flag=u}, ezic_parse:time("1:28:14g")) + , ?_assertEqual(#tztime{time={1,28,14}, flag=u}, ezic_parse:time("1:28:14z")) + + , ?_assertError(badtime, ezic_parse:time("1:28:14wtf?")) + , ?_assertError(badtime, ezic_parse:time("1:28:14:00")) + ]. + + +time_val_test_() -> + [ + ?_assertEqual({0,0,0}, ezic_parse:time_val("-")) + , ?_assertEqual({2,0,0}, ezic_parse:time_val("2:00")) + , ?_assertEqual({15,0,0}, ezic_parse:time_val("15:00")) + , ?_assertEqual({1,28,14}, ezic_parse:time_val("1:28:14")) + , ?_assertEqual({1,28,14}, ezic_parse:time_val("1:28:14w")) + , ?_assertEqual({1,28,14}, ezic_parse:time_val("1:28:14s")) + , ?_assertEqual({1,28,14}, ezic_parse:time_val("1:28:14u")) + , ?_assertEqual({1,28,14}, ezic_parse:time_val("1:28:14g")) + , ?_assertEqual({1,28,14}, ezic_parse:time_val("1:28:14z")) + + , ?_assertError(badtime, ezic_parse:time_val("1:28:14wtf?")) + , ?_assertError(badtime, ezic_parse:time_val("1:28:14:00")) + ]. + + + +day_pattern_test_() -> + [ + ?_assertEqual(5, ezic_parse:day_pattern("5")) + + , ?_assertEqual({last, "Sun"}, ezic_parse:day_pattern("lastSun")) + , ?_assertEqual({last, "Mon"}, ezic_parse:day_pattern("lastMon")) + , ?_assertError(badday, ezic_parse:day_pattern("lastFoo")) + + , ?_assertEqual(#tzon{day="Sun", filter={geq, 8}}, ezic_parse:day_pattern("Sun>=8")) + , ?_assertEqual(#tzon{day="Sun", filter={leq, 25}}, ezic_parse:day_pattern("Sun<=25")) + , ?_assertError(badday, ezic_parse:day_pattern("Foo<=25")) + ]. + + + + +tz_abbr_test_() -> + [ + ?_assertEqual("POS", ezic_parse:tz_abbr("POS")) + , ?_assertEqual("P~sS", ezic_parse:tz_abbr("P%sS")) + , ?_assertEqual("PS~s", ezic_parse:tz_abbr("PS%s")) + ]. + + + diff --git a/test/ezic_record_tests.erl b/test/ezic_record_tests.erl index 8c9f503..2893a5e 100644 --- a/test/ezic_record_tests.erl +++ b/test/ezic_record_tests.erl @@ -2,89 +2,3 @@ -include("include/ezic.hrl"). -include_lib("eunit/include/eunit.hrl"). - -parse_fromto_test_() -> - [ - ?_assertEqual(minimum, ezic_record:parse_from("minimum")) - , ?_assertEqual(minimum, ezic_record:parse_to("minimum")) - - , ?_assertEqual(maximum, ezic_record:parse_from("maximum")) - , ?_assertEqual(maximum, ezic_record:parse_to("maximum")) - - , ?_assertError(badarg, ezic_record:parse_from("only")) - , ?_assertEqual(only, ezic_record:parse_to("only")) - - , ?_assertEqual(1978, ezic_record:parse_from("1978")) - , ?_assertEqual(1978, ezic_record:parse_to("1978")) - - , ?_assertError(badarg, ezic_record:parse_from("asdf")) - , ?_assertError(badarg, ezic_record:parse_to("asdf")) - ]. - - -parse_time_test_() -> - [ - ?_assertEqual(#tztime{time={0,0,0}}, ezic_record:parse_time("-")) - , ?_assertEqual(#tztime{time={2,0,0}}, ezic_record:parse_time("2:00")) - , ?_assertEqual(#tztime{time={15,0,0}}, ezic_record:parse_time("15:00")) - , ?_assertEqual(#tztime{time={1,28,14}}, ezic_record:parse_time("1:28:14")) - , ?_assertEqual(#tztime{time={1,28,14}, flag=u}, ezic_record:parse_time("1:28:14u")) - , ?_assertEqual(#tztime{time={1,28,14}, flag=w}, ezic_record:parse_time("1:28:14w")) - , ?_assertEqual(#tztime{time={1,28,14}, flag=s}, ezic_record:parse_time("1:28:14s")) - - , ?_assertError(badtime, ezic_record:parse_time("1:28:14wtf?")) - , ?_assertError(badtime, ezic_record:parse_time("1:28:14:00")) - ]. - - -parse_at_test_() -> - [ - ?_assertEqual(#tztime{time={0,0,0}}, ezic_record:parse_at("-")) - , ?_assertEqual(#tztime{time={2,0,0}}, ezic_record:parse_at("2:00")) - , ?_assertEqual(#tztime{time={15,0,0}}, ezic_record:parse_at("15:00")) - , ?_assertEqual(#tztime{time={1,28,14}}, ezic_record:parse_at("1:28:14")) - , ?_assertEqual(#tztime{time={1,28,14}, flag=u}, ezic_record:parse_at("1:28:14u")) - , ?_assertEqual(#tztime{time={1,28,14}, flag=w}, ezic_record:parse_at("1:28:14w")) - , ?_assertEqual(#tztime{time={1,28,14}, flag=s}, ezic_record:parse_at("1:28:14s")) - , ?_assertError(badtime, ezic_record:parse_at("1:28:14wtf?")) - ]. - - -parse_save_test_() -> - [ - ?_assertEqual(#tztime{time={0,0,0}}, ezic_record:parse_save("-")) - , ?_assertEqual(#tztime{time={2,0,0}}, ezic_record:parse_save("2:00")) - , ?_assertEqual(#tztime{time={15,0,0}}, ezic_record:parse_save("15:00")) - , ?_assertEqual(#tztime{time={1,28,14}}, ezic_record:parse_save("1:28:14")) - , ?_assertError(badsave, ezic_record:parse_save("1:28:14u")) - , ?_assertError(badsave, ezic_record:parse_save("1:28:14w")) - , ?_assertError(badsave, ezic_record:parse_save("1:28:14s")) - , ?_assertError(badsave, ezic_record:parse_save("1:28:14wtf?")) - ]. - - - - - -parse_on_test_() -> - [ - ?_assertEqual(5, ezic_record:parse_on("5")) - - , ?_assertEqual({last, "Sun"}, ezic_record:parse_on("lastSun")) - , ?_assertEqual({last, "Mon"}, ezic_record:parse_on("lastMon")) - , ?_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={leq, 25}}, ezic_record:parse_on("Sun<=25")) - , ?_assertError(badday, ezic_record:parse_on("Foo<=25")) - ]. - - -convert_format_test_() -> - [ - ?_assertEqual("POS", ezic_record:convert_format("POS")) - , ?_assertEqual("P~sS", ezic_record:convert_format("P%sS")) - ]. - - - diff --git a/test/test.erl b/test/test.erl index 9fdce40..05ebae2 100644 --- a/test/test.erl +++ b/test/test.erl @@ -3,6 +3,9 @@ -include_lib("eunit/include/eunit.hrl"). all() -> - eunit:test(ezic_record), - eunit:test(ezic_date), - eunit:test(ezic_zone). + eunit:test(ezic_record) + , eunit:test(ezic_date) + , eunit:test(ezic_zone) + , eunit:test(ezic_parse) + + ,ok.