handled case where zone and rule both end. dealing with Tripoli recursion bug (ambiguous year in ezic_date:for_rule)
This commit is contained in:
@@ -50,7 +50,9 @@ load(Folder) ->
|
||||
|
||||
dev_start() ->
|
||||
% ezic:load(filename:join("priv","tzdata")),
|
||||
ezic_flatten:flatten().
|
||||
% ezic_flatten:flatten().
|
||||
TZones= ezic_db:zones("Africa/Tripoli"),
|
||||
ezic_flatten:flatten_all_zones(TZones).
|
||||
|
||||
|
||||
test() ->
|
||||
|
||||
@@ -51,13 +51,15 @@ normalize(Date={Y,M,D})
|
||||
when is_integer(Y), is_integer(M), is_integer(D) ->
|
||||
{Date, #tztime{}};
|
||||
normalize(R={{_,_,_}, #tztime{}}) ->
|
||||
R.
|
||||
R;
|
||||
normalize({D={_,_,_}, T={_,_,_}}) ->
|
||||
{D, #tztime{time=T}}.
|
||||
|
||||
|
||||
%% normalizes a date, and sets the #tztime{flag=Flag} if appropriate
|
||||
%% @todo ensure flag is valid
|
||||
%% @todo cover all the cases. this is currently just used for standard erlang datetimes
|
||||
normalize(DT={D={_,_,_},T={HH,_,_}}, Flag)
|
||||
normalize({D={_,_,_},T={HH,_,_}}, Flag)
|
||||
when is_atom(Flag), is_integer(HH) ->
|
||||
|
||||
DTz= {D, #tztime{time=T, flag=Flag}},
|
||||
@@ -90,6 +92,7 @@ for_rule_relative(#rule{in=M, on=#tzon{day=Day, filter=Filter}, at=At}, Y) ->
|
||||
|
||||
%% returns set of ALL datetimes for a rule, given the gmt offset and
|
||||
%% current dst offset.
|
||||
%% @bug @todo Year is ambiguous. In the case of Africa/Tripoli, a jan 1st, 1952 rule shows up as 1951 due to offset and dst.
|
||||
for_rule(Rule, Offset, PrevDSTOffset, NextDSTOffset, Year) ->
|
||||
{WT,ST,UT}= for_rule_old_dst(Rule, Offset, PrevDSTOffset, Year),
|
||||
WTNew= add_offset(WT, PrevDSTOffset, NextDSTOffset),
|
||||
@@ -101,7 +104,7 @@ for_rule(Rule, Offset, PrevDSTOffset, NextDSTOffset, Year) ->
|
||||
|
||||
for_rule_old_dst(Rule, Offset, PrevDSTOffset, Year) ->
|
||||
DT= for_rule_relative(Rule, Year),
|
||||
{WT,ST,UT}= all_times(DT, Offset, PrevDSTOffset).
|
||||
all_times(DT, Offset, PrevDSTOffset).
|
||||
|
||||
|
||||
|
||||
@@ -239,22 +242,25 @@ when is_integer(Y1), is_integer(Y2)
|
||||
, is_integer(SS1), is_integer(SS2)
|
||||
->
|
||||
|
||||
DT1 =< DT2.
|
||||
DT1 =< DT2;
|
||||
|
||||
|
||||
compare({Date1, #tztime{time=Time1, flag=F}}
|
||||
, {Date2, #tztime{time=Time2, flag=F}}) ->
|
||||
|
||||
Date1 =< Date2 orelse Time1 =< time2;
|
||||
|
||||
% 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)
|
||||
->
|
||||
compare(X,Y) ->
|
||||
XN= normalize(X),
|
||||
YN= normalize(Y),
|
||||
compare(XN, YN).
|
||||
|
||||
|
||||
DT1 =:= DT2.
|
||||
|
||||
equal(X,Y) when X=:=Y ->
|
||||
true;
|
||||
equal(_,_) ->
|
||||
false.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -9,16 +9,22 @@
|
||||
|
||||
|
||||
|
||||
%% @todo move MAXYEAR to config file
|
||||
-define(MAXYEAR, 2500). % last year to process flatzones for.
|
||||
|
||||
|
||||
-export([flatten/0]).
|
||||
|
||||
|
||||
%% debug
|
||||
-export([flatten_all_zones/1]).
|
||||
|
||||
|
||||
|
||||
flatten() ->
|
||||
AllZones= ezic_db:get_all(zone),
|
||||
flatten_all_zones(AllZones),
|
||||
not_done.
|
||||
done.
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
@@ -28,15 +34,15 @@ flatten() ->
|
||||
|
||||
% recursively processes sets of similar zones until they're all done,
|
||||
% passing zone sets to flatten_zone_set/1
|
||||
flatten_all_zones(Zones) ->
|
||||
flatten_all_zones(Zones, []).
|
||||
|
||||
flatten_all_zones([], Flats) ->
|
||||
Flats;
|
||||
flatten_all_zones([Z1|_]= AllZones, Flats) ->
|
||||
flatten_all_zones([]) ->
|
||||
done;
|
||||
flatten_all_zones([Z1|_]= AllZones) ->
|
||||
{CurrentZones, RestZones}= ezic_zone:split_by_name(Z1, AllZones),
|
||||
NewFlats= lists:merge(Flats, flatten_zone_set(CurrentZones)),
|
||||
flatten_all_zones(RestZones, NewFlats).
|
||||
|
||||
Flats= flatten_zone_set(CurrentZones),
|
||||
ezic_db:insert_all(Flats),
|
||||
|
||||
flatten_all_zones(RestZones).
|
||||
|
||||
|
||||
|
||||
@@ -50,7 +56,7 @@ flatten_all_zones([Z1|_]= AllZones, Flats) ->
|
||||
%% offset (#flatzone). This is a recursive solution, eliminating Zones
|
||||
%% from the list until it's been exhausted
|
||||
flatten_zone_set(Zones) ->
|
||||
flatten_zone_set(?MINFLAT, Zones, []).
|
||||
flatten_zone_set(?MINFLAT, Zones, [], none).
|
||||
|
||||
|
||||
% flatten_zone_set(FromTime, Zones, Flats) -> [#flatzone{}]
|
||||
@@ -59,12 +65,10 @@ flatten_zone_set(Zones) ->
|
||||
% Flats= [#flatzone{}]
|
||||
%
|
||||
% assumes a new zone every time it is called
|
||||
flatten_zone_set(_, [], Flats) ->
|
||||
erlang:error(debug_quit),
|
||||
Flats;
|
||||
flatten_zone_set(FromTimeStub=#flatzone{utc_from=UTCFrom, dstoffset=DSTOffset}
|
||||
, Zones %[Z1=#zone{rule=RuleName, until=UntilTime, gmtoff=Offset} | _RestZones],
|
||||
, Flats) ->
|
||||
, Flats
|
||||
, CurrentRule) ->
|
||||
|
||||
[Zone | RestZones] = ezic_zone:next(Zones, UTCFrom, DSTOffset),
|
||||
#zone{rule=RuleName, until=_UntilTime, gmtoff=Offset}= Zone,
|
||||
@@ -75,11 +79,11 @@ flatten_zone_set(FromTimeStub=#flatzone{utc_from=UTCFrom, dstoffset=DSTOffset}
|
||||
%% must populate the base gmt offset and name for the current zone
|
||||
|
||||
FromTime= populate_flatzone(FromTimeStub, Zone),
|
||||
% FromTime= FromTimeStub#flatzone{offset=Offset, tzname=Zone#zone.name},
|
||||
|
||||
%% if this is the first run, DST offset is {0,0,0}
|
||||
%% if this is a recursion, DST offset is the previous zone's last DST offset
|
||||
%% @todo see if dst rules carry over zone changes IRL
|
||||
%% if this is the first run, DST offset is {0,0,0} if this is a
|
||||
%% recursion, DST offset is the previous zone's last DST offset
|
||||
%% @todo see if dst rules carry over zone changes IRL. I'll assume
|
||||
%% they don't.
|
||||
|
||||
|
||||
%% we gather all rules that _may_ apply
|
||||
@@ -89,35 +93,36 @@ flatten_zone_set(FromTimeStub=#flatzone{utc_from=UTCFrom, dstoffset=DSTOffset}
|
||||
?debugVal(FromTime),
|
||||
?debugVal(Rules),
|
||||
|
||||
|
||||
%% apply all rules in order, creating flatzones, until this zone
|
||||
%% ends, then regain control.
|
||||
{RuleFlats, LastFlat, EndingDST}= flatten_rule_set(FromTime, Zone, Rules, []),
|
||||
%% ends, then regain control. rules have been exhausted, and zone
|
||||
%% is ending. let's finish this.
|
||||
|
||||
?debugVal(RuleFlats),
|
||||
?debugVal(EndingDST),
|
||||
|
||||
%% rules have been exhausted, and zone is ending. let's finish this.
|
||||
{FinalFlat, NextFlat}= finish_and_start_flat(LastFlat, Zone, EndingDST),
|
||||
FinalFlats= lists:merge([[FinalFlat], RuleFlats, Flats]),
|
||||
{RuleFlats, NextFlat, EndingRule}= flatten_rule_set(FromTime, Zone, Rules, CurrentRule, []),
|
||||
FinalFlats= lists:append([RuleFlats, Flats]),
|
||||
|
||||
?debugVal(FinalFlat),
|
||||
?debugVal(FinalFlats),
|
||||
|
||||
?debugVal(NextFlat),
|
||||
|
||||
flatten_zone_set(NextFlat, RestZones, FinalFlats).
|
||||
%% return flats if we've exceeded our years, or recurse if we can keep going
|
||||
NFUTCFrom = NextFlat#flatzone.utc_from,
|
||||
case maxyear_reached(NFUTCFrom) of
|
||||
true ->
|
||||
?debugMsg("maxyear reached from flatten_zone_set"),
|
||||
FinalFlats;
|
||||
false ->
|
||||
flatten_zone_set(NextFlat, RestZones, FinalFlats, EndingRule)
|
||||
end.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
flatten_rule_set(FlatStart=#flatzone{utc_from=UTCFrom, dstoffset=DSTOffset, offset=Offset}
|
||||
, Zone, Rules, Flats) ->
|
||||
, Zone, Rules, CurrentRule, Flats) ->
|
||||
|
||||
|
||||
%% add normalized (possibly inaccurate) dates for sorting
|
||||
%% purposes. note this may be empty. also note this MUST (I think)
|
||||
%% be done in the loop, since UTCFrom and DSTOffset can
|
||||
%% potentially change which rule comes next (however unlikely that
|
||||
%% case may be in real life)
|
||||
ValidRules= lists:delete(CurrentRule, Rules),
|
||||
RulesWithDates= lists:foldl(
|
||||
fun(R, Acc)->
|
||||
case ezic_rule:project_next(R, Offset, DSTOffset, UTCFrom) of
|
||||
@@ -125,12 +130,10 @@ flatten_rule_set(FlatStart=#flatzone{utc_from=UTCFrom, dstoffset=DSTOffset, offs
|
||||
D -> [{D,R} | Acc]
|
||||
end
|
||||
end
|
||||
,[], Rules),
|
||||
,[], ValidRules),
|
||||
|
||||
?debugVal(RulesWithDates),
|
||||
|
||||
|
||||
{ActualEndingRuleDate, EndingRule}=
|
||||
{UTCEndingRuleDate, EndingRule}=
|
||||
case length(RulesWithDates) > 0 of
|
||||
false -> {maximum, none};
|
||||
true -> hd(lists:sort(RulesWithDates))
|
||||
@@ -139,26 +142,45 @@ flatten_rule_set(FlatStart=#flatzone{utc_from=UTCFrom, dstoffset=DSTOffset, offs
|
||||
ZoneDate= ezic_zone:project_end_utc(Zone, DSTOffset),
|
||||
|
||||
|
||||
?debugVal(ActualEndingRuleDate),
|
||||
?debugVal(UTCEndingRuleDate),
|
||||
?debugVal(ZoneDate),
|
||||
|
||||
|
||||
case ezic_date:compare(ActualEndingRuleDate, ZoneDate) of
|
||||
|
||||
case maxyear_reached(UTCEndingRuleDate) andalso maxyear_reached(ZoneDate) of
|
||||
true ->
|
||||
%% same zone, new rule
|
||||
{EndFlat, NextFlat}= finish_and_start_flat(FlatStart, EndingRule, ActualEndingRuleDate, Offset, DSTOffset),
|
||||
NewFlats= [EndFlat | Flats],
|
||||
flatten_rule_set(NextFlat, Zone, Rules, NewFlats);
|
||||
?debugMsg("maxyear reached from flatten_rule_set"),
|
||||
{Flats, #flatzone{utc_from=maximum}, none};
|
||||
false ->
|
||||
%% new zone is handled in the caller: flatten_zone_set
|
||||
{Flats, FlatStart, DSTOffset}
|
||||
|
||||
case ezic_date:compare(ZoneDate, UTCEndingRuleDate) of
|
||||
false ->
|
||||
%% same zone, new rule
|
||||
{EndFlat, NextFlat}= finish_and_start_flat(FlatStart, EndingRule, UTCEndingRuleDate),
|
||||
NewFlats= [EndFlat | Flats],
|
||||
flatten_rule_set(NextFlat, Zone, Rules, EndingRule, NewFlats);
|
||||
true ->
|
||||
% zone change
|
||||
case ezic_date:equal(ZoneDate, UTCEndingRuleDate) of
|
||||
false ->
|
||||
% zone only
|
||||
{IEF, INF}= finish_and_start_flat(FlatStart, Zone, DSTOffset),
|
||||
{[IEF | Flats], INF, CurrentRule};
|
||||
true ->
|
||||
% zone AND rule
|
||||
{IEF, INF}= finish_flatzone_both(FlatStart, Zone, EndingRule, DSTOffset),
|
||||
{[IEF | Flats], INF, EndingRule}
|
||||
end
|
||||
end
|
||||
end.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
finish_and_start_flat(FlatStub=#flatzone{}, NewRule=#rule{save=NewDSTSave}, _EndingRuleDate={{ERDY,_,_},_}, Offset, OldDSTOffset) ->
|
||||
%% rule is ending, while timezone remains
|
||||
finish_and_start_flat(FlatStub=#flatzone{offset=Offset, dstoffset=OldDSTOffset}
|
||||
, NewRule=#rule{save=NewDSTSave}
|
||||
, _EndingRuleDate={{ERDY,_,_},_}) ->
|
||||
|
||||
%% @todo for_rule_all was already called in a loop earlier. use those values instead.
|
||||
{{WD, WDn}, SD, UD}= ezic_date:for_rule(NewRule, Offset, OldDSTOffset, NewDSTSave, ERDY),
|
||||
{WDm, SDm, UDm}= ezic_date:m1s({WD, SD, UD}),
|
||||
@@ -172,9 +194,10 @@ finish_and_start_flat(FlatStub=#flatzone{}, NewRule=#rule{save=NewDSTSave}, _End
|
||||
?debugVal(EndFlat),
|
||||
?debugVal(FinalNewFlat),
|
||||
|
||||
{EndFlat, FinalNewFlat}.
|
||||
{EndFlat, FinalNewFlat};
|
||||
|
||||
|
||||
%% timezone is ending, while rule remains the same.
|
||||
%% returns the finished flatzone for the current zone, and a stub for
|
||||
%% the next zone with the current DST offset and the UTC start
|
||||
%% datetime
|
||||
@@ -186,11 +209,25 @@ finish_and_start_flat(FlatStub=#flatzone{}, Zone=#zone{}, EndingDST) ->
|
||||
RetNextFlat= #flatzone{dstoffset=EndingDST, utc_from=UD},
|
||||
|
||||
?debugVal(EndFlat),
|
||||
?debugVal(RetNextFlat),
|
||||
% ?debugVal(RetNextFlat),
|
||||
|
||||
{EndFlat, RetNextFlat}.
|
||||
|
||||
|
||||
%% both timezone and rule are ending at the same time
|
||||
finish_flatzone_both(FlatStub=#flatzone{}, EndingZone=#zone{}, ChangingRule=#rule{save=NewDST}, EndingDST) ->
|
||||
?debugVal(FlatStub),
|
||||
|
||||
EndDatesP1={WD,SD,UD}= ezic_zone:project_end(EndingZone, EndingDST),
|
||||
{WDm, SDm, UDm}= ezic_date:m1s(EndDatesP1),
|
||||
EndFlat= ?ENDFLAT(FlatStub, WDm, SDm, UDm, EndingDST),
|
||||
|
||||
?debugVal(EndFlat),
|
||||
?debugVal(ChangingRule),
|
||||
|
||||
RetNextFlat= #flatzone{dstoffset=NewDST, utc_from=UD},
|
||||
{EndFlat, RetNextFlat}.
|
||||
|
||||
|
||||
populate_flatzone(
|
||||
FZ=#flatzone{utc_from=UTCFrom, dstoffset=DSTOffset}
|
||||
@@ -199,3 +236,14 @@ populate_flatzone(
|
||||
UTCFromTZ= ezic_date:normalize(UTCFrom, u),
|
||||
{WT, ST, UTCFRom}= ezic_date:all_times(UTCFromTZ, Offset, DSTOffset),
|
||||
FZ#flatzone{offset=Offset, tzname=Name, wall_from=WT, std_from=ST}.
|
||||
|
||||
|
||||
|
||||
maxyear_reached({{Y,_,_},_}) when Y > ?MAXYEAR ->
|
||||
true;
|
||||
maxyear_reached({{Y,_,_},_}) when Y =< ?MAXYEAR ->
|
||||
false;
|
||||
maxyear_reached(Atom) when Atom=:=maximum; Atom=:=current ->
|
||||
true; % for some N, taking n > N => maximum > ?MAXYEAR
|
||||
maxyear_reached(Val) ->
|
||||
erlang:error(bad_year, Val).
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
-export([project_next/4]).
|
||||
|
||||
|
||||
|
||||
parse([Name,FromS,ToS,_Type,InS,OnS,AtS,SaveS,Letters]) ->
|
||||
From= ezic_parse:year(FromS),
|
||||
To= ezic_parse:year(ToS),
|
||||
@@ -29,8 +30,8 @@ parse([Name,FromS,ToS,_Type,InS,OnS,AtS,SaveS,Letters]) ->
|
||||
project_next(Rule=#rule{from=RFrom}, Offset, DSTOffset, minimum) ->
|
||||
ezic_date:for_rule_utc(Rule, Offset, DSTOffset, RFrom);
|
||||
project_next(Rule=#rule{}, Offset, DSTOff, UTCAfter={{AY,_,_},_}) ->
|
||||
AllYears= years(Rule),
|
||||
GoodYears= years_after(AY, AllYears),
|
||||
YearRange= years(Rule),
|
||||
GoodYears= years_after(AY, YearRange),
|
||||
project_next2(Rule, Offset, UTCAfter, DSTOff, GoodYears).
|
||||
|
||||
|
||||
@@ -39,41 +40,41 @@ project_next(Rule=#rule{}, Offset, DSTOff, UTCAfter={{AY,_,_},_}) ->
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
% returns the sorted list of years a rule existed for.
|
||||
% returns the range of years a rule existed for, normalized for calculations.
|
||||
years(#rule{from=From, to=only}) ->
|
||||
[From];
|
||||
{From,From};
|
||||
years(#rule{from=From, to=X}) when X=:=max; X=:=maximum->
|
||||
[From,9999]; % let's hope this isn't used past year 9999
|
||||
{From,X};
|
||||
years(#rule{from=From, to=To}) when From =< To, is_integer(From), is_integer(To) ->
|
||||
{From, To};
|
||||
years(#rule{from=From, to=To}) ->
|
||||
try lists:seq(From, To)
|
||||
catch error:function_clause ->
|
||||
erlang:error(bad_year_range, [From, To])
|
||||
end.
|
||||
erlang:error(bad_year_range, [From, To]).
|
||||
|
||||
% returns the years from the list that are greater than OR equal to Y
|
||||
years_after(_, []) ->
|
||||
[];
|
||||
years_after(Y, Years) ->
|
||||
{GOOD, _}= lists:partition(
|
||||
fun(X) when Y =< X -> true;
|
||||
(_) -> false
|
||||
end, Years),
|
||||
GOOD.
|
||||
|
||||
%% returns the range of years that are greater than OR equal to Y.
|
||||
%% calculation stops after a fixed year, configurable above.
|
||||
years_after(Y, {F,M}) when M=:=max; M=:=maximum ->
|
||||
{erlang:max(Y,F), M};
|
||||
years_after(Y, {From, To}) when Y > To ->
|
||||
none;
|
||||
years_after(Y, {From, To}) ->
|
||||
{erlang:max(Y,From), To}.
|
||||
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% INTERNAL
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
|
||||
project_next2(_,_,_,_,[]) ->
|
||||
project_next2(_,_,_,_,none) ->
|
||||
none;
|
||||
project_next2(Rule, Offset, UTCAfter, DSTOffset, [Year|RestYears]) ->
|
||||
RuleDate= ezic_date:for_rule_utc(Rule, Offset, DSTOffset, Year),
|
||||
project_next2(Rule, Offset, UTCAfter, DSTOffset, Years={FromYear, _}) ->
|
||||
RuleDate= ezic_date:for_rule_utc(Rule, Offset, DSTOffset, FromYear),
|
||||
case ezic_date:compare(UTCAfter, RuleDate) andalso (not ezic_date:equal(UTCAfter, RuleDate)) of
|
||||
true -> RuleDate;
|
||||
_ -> project_next2(Rule, Offset, UTCAfter, DSTOffset, RestYears)
|
||||
false ->
|
||||
RestYears= years_after(FromYear+1, Years),
|
||||
project_next2(Rule, Offset, UTCAfter, DSTOffset, RestYears)
|
||||
end.
|
||||
|
||||
|
||||
@@ -91,9 +92,13 @@ project_next2(Rule, Offset, UTCAfter, DSTOffset, [Year|RestYears]) ->
|
||||
|
||||
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}))
|
||||
?_assertEqual({1952,1952}, years(#rule{from=1952,to=only}))
|
||||
, ?_assertEqual({1952,1953}, years(#rule{from=1952,to=1953}))
|
||||
, ?_assertEqual({1952,1955}, years(#rule{from=1952,to=1955}))
|
||||
|
||||
, ?_assertEqual({1952,max}, years(#rule{from=1952,to=max}))
|
||||
, ?_assertEqual({1952,maximum}, years(#rule{from=1952,to=maximum}))
|
||||
|
||||
, ?_assertError(bad_year_range, years(#rule{from=1955,to=1952}))
|
||||
].
|
||||
|
||||
@@ -101,11 +106,14 @@ years_test_() ->
|
||||
% @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, []))
|
||||
?_assertEqual({2010,2010}, years_after(2010, {2010,2010}))
|
||||
, ?_assertEqual({2010,2011}, years_after(2010, {2010,2011}))
|
||||
, ?_assertEqual({2011,2011}, years_after(2011, {2010,2011}))
|
||||
|
||||
, ?_assertEqual({2011,max}, years_after(2011, {2010,max}))
|
||||
, ?_assertEqual({2010,max}, years_after(2009, {2010,max}))
|
||||
|
||||
, ?_assertEqual(none, years_after(2012, {2010,2011}))
|
||||
].
|
||||
|
||||
-endif.
|
||||
|
||||
Reference in New Issue
Block a user