11module Olsen
22
33using Base. Dates
4- import Base. Dates: value, toms
54
6- import .. TimeZones: TZDATA_DIR, COMPILED_DIR
7- import .. TimeZones: TimeZone, FixedTimeZone, VariableTimeZone, Transition
5+ import .. TimeZones: TZDATA_DIR, COMPILED_DIR, ZERO, MIN_GMT_OFFSET, MAX_GMT_OFFSET,
6+ MIN_SAVE, MAX_SAVE, ABS_DIFF_OFFSET, Time, toseconds
7+ import .. TimeZones: TimeZone, FixedTimeZone, VariableTimeZone, Transition, Time
88
99const REGIONS = (
1010 " africa" , " antarctica" , " asia" , " australasia" ,
1111 " europe" , " northamerica" , " southamerica" ,
1212)
1313
14- # Convenience type for working with HH:MM:SS.
15- immutable Time <: TimePeriod
16- seconds:: Int
17- end
18- const ZERO = Time (0 )
19-
20- function Time (hour:: Int , minute:: Int , second:: Int )
21- Time (hour * 3600 + minute * 60 + second)
22- end
23-
24- function Time (s:: String )
25- # "-" represents 0:00 for some DST rules
26- s == " -" && return ZERO
27- parsed = map (n -> parse (Int, n), split (s, ' :' ))
28-
29- # Only can handle up to hour, minute, second.
30- length (parsed) > 3 && error (" Invalid Time string" )
31- any (parsed[2 : end ] .< 0 ) && error (" Invalid Time string" )
32-
33- # Handle variations where minutes and seconds may be excluded.
34- values = [0 ,0 ,0 ]
35- values[1 : length (parsed)] = parsed
36-
37- if values[1 ] < 0
38- for i in 2 : length (values)
39- values[i] = - values[i]
40- end
41- end
42-
43- return Time (values... )
44- end
45-
46- # TimePeriod methods
47- value (t:: Time ) = t. seconds
48- toms (t:: Time ) = t. seconds * 1000
49-
50- toseconds (t:: Time ) = t. seconds
51- hour (t:: Time ) = div (toseconds (t), 3600 )
52- minute (t:: Time ) = rem (div (toseconds (t), 60 ), 60 )
53- second (t:: Time ) = rem (toseconds (t), 60 )
54-
55- function hourminutesecond (t:: Time )
56- h, r = divrem (toseconds (t), 3600 )
57- m, s = divrem (r, 60 )
58- return h, m, s
59- end
60-
61- Base. convert (:: Type{Second} , t:: Time ) = Second (toseconds (t))
62- Base. convert (:: Type{Millisecond} , t:: Time ) = Millisecond (toseconds (t) * 1000 )
63- Base. promote_rule {P<:Union{Week,Day,Hour,Minute,Second}} (:: Type{P} , :: Type{Time} ) = Second
64- Base. promote_rule (:: Type{Millisecond} , :: Type{Time} ) = Millisecond
65-
66- # Should be defined in Base.Dates
67- Base. isless (x:: Period , y:: Period ) = isless (promote (x,y)... )
68-
69- # https://en.wikipedia.org/wiki/ISO_8601#Times
70- function Base. string (t:: Time )
71- neg = toseconds (t) < 0 ? " -" : " "
72- h, m, s = map (abs, hourminutesecond (t))
73- @sprintf (" %s%02d:%02d:%02d" , neg, h, m, s)
74- end
75-
76- Base. show (io:: IO , t:: Time ) = print (io, string (t))
77-
78- # min/max offsets across all zones and all time.
79- const MINOFFSET = Time (" -15:56:00" ) # Asia/Manilla
80- const MAXOFFSET = Time (" 15:13:42" ) # America/Metlakatla
81-
82- # min/max save across all zones/rules and all time.
83- const MINSAVE = Time (" 00:00" )
84- const MAXSAVE = Time (" 02:00" ) # France, Germany, Port, Spain
85-
86- const MAXABSDIFF = abs ((MAXOFFSET + MAXSAVE) - (MINOFFSET + MINSAVE))
87-
8814# Zone type maps to an Olsen Timezone database entity
8915type Zone
9016 gmtoffset:: Time
@@ -101,7 +27,7 @@ function Base.isless(x::Zone,y::Zone)
10127
10228 # Easy to compare until's if they are using the same flag. Alternatively, it should
10329 # be safe to compare different until flags if the DateTimes are far enough apart.
104- if x. until_flag == y. until_flag || abs (x_dt - y_dt) > MAXABSDIFF
30+ if x. until_flag == y. until_flag || abs (x_dt - y_dt) > ABS_DIFF_OFFSET
10531 return isless (x_dt, y_dt)
10632 else
10733 error (" Unable to compare zones when until datetimes are too close and flags are mixed" )
@@ -249,8 +175,8 @@ function ruleparse(from, to, rule_type, month, on, at, save, letter)
249175 letter = letter == " -" ? " " : letter
250176
251177 # Report unexpected save values that could cause issues during resolve.
252- save_hm < MINSAVE && warn (" Discovered save $save_hm less than the expected min $MINSAVE " )
253- save_hm > MAXSAVE && warn (" Discovered save $save_hm larger than the expected max $MAXSAVE " )
178+ save_hm < MIN_SAVE && warn (" Discovered save $save_hm less than the expected min $MIN_SAVE " )
179+ save_hm > MAX_SAVE && warn (" Discovered save $save_hm larger than the expected max $MAX_SAVE " )
254180
255181 # Now we've finally parsed everything we need
256182 return Rule (
@@ -270,8 +196,8 @@ function zoneparse(gmtoff, rules, format, until="")
270196 offset = Time (gmtoff)
271197
272198 # Report unexpected offsets that could cause issues during resolve.
273- offset < MINOFFSET && warn (" Discovered offset $offset less than the expected min $MINOFFSET " )
274- offset > MAXOFFSET && warn (" Discovered offset $offset larger than the expected max $MAXOFFSET " )
199+ offset < MIN_GMT_OFFSET && warn (" Discovered offset $offset less than the expected min $MIN_GMT_OFFSET " )
200+ offset > MAX_GMT_OFFSET && warn (" Discovered offset $offset larger than the expected max $MAX_GMT_OFFSET " )
275201
276202 format = format == " zzz" ? " " : format
277203
@@ -347,7 +273,7 @@ function order_rules(rules::Array{Rule})
347273 # there is a small chance that the results are not ordered correctly.
348274 last_date = typemin (Date)
349275 for (i, (date, rule)) in enumerate (date_rules)
350- if i > 1 && date - last_date <= MAXABSDIFF
276+ if i > 1 && date - last_date <= ABS_DIFF_OFFSET
351277 error (" Dates are probably not in order" )
352278 end
353279 last_date = date
0 commit comments