124 lines
3.8 KiB
Erlang
124 lines
3.8 KiB
Erlang
-module(ezic_rule).
|
|
-include("include/ezic.hrl").
|
|
|
|
|
|
-export([parse/1]).
|
|
-export([project_next/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}.
|
|
|
|
|
|
|
|
% returns {Year, UTCDate} where UTCDate is 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, and Year is the rule
|
|
% year (which may differ from the UTC year).
|
|
project_next(Rule=#rule{from=RFrom}, Offset, DSTOffset, minimum) ->
|
|
RetDate={{RetYear,_,_},_}= ezic_date:for_rule_utc(Rule, Offset, DSTOffset, RFrom),
|
|
{RetYear, RetDate};
|
|
project_next(Rule=#rule{}, Offset, DSTOff, UTCAfter={{AY,_,_},_}) ->
|
|
YearRange= years(Rule),
|
|
GoodYears= years_after(AY, YearRange),
|
|
project_next2(Rule, Offset, UTCAfter, DSTOff, GoodYears).
|
|
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
% PRIVATE
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
|
|
% returns the range of years a rule existed for, normalized for calculations.
|
|
years(#rule{from=From, to=only}) ->
|
|
{From,From};
|
|
years(#rule{from=From, to=X}) when X=:=max; X=:=maximum->
|
|
{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}) ->
|
|
erlang:error(bad_year_range, [From, To]).
|
|
|
|
%% 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(_,_,_,_,none) ->
|
|
none;
|
|
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 -> {FromYear, RuleDate};
|
|
false ->
|
|
RestYears= years_after(FromYear+1, Years),
|
|
project_next2(Rule, Offset, UTCAfter, DSTOffset, RestYears)
|
|
end.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
% Tests of Private Methods
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
|
|
-ifdef(TEST).
|
|
-include_lib("eunit/include/eunit.hrl").
|
|
|
|
years_test_() ->
|
|
[
|
|
?_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}))
|
|
].
|
|
|
|
|
|
% @todo type checking. lack of types worries me sometimes :(
|
|
years_after_test_() ->
|
|
[
|
|
?_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.
|