datetime manipulation is now much clearer. tests were added, and expectations stated explicitly in many places. rules got lots of attention.
This commit is contained in:
@@ -11,13 +11,13 @@
|
||||
-record(leap, {datetime, corr, rs}).
|
||||
|
||||
|
||||
-record(tztime, {time={0,0,0}, flag}).
|
||||
-record(tztime, {time={0,0,0}, flag=w}).
|
||||
-record(tzon, {day, filter}).
|
||||
|
||||
|
||||
|
||||
% a flattened zone record, giving specific information for a specific time range.
|
||||
-record(flatzone, {tzname, wall_from, wall_to, std_from, std_to, utc_from, utc_to, offset}).
|
||||
-record(flatzone, {tzname, wall_from, wall_to, std_from, std_to, utc_from, utc_to, offset, dstoffset={0,0,0}}).
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
-export([
|
||||
% rule-specific
|
||||
for_rule/2
|
||||
, for_rule_zone/3
|
||||
, for_rule_utc/4
|
||||
|
||||
|
||||
% converters
|
||||
@@ -17,7 +17,12 @@
|
||||
|
||||
% date math
|
||||
, add_seconds/2
|
||||
, add_offset/2
|
||||
, all_times/3
|
||||
|
||||
% comparisons
|
||||
, compare/2
|
||||
, equal/2
|
||||
]).
|
||||
|
||||
|
||||
@@ -27,26 +32,20 @@
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
% 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(#rule{in=M, on=#tzon{day=Day, filter=Filter}}, Y) ->
|
||||
first_day_limited(Day, Filter, Y,M).
|
||||
% returns RELATIVE {Y,M,D} for a rule and Year
|
||||
for_rule(#rule{in=M, on=D, at=At}, Y) when is_integer(D) ->
|
||||
{{Y,M,D}, At};
|
||||
for_rule(#rule{in=M, on={last, D}, at=At}, Y) ->
|
||||
{last_day_of(D, Y,M), At};
|
||||
for_rule(#rule{in=M, on=#tzon{day=Day, filter=Filter}, at=At}, Y) ->
|
||||
{first_day_limited(Day, Filter, Y,M), At}.
|
||||
|
||||
|
||||
|
||||
|
||||
% 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),
|
||||
|
||||
not_done.
|
||||
% returns UTC datetime for rule, offset, and year
|
||||
for_rule_utc(Rule, Offset, DSTOffset, Year) ->
|
||||
DT= for_rule(Rule, Year),
|
||||
{_,_,UTCDatetime} = all_times(DT, Offset, DSTOffset),
|
||||
UTCDatetime.
|
||||
|
||||
|
||||
|
||||
@@ -89,47 +88,83 @@ add_seconds(Datetime, Seconds) ->
|
||||
|
||||
|
||||
|
||||
add_offset(Datetime, Offset) ->
|
||||
Sec= calendar:time_to_seconds(Offset),
|
||||
add_seconds(Datetime, Sec).
|
||||
|
||||
|
||||
|
||||
% returns {WallTime, StdTime, UtcTime}
|
||||
% where each is a datetime tuple: {{Y,M,D}{HH,MM,SS}}
|
||||
|
||||
% universal time given
|
||||
all_times(#tztime{time=UTCTime, flag=Flag}, Offset, DSTOffset)
|
||||
all_times({Date, #tztime{time=UTCTime, flag=Flag}}, Offset, DSTOffset)
|
||||
when Flag=:=u; Flag=:=g; Flag=:=z ->
|
||||
UTCDatetime= {Date, UTCTime},
|
||||
|
||||
OSec= calendar:time_to_seconds(Offset),
|
||||
DSTSec= calendar:time_to_seconds(DSTOffset),
|
||||
|
||||
STDTime= add_seconds(UTCTime, OSec),
|
||||
STDTime= add_seconds(UTCDatetime, OSec),
|
||||
WallTime= add_seconds(STDTime, DSTSec),
|
||||
|
||||
{WallTime, STDTime, UTCTime};
|
||||
{WallTime, STDTime, UTCDatetime};
|
||||
|
||||
|
||||
% standard time given
|
||||
all_times(#tztime{time=STDTime, flag=s}, Offset, DSTOffset) ->
|
||||
all_times({Date, #tztime{time=STDTime, flag=s}}, Offset, DSTOffset) ->
|
||||
STDDatetime= {Date, STDTime},
|
||||
|
||||
OSec= calendar:time_to_seconds(Offset),
|
||||
DSTSec= calendar:time_to_seconds(DSTOffset),
|
||||
|
||||
UTCTime= add_seconds(STDTime, -1*OSec),
|
||||
WallTime= add_seconds(STDTime, DSTSec),
|
||||
UTCTime= add_seconds(STDDatetime, -1*OSec),
|
||||
WallTime= add_seconds(STDDatetime, DSTSec),
|
||||
|
||||
{WallTime, STDTime, UTCTime};
|
||||
{WallTime, STDDatetime, UTCTime};
|
||||
|
||||
|
||||
% wall time given
|
||||
all_times(#tztime{time=WallTime, flag=Flag}, Offset, DSTOffset)
|
||||
when Flag=:=w, Flag=:=undefined ->
|
||||
all_times({Date, #tztime{time=WallTime, flag=Flag}}, Offset, DSTOffset)
|
||||
when Flag=:=w; Flag=:=undefined ->
|
||||
WallDatetime= {Date, WallTime},
|
||||
|
||||
OSec= calendar:time_to_seconds(Offset),
|
||||
DSTSec= calendar:time_to_seconds(DSTOffset),
|
||||
|
||||
STDTime= add_seconds(WallTime, -1*DSTSec),
|
||||
STDTime= add_seconds(WallDatetime, -1*DSTSec),
|
||||
UTCTime= add_seconds(STDTime, -1*OSec),
|
||||
|
||||
{WallTime, STDTime, UTCTime}.
|
||||
{WallDatetime, STDTime, UTCTime}.
|
||||
|
||||
|
||||
|
||||
|
||||
% returns true if DT1 =< DT2. False otherwise. can be used with lists:sort/2
|
||||
% both times are assumed to be in the same zone/DST context
|
||||
compare(DT1={{Y1,M1,D1},{HH1,MM1,SS1}}, DT2={{Y2,M2,D2},{HH2,MM2,SS2}})
|
||||
when is_integer(Y1), is_integer(Y2)
|
||||
, is_integer(M1), is_integer(M2)
|
||||
, is_integer(D1), is_integer(D2)
|
||||
, is_integer(HH1), is_integer(HH2)
|
||||
, is_integer(MM1), is_integer(MM2)
|
||||
, is_integer(SS1), is_integer(SS2)
|
||||
->
|
||||
|
||||
DT1 =< DT2.
|
||||
|
||||
% returns true if DT1 =:= DT2. False otherwise
|
||||
% both times are assumed to be in the same zone/DST context
|
||||
equal(DT1={{Y1,M1,D1},{HH1,MM1,SS1}}, DT2={{Y2,M2,D2},{HH2,MM2,SS2}})
|
||||
when is_integer(Y1), is_integer(Y2)
|
||||
, is_integer(M1), is_integer(M2)
|
||||
, is_integer(D1), is_integer(D2)
|
||||
, is_integer(HH1), is_integer(HH2)
|
||||
, is_integer(MM1), is_integer(MM2)
|
||||
, is_integer(SS1), is_integer(SS2)
|
||||
->
|
||||
|
||||
DT1 =:= DT2.
|
||||
|
||||
|
||||
|
||||
@@ -211,10 +246,3 @@ add_days_in_month(Days, Date={Y,M,D}) ->
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
|
||||
normalize(_Datetime) ->
|
||||
not_done.
|
||||
|
||||
compare_normal(_DT1, _DT2) ->
|
||||
not_done.
|
||||
|
||||
|
||||
@@ -88,55 +88,28 @@ 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=#flatzone{utc_from=UTCFrom, dstoffset=DSTOffset}, [Z1=#zone{rule=RuleName, until=UntilTime, gmtoff=Offset} | _RestZones], _Flats) ->
|
||||
|
||||
%% we have a flatzone with start times, we populate the base offset
|
||||
FromTime= FromTimeStub#flatzone{offset=Offset},
|
||||
%% note that dst offset default to {0,0,0} in #flatzone{}
|
||||
|
||||
|
||||
%% 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),
|
||||
RuleDates= lists:foldl(
|
||||
fun(R, Acc)->
|
||||
case ezic_rule:project_next(R, Offset, DSTOffset, UTCFrom) of
|
||||
none -> Acc;
|
||||
D -> [{D,R} | Acc]
|
||||
end
|
||||
end
|
||||
,[], Rules),
|
||||
AllDates= [{ezic_zone:project_end(Z1, DSTOffset), Z1} | RuleDates],
|
||||
|
||||
|
||||
|
||||
not_done.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
% flattens a single zone into multiple flatzones.
|
||||
% FromTime has its *_from fields and offset field populated. (it should anyway)
|
||||
% @todo invalid input checking
|
||||
% Rules are sorted
|
||||
flatten_zone(BaseFlat, Zone, Rules) ->
|
||||
flatten_zone(BaseFlat, Zone, Rules, []).
|
||||
|
||||
flatten_zone(BaseFlat, Zone=#zone{until=Until, gmtoff=Offset}, Rules, Flats) ->
|
||||
case ezic_rule:next_event(BaseFlat, Until, Offset, Rules) of
|
||||
% is this enough information to compare all times corectly?
|
||||
{end_until, EndTimes} ->
|
||||
NewFlats= [end_flat(BaseFlat, EndTimes) | Flats],
|
||||
NewFrom= make_next_flat(EndTimes),
|
||||
{ok, NewFrom, NewFlats}; % base case
|
||||
|
||||
{end_rule, EndTimes, NextOffset} ->
|
||||
NewFlats= [end_flat(BaseFlat, EndTimes) | Flats],
|
||||
NewFrom= make_next_flat(EndTimes, NextOffset),
|
||||
flatten_zone(NewFrom, Zone, Rules, NewFlats) % tail recursion
|
||||
|
||||
end.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -145,7 +145,7 @@ time_flag_rev([F|RTime]) when F =:= $g; F =:= $z ->
|
||||
time_flag_rev(X=[F|_]) when F-48 < 0; F-48 > 9 ->
|
||||
erlang:error(badtime, lists:reverse(X));
|
||||
time_flag_rev(RTime) ->
|
||||
{undefined, RTime}.
|
||||
{w, RTime}.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -3,11 +3,6 @@
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
|
||||
-ifdef(TEST).
|
||||
-compile([export_all]).
|
||||
-endif.
|
||||
|
||||
|
||||
-export([
|
||||
link/1
|
||||
, leap/1
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
|
||||
|
||||
-export([parse/1]).
|
||||
-export([next_event/4]).
|
||||
|
||||
-export([project_next/4]).
|
||||
|
||||
|
||||
parse([Name,FromS,ToS,_Type,InS,OnS,AtS,SaveS,Letters]) ->
|
||||
@@ -25,37 +24,38 @@ parse([Name,FromS,ToS,_Type,InS,OnS,AtS,SaveS,Letters]) ->
|
||||
|
||||
|
||||
|
||||
% 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, []) ->
|
||||
{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]) ->
|
||||
|
||||
not_done.
|
||||
|
||||
|
||||
|
||||
% returns the projected date of the next "rule event" in UTC time,
|
||||
% after the given UTCDatetime, with the given the zone Offset and current DST offset.
|
||||
project_next(Rule=#rule{from=RFrom, to=RTo}, Offset, DSTOff, UTCAfter={{AY,_,_},_}) ->
|
||||
AllYears= years(Rule),
|
||||
GoodYears= years_after(AY, AllYears),
|
||||
project_next2(Rule, Offset, UTCAfter, DSTOff, GoodYears).
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% PRIVATE
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
% create endtimes for a #flatzone, with no dst offset
|
||||
make_times(Until, Offset) ->
|
||||
make_times(Until, Offset, 0).
|
||||
|
||||
make_times(Until, Offset, DSTOffset) ->
|
||||
ezic_date:all_times(Until, Offset, DSTOffset).
|
||||
|
||||
|
||||
% returns the sorted list of years a rule existed for.
|
||||
years(Rule=#rule{from=From, to=only}) ->
|
||||
[From];
|
||||
years(Rule=#rule{from=From, to=To}) ->
|
||||
try lists:seq(From, To)
|
||||
catch error:function_clause ->
|
||||
erlang:error(bad_year_range)
|
||||
end.
|
||||
|
||||
% returns the years from the list that are greater than OR equal to Y
|
||||
years_after(Y, []) ->
|
||||
[];
|
||||
years_after(Y, Years) ->
|
||||
{GOOD, _}= lists:partition(
|
||||
fun(X) when Y =< X -> true;
|
||||
(_) -> false
|
||||
end, Years),
|
||||
GOOD.
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% INTERNAL
|
||||
@@ -63,4 +63,45 @@ make_times(Until, Offset, DSTOffset) ->
|
||||
|
||||
|
||||
|
||||
project_next2(_,_,_,_,[]) ->
|
||||
none;
|
||||
project_next2(Rule, Offset, UTCAfter, DSTOffset, [Year|RestYears]) ->
|
||||
RuleDate= ezic_date:for_rule_utc(Rule, Offset, DSTOffset, Year),
|
||||
case ezic_date:compare(UTCAfter, RuleDate) andalso (not ezic_date:equal(UTCAfter, RuleDate)) of
|
||||
true -> RuleDate;
|
||||
_ -> project_next2(Rule, Offset, UTCAfter, DSTOffset, RestYears)
|
||||
end.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% Tests of Private Methods
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
years_test_() ->
|
||||
[
|
||||
?_assertEqual([1952], years(#rule{from=1952,to=only}))
|
||||
, ?_assertEqual([1952,1953], years(#rule{from=1952,to=1953}))
|
||||
, ?_assertEqual([1952,1953,1954,1955], years(#rule{from=1952,to=1955}))
|
||||
, ?_assertError(bad_year_range, years(#rule{from=1955,to=1952}))
|
||||
].
|
||||
|
||||
|
||||
% @todo type checking. lack of types worries me sometimes :(
|
||||
years_after_test_() ->
|
||||
[
|
||||
?_assertEqual([2010], years_after(2010, [2010]))
|
||||
, ?_assertEqual([2010,2011], years_after(2010, [2010,2011]))
|
||||
, ?_assertEqual([2011], years_after(2011, [2010,2011]))
|
||||
, ?_assertEqual([], years_after(2012, [2010,2011]))
|
||||
, ?_assertEqual([], years_after(2012, []))
|
||||
].
|
||||
|
||||
-endif.
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
, sort_ascending/2
|
||||
, sort_descending/2
|
||||
, offset_sec/1
|
||||
|
||||
, project_end/2
|
||||
]).
|
||||
|
||||
|
||||
@@ -94,6 +96,11 @@ offset_sec(Zone) ->
|
||||
|
||||
|
||||
|
||||
% returns the UTC datetime projected for zone end (given current DST Offset)
|
||||
project_end(#zone{until=Until, gmtoff=Offset}, DSTOffset) ->
|
||||
{_,_,UTCDatetime}= ezic_date:all_times(Until, Offset, DSTOffset),
|
||||
UTCDatetime.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -4,19 +4,46 @@
|
||||
|
||||
|
||||
for_rule_test_() ->
|
||||
BR= #rule{at=#tztime{}},
|
||||
[
|
||||
% 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, 03, 28}, #tztime{}}, ezic_date:for_rule(BR#rule{in=3, on={last, "Sun"}}, 2010))
|
||||
, ?_assertEqual({{2010, 11, 30}, #tztime{}}, ezic_date:for_rule(BR#rule{in=11, on={last, "Tue"}}, 2010))
|
||||
, ?_assertEqual({{2010, 11, 24}, #tztime{}}, ezic_date:for_rule(BR#rule{in=11, on={last, "Wed"}}, 2010))
|
||||
|
||||
% 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, 14}, #tztime{}}, ezic_date:for_rule(BR#rule{in=11, on=#tzon{day="Sun", filter={geq, 9}}}, 2010))
|
||||
, ?_assertEqual({{2010, 11, 7}, #tztime{}}, ezic_date:for_rule(BR#rule{in=11, on=#tzon{day="Sun", filter={leq, 9}}}, 2010))
|
||||
|
||||
% 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))
|
||||
, ?_assertError(no_previous_day, ezic_date:for_rule(BR#rule{in=11, on=#tzon{day="Sun", filter={leq, 1}}}, 2010))
|
||||
, ?_assertError(no_next_day, ezic_date:for_rule(BR#rule{in=11, on=#tzon{day="Sun", filter={geq, 29}}}, 2010))
|
||||
].
|
||||
|
||||
|
||||
for_rule_utc_dst_test_() ->
|
||||
WRule= #rule{in=11, on=11, at=#tztime{time={0,0,0}}, save={0,0,0}},
|
||||
SRule= #rule{in=11, on=11, at=#tztime{time={0,0,0}, flag=s}, save={0,0,0}},
|
||||
URule= #rule{in=11, on=11, at=#tztime{time={0,0,0}, flag=u}, save={0,0,0}},
|
||||
DST= {1,0,0},
|
||||
|
||||
%%% given a DST savings of 1 in a -7 zone, and given rules in each of the relative timezones:
|
||||
%%% - wall time should respect the given DST and offset
|
||||
%%% - std time should respect the offset, but not DST
|
||||
%%% - utc should respect neither
|
||||
[
|
||||
%% same "time" with different relative contexts should return different UTC results
|
||||
?_assertEqual({{2010,11,11}, {6,0,0}}, ezic_date:for_rule_utc(WRule, {-7,0,0}, DST, 2010))
|
||||
, ?_assertEqual({{2010,11,11}, {7,0,0}}, ezic_date:for_rule_utc(SRule, {-7,0,0}, DST, 2010))
|
||||
, ?_assertEqual({{2010,11,11}, {0,0,0}}, ezic_date:for_rule_utc(URule, {-7,0,0}, DST, 2010))
|
||||
|
||||
%% some absolute time in all contexts should return the same UTC results
|
||||
, ?_assertEqual({{2010,11,11}, {0,0,0}},
|
||||
ezic_date:for_rule_utc(WRule#rule{on=10, at=#tztime{flag=w, time={18,0,0}}}, {-7,0,0}, DST, 2010))
|
||||
, ?_assertEqual({{2010,11,11}, {0,0,0}},
|
||||
ezic_date:for_rule_utc(SRule#rule{on=10, at=#tztime{flag=s, time={17,0,0}}}, {-7,0,0}, DST, 2010))
|
||||
, ?_assertEqual({{2010,11,11}, {0,0,0}},
|
||||
ezic_date:for_rule_utc(URule, {-7,0,0}, DST, 2010))
|
||||
].
|
||||
|
||||
|
||||
|
||||
37
test/ezic_rule_tests.erl
Normal file
37
test/ezic_rule_tests.erl
Normal file
@@ -0,0 +1,37 @@
|
||||
-module(ezic_rule_tests).
|
||||
-include("include/ezic.hrl").
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
|
||||
project_next_test_() ->
|
||||
[
|
||||
|
||||
% simple UTC example
|
||||
?_assertEqual({{2010,11,10},{16,20,0}},
|
||||
ezic_rule:project_next(
|
||||
#rule{from=1984, to=2032, in=11, on=10, at=#tztime{time={16,20,0}, flag=u}}
|
||||
, {-5,0,0}, {-1,0,0}, {{2010,11,10},{0,0,0}}
|
||||
))
|
||||
|
||||
% skip a year UTC example
|
||||
, ?_assertEqual({{2011,11,10},{16,20,0}},
|
||||
ezic_rule:project_next(
|
||||
#rule{from=1984, to=2032, in=11, on=10, at=#tztime{time={16,20,0}, flag=u}}
|
||||
, {-5,0,0}, {-1,0,0}, {{2010,11,10},{16,21,0}}
|
||||
))
|
||||
|
||||
% skip 3 years UTC example
|
||||
, ?_assertEqual({{2013,11,10},{16,20,0}},
|
||||
ezic_rule:project_next(
|
||||
#rule{from=1984, to=2032, in=11, on=10, at=#tztime{time={16,20,0}, flag=u}}
|
||||
, {-5,0,0}, {-1,0,0}, {{2012,11,11},{16,20,0}}
|
||||
))
|
||||
|
||||
% no solution
|
||||
, ?_assertEqual(none,
|
||||
ezic_rule:project_next(
|
||||
#rule{from=1984, to=2010, in=11, on=10, at=#tztime{time={16,20,0}, flag=u}}
|
||||
, {-5,0,0}, {-1,0,0}, {{2012,11,11},{16,20,0}}
|
||||
))
|
||||
|
||||
].
|
||||
@@ -12,3 +12,23 @@ split_by_name_test_() ->
|
||||
, ?_assertEqual({BZones, AZones}, ezic_zone:split_by_name(B, AllZones))
|
||||
, ?_assertEqual({[], AllZones}, ezic_zone:split_by_name(#zone{name=c}, AllZones))
|
||||
].
|
||||
|
||||
|
||||
|
||||
project_end_test_() ->
|
||||
[
|
||||
?_assertEqual({{2010,11,10},{16,20,0}},
|
||||
ezic_zone:project_end(
|
||||
#zone{until={{2010,11,10},#tztime{time={10,20,0}, flag=w}}, gmtoff={-7,0,0}}
|
||||
, {1,0,0}))
|
||||
|
||||
, ?_assertEqual({{2010,11,10},{16,20,0}},
|
||||
ezic_zone:project_end(
|
||||
#zone{until={{2010,11,10},#tztime{time={9,20,0}, flag=s}}, gmtoff={-7,0,0}}
|
||||
, {1,0,0}))
|
||||
|
||||
, ?_assertEqual({{2010,11,10},{16,20,0}},
|
||||
ezic_zone:project_end(
|
||||
#zone{until={{2010,11,10},#tztime{time={16,20,0}, flag=u}}, gmtoff={-7,0,0}}
|
||||
, {1,0,0}))
|
||||
].
|
||||
|
||||
@@ -7,5 +7,6 @@ all() ->
|
||||
, eunit:test(ezic_date)
|
||||
, eunit:test(ezic_zone)
|
||||
, eunit:test(ezic_parse)
|
||||
, eunit:test(ezic_rule)
|
||||
|
||||
,ok.
|
||||
|
||||
Reference in New Issue
Block a user