Costa Rica's flatzones aren't processed after 1992. Gotta check her out.

This commit is contained in:
aj
2010-11-13 22:54:44 -08:00
parent 3f438e66e0
commit d664384c60
9 changed files with 133 additions and 53 deletions

View File

@@ -8,7 +8,7 @@
, next_timechange_after/2
]).
-export([load/1, dev_start/0, test/0]).
-export([load/1, dev/0, test/0]).
@@ -21,13 +21,19 @@
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),
ezic_date:add_seconds(UTCDatetime, SecDiff).
%% utc_to_local(UTCDatetime, TzName) ->
%% {ok, Zone, Rule}= current_as_of_utc(UTCDatetime, TzName),
%% SecDiff= time_offset(Zone, Rule),
%% ezic_date:add_seconds(UTCDatetime, SecDiff).
utc_to_local(UTCDatetime, TzName) ->
#flatzone{offset=Offset, dstoffset=DSTOffset}= ezic_db:flatzone(UTCDatetime, TzName),
ezic_date:add_offset(ezic_date:add_offset(UTCDatetime, Offset), DSTOffset).
next_timechange(TzName) ->
next_timechange_after(erlang:universaltime(), TzName).
@@ -48,11 +54,13 @@ load(Folder) ->
ezic_loader:load(Folder).
dev_start() ->
% ezic:load(filename:join("priv","tzdata")),
% ezic_flatten:flatten().
TZones= ezic_db:zones("Africa/Tripoli"),
ezic_flatten:flatten_all_zones(TZones).
dev() ->
ezic:load(filename:join("priv","tzdata")),
ezic_flatten:flatten(),
% Zones= ezic_db:zones("WET"),
% ezic_flatten:flatten_all_zones(Zones),
ok.
test() ->

View File

@@ -47,13 +47,12 @@ normalize(A) when is_atom(A) ->
A;
normalize(Y) when is_integer(Y) ->
{{Y,1,1}, #tztime{}};
normalize(Date={Y,M,D})
when is_integer(Y), is_integer(M), is_integer(D) ->
{Date, #tztime{}};
normalize(R={{_,_,_}, #tztime{}}) ->
R;
normalize({D={_,_,_}, T={_,_,_}}) ->
{D, #tztime{time=T}}.
normalize({Y,M,D}) ->
{relative_date(Y,M,D), #tztime{}};
normalize({{Y,M,D}, T=#tztime{}}) ->
{relative_date(Y,M,D), T};
normalize({{Y,M,D}, T={_,_,_}}) ->
{relative_date(Y,M,D), #tztime{time=T}}.
%% normalizes a date, and sets the #tztime{flag=Flag} if appropriate
@@ -76,23 +75,26 @@ normalize(D, Flag) ->
%% returns RELATIVE datetime for a rule and Year
%% -> {{Y,M,D},#tztime{}} | {{Y,M,D},{HH,MM,SS}}
for_rule_relative(#rule{in=M, on=D, at=At}, Y) when is_integer(D) ->
{{Y,M,D}, At};
for_rule_relative(#rule{in=M, on={last, D}, at=At}, Y) ->
{last_day_of(D, Y,M), At};
for_rule_relative(#rule{in=M, on=#tzon{day=Day, filter=Filter}, at=At}, Y) ->
{first_day_limited(Day, Filter, Y,M), At}.
for_rule_relative(#rule{in=M, on=D, at=At}, Y) ->
{relative_date(Y,M,D), At}.
relative_date(Y,M,D) when is_integer(D) ->
{Y,M,D};
relative_date(Y,M,{last, D}) ->
last_day_of(D, Y,M);
relative_date(Y,M,#tzon{day=Day, filter=Filter}) ->
first_day_limited(Day, Filter, Y,M).
%% 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.
%% @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),

View File

@@ -4,7 +4,7 @@
-include_lib("eunit/include/eunit.hrl").
-export([zones/1, rules/1]).
-export([zones/1, rules/1, flatzones/1, flatzone/2]).
-export([wipe/0, init/0, insert_all/1, get_all/1]).
@@ -49,6 +49,29 @@ get_all(Tab) when is_atom(Tab) ->
end,
{atomic, Ret}= mnesia:transaction(F),
Ret.
flatzones(TzName) ->
F = fun() ->
Q = qlc:q([Fz || Fz=#flatzone{tzname=N}<- mnesia:table(flatzone), N=:=TzName]),
qlc:e(Q)
end,
{atomic, Ret}= mnesia:transaction(F),
Ret.
flatzone(Date, TzName) ->
F = fun()->
Q = qlc:q(
[Fz || Fz=#flatzone{tzname=N, utc_from=UF, utc_to=UT} <- mnesia:table(flatzone)
, N=:=TzName
, ezic_date:compare(UF, Date)
, ezic_date:compare(Date, UT)]),
qlc:e(Q)
end,
{atomic, [FlatZone]}= mnesia:transaction(F),
FlatZone.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -76,7 +99,7 @@ insert_all(Records) ->
% initialize the db
init() ->
create_tabs(mnesia:create_schema([node()])),
mnesia:wait_for_tables([rule, zone, link, leap], 3000).
mnesia:wait_for_tables([rule, zone, link, leap, flatzone], 3000).
% WARNING: deletes all db files

View File

@@ -37,6 +37,7 @@ flatten() ->
flatten_all_zones([]) ->
done;
flatten_all_zones([Z1|_]= AllZones) ->
io:format("Flattening zones: ~s~n", [Z1#zone.name]),
{CurrentZones, RestZones}= ezic_zone:split_by_name(Z1, AllZones),
Flats= flatten_zone_set(CurrentZones),
@@ -71,7 +72,7 @@ flatten_zone_set(FromTimeStub=#flatzone{utc_from=UTCFrom, dstoffset=DSTOffset}
, CurrentRule) ->
[Zone | RestZones] = ezic_zone:next(Zones, UTCFrom, DSTOffset),
#zone{rule=RuleName, until=_UntilTime, gmtoff=Offset}= Zone,
#zone{rule=RuleName}= Zone,
?debugVal(Zone),
@@ -106,12 +107,17 @@ flatten_zone_set(FromTimeStub=#flatzone{utc_from=UTCFrom, dstoffset=DSTOffset}
%% 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
try maxyear_reached(NFUTCFrom) of
true ->
?debugMsg("maxyear reached from flatten_zone_set"),
FinalFlats;
false ->
flatten_zone_set(NextFlat, RestZones, FinalFlats, EndingRule)
catch
exit:Reason ->
?debugMsg("bad year for nextflat:"),
?debugVal(NextFlat),
erlang:error(Reason)
end.
@@ -121,21 +127,25 @@ flatten_zone_set(FromTimeStub=#flatzone{utc_from=UTCFrom, dstoffset=DSTOffset}
flatten_rule_set(FlatStart=#flatzone{utc_from=UTCFrom, dstoffset=DSTOffset, offset=Offset}
, Zone, Rules, CurrentRule, Flats) ->
?debugVal(Offset),
?debugVal(DSTOffset),
?debugVal(UTCFrom),
ValidRules= lists:delete(CurrentRule, Rules),
RulesWithDates= lists:foldl(
fun(R, Acc)->
case ezic_rule:project_next(R, Offset, DSTOffset, UTCFrom) of
none -> Acc;
D -> [{D,R} | Acc]
{Year, D} -> [{D,Year, R} | Acc]
end
end
,[], ValidRules),
{UTCEndingRuleDate, EndingRule}=
{UTCEndingRuleDate, EndingRuleYear, EndingRule}=
case length(RulesWithDates) > 0 of
false -> {maximum, none};
false -> {maximum, maximum, none};
true -> hd(lists:sort(RulesWithDates))
end,
@@ -143,10 +153,12 @@ flatten_rule_set(FlatStart=#flatzone{utc_from=UTCFrom, dstoffset=DSTOffset, offs
?debugVal(UTCEndingRuleDate),
?debugVal(EndingRuleYear),
?debugVal(EndingRule),
?debugVal(ZoneDate),
case maxyear_reached(UTCEndingRuleDate) andalso maxyear_reached(ZoneDate) of
try maxyear_reached(UTCEndingRuleDate) andalso maxyear_reached(ZoneDate) of
true ->
?debugMsg("maxyear reached from flatten_rule_set"),
{Flats, #flatzone{utc_from=maximum}, none};
@@ -155,7 +167,7 @@ flatten_rule_set(FlatStart=#flatzone{utc_from=UTCFrom, dstoffset=DSTOffset, offs
case ezic_date:compare(ZoneDate, UTCEndingRuleDate) of
false ->
%% same zone, new rule
{EndFlat, NextFlat}= finish_and_start_flat(FlatStart, EndingRule, UTCEndingRuleDate),
{EndFlat, NextFlat}= finish_and_start_flat(FlatStart, EndingRule, EndingRuleYear),
NewFlats= [EndFlat | Flats],
flatten_rule_set(NextFlat, Zone, Rules, EndingRule, NewFlats);
true ->
@@ -171,6 +183,10 @@ flatten_rule_set(FlatStart=#flatzone{utc_from=UTCFrom, dstoffset=DSTOffset, offs
{[IEF | Flats], INF, EndingRule}
end
end
catch
error:{bad_year,Val} ->
io:format("bad year for EndingRule: ~p~n", [EndingRule]),
erlang:error(bad_year, Val)
end.
@@ -179,10 +195,10 @@ flatten_rule_set(FlatStart=#flatzone{utc_from=UTCFrom, dstoffset=DSTOffset, offs
%% rule is ending, while timezone remains
finish_and_start_flat(FlatStub=#flatzone{offset=Offset, dstoffset=OldDSTOffset}
, NewRule=#rule{save=NewDSTSave}
, _EndingRuleDate={{ERDY,_,_},_}) ->
, EndingRuleYear) ->
%% @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),
{{WD, WDn}, SD, UD}= ezic_date:for_rule(NewRule, Offset, OldDSTOffset, NewDSTSave, EndingRuleYear),
{WDm, SDm, UDm}= ezic_date:m1s({WD, SD, UD}),
EndFlat= ?ENDFLAT(FlatStub, WDm, SDm, UDm, OldDSTOffset),
@@ -202,7 +218,7 @@ finish_and_start_flat(FlatStub=#flatzone{offset=Offset, dstoffset=OldDSTOffset}
%% the next zone with the current DST offset and the UTC start
%% datetime
finish_and_start_flat(FlatStub=#flatzone{}, Zone=#zone{}, EndingDST) ->
EndDatesP1={WD,SD,UD}= ezic_zone:project_end(Zone, EndingDST),
EndDatesP1={_,_,UD}= ezic_zone:project_end(Zone, EndingDST),
{WDm, SDm, UDm}= ezic_date:m1s(EndDatesP1),
EndFlat= ?ENDFLAT(FlatStub, WDm, SDm, UDm, EndingDST),
@@ -218,7 +234,7 @@ finish_and_start_flat(FlatStub=#flatzone{}, Zone=#zone{}, EndingDST) ->
finish_flatzone_both(FlatStub=#flatzone{}, EndingZone=#zone{}, ChangingRule=#rule{save=NewDST}, EndingDST) ->
?debugVal(FlatStub),
EndDatesP1={WD,SD,UD}= ezic_zone:project_end(EndingZone, EndingDST),
EndDatesP1={_,_,UD}= ezic_zone:project_end(EndingZone, EndingDST),
{WDm, SDm, UDm}= ezic_date:m1s(EndDatesP1),
EndFlat= ?ENDFLAT(FlatStub, WDm, SDm, UDm, EndingDST),
@@ -231,10 +247,10 @@ finish_flatzone_both(FlatStub=#flatzone{}, EndingZone=#zone{}, ChangingRule=#rul
populate_flatzone(
FZ=#flatzone{utc_from=UTCFrom, dstoffset=DSTOffset}
, Zone=#zone{name=Name, gmtoff=Offset}) ->
, #zone{name=Name, gmtoff=Offset}) ->
UTCFromTZ= ezic_date:normalize(UTCFrom, u),
{WT, ST, UTCFRom}= ezic_date:all_times(UTCFromTZ, Offset, DSTOffset),
{WT, ST, _}= ezic_date:all_times(UTCFromTZ, Offset, DSTOffset),
FZ#flatzone{offset=Offset, tzname=Name, wall_from=WT, std_from=ST}.

View File

@@ -25,16 +25,20 @@ parse([Name,FromS,ToS,_Type,InS,OnS,AtS,SaveS,Letters]) ->
% 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.
% 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) ->
ezic_date:for_rule_utc(Rule, Offset, DSTOffset, RFrom);
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
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -71,7 +75,7 @@ project_next2(_,_,_,_,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 -> RuleDate;
true -> {FromYear, RuleDate};
false ->
RestYears= years_after(FromYear+1, Years),
project_next2(Rule, Offset, UTCAfter, DSTOffset, RestYears)

View File

@@ -85,6 +85,7 @@ project_end(#zone{until=Until, gmtoff=Offset}, DSTOffset) ->
NUntil= ezic_date:normalize(Until),
ezic_date:all_times(NUntil, Offset, DSTOffset).
% returns just the UTC datetime projected for zone end
project_end_utc(Zone=#zone{}, DSTOffset) ->
% ?debugVal(Zone),