@@ -10,16 +10,22 @@ const tzsample = "VFppZjIAAAAAAAAAAAAAAAAAAAAAAAAGAAAABgAAAAAAAADsAAAABgAAABSAAA
1010
1111const tzsample2 = "VFppZjIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAQAAAAAAABVVEMAVFppZjIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAQAAAAAAABVVEMAClVUQzAK"
1212
13+ const canberra = "VFppZjIAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAACOAAAABAAAAA6AAAAAnE7CgJy8LwDLVLMAy8dlgMy3VoDNp0eAzqBzAM+HKYADcDmABA0cAAVQG4AF9jiABy/9gAfWGoAJD9+ACbX8gArvwYALnxkADNjeAA1++wAOuMAAD17dABCYogARPr8AEniEABMeoQAUWGYAFP6DABY4SAAXDImAGCFkgBjHgYAaAUaAGqdjgBvhKIAch0WAHcEKgB55nIAfl7IAIFl+gCGAzoAiQpsAI2nrACQifQAlSc0AJe/qACcprwAnz8wAKQmRACmvrgAq6XMAK5jKgCzSj4AteKyALrJxgC9YjoAwklOAMV1agDJyNYAzPTyANFIXgDUdHoA2MfmANv0AgDgbFgA43OKAOafpgDq8xIA72toAPKXhAD26vAA+hcMAP5qeAEBlpQBBg7qAQkWHAENjnIBELqOARUN+gEYFSwBHI2CAR/eiAEjnkwBJ14QASsd1AEu3ZgBMp1cATZdIAE6HOQBPdyoAUHBVgFFgRoBSUDeAU0AogFQwGYBVIAqAVg/7gFb/7IBX792AWN/OgFnPv4Bav7CAW7jcAFyozQBdmL4AXoivAF94oABgaJEAYViCAGJIcwBjOGQAZChVAGUYRgBmEXGAZwFigGfxU4Bo4USAadE1gGrBJoBrsReAbKEIgG2Q+YBugOqAb3DbgHBqBwBxWfgAcknpAHM52gB0KcsAdRm8AHYJrQB2+Z4Ad+mPAHjZgAB5yXEAerliAHuyjYB8on6AfZJvgH6CYIB/clGAAwECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQAAjcQAAAAAmrABBAAAjKAACQAAjKAACUxNVABBRURUAEFFU1QAAAEBAFRaaWYyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAjgAAAAQAAAAO/////3MWfzz/////nE7CgP////+cvC8A/////8tUswD/////y8dlgP/////Mt1aA/////82nR4D/////zqBzAP/////PhymAAAAAAANwOYAAAAAABA0cAAAAAAAFUBuAAAAAAAX2OIAAAAAABy/9gAAAAAAH1hqAAAAAAAkP34AAAAAACbX8gAAAAAAK78GAAAAAAAufGQAAAAAADNjeAAAAAAANfvsAAAAAAA64wAAAAAAAD17dAAAAAAAQmKIAAAAAABE+vwAAAAAAEniEAAAAAAATHqEAAAAAABRYZgAAAAAAFP6DAAAAAAAWOEgAAAAAABcMiYAAAAAAGCFkgAAAAAAYx4GAAAAAABoBRoAAAAAAGqdjgAAAAAAb4SiAAAAAAByHRYAAAAAAHcEKgAAAAAAeeZyAAAAAAB+XsgAAAAAAIFl+gAAAAAAhgM6AAAAAACJCmwAAAAAAI2nrAAAAAAAkIn0AAAAAACVJzQAAAAAAJe/qAAAAAAAnKa8AAAAAACfPzAAAAAAAKQmRAAAAAAApr64AAAAAACrpcwAAAAAAK5jKgAAAAAAs0o+AAAAAAC14rIAAAAAALrJxgAAAAAAvWI6AAAAAADCSU4AAAAAAMV1agAAAAAAycjWAAAAAADM9PIAAAAAANFIXgAAAAAA1HR6AAAAAADYx+YAAAAAANv0AgAAAAAA4GxYAAAAAADjc4oAAAAAAOafpgAAAAAA6vMSAAAAAADva2gAAAAAAPKXhAAAAAAA9urwAAAAAAD6FwwAAAAAAP5qeAAAAAABAZaUAAAAAAEGDuoAAAAAAQkWHAAAAAABDY5yAAAAAAEQuo4AAAAAARUN+gAAAAABGBUsAAAAAAEcjYIAAAAAAR/eiAAAAAABI55MAAAAAAEnXhAAAAAAASsd1AAAAAABLt2YAAAAAAEynVwAAAAAATZdIAAAAAABOhzkAAAAAAE93KgAAAAAAUHBVgAAAAABRYEaAAAAAAFJQN4AAAAAAU0AogAAAAABUMBmAAAAAAFUgCoAAAAAAVg/7gAAAAABW/+yAAAAAAFfv3YAAAAAAWN/OgAAAAABZz7+AAAAAAFq/sIAAAAAAW7jcAAAAAABcqM0AAAAAAF2YvgAAAAAAXoivAAAAAABfeKAAAAAAAGBokQAAAAAAYViCAAAAAABiSHMAAAAAAGM4ZAAAAAAAZChVAAAAAABlGEYAAAAAAGYRcYAAAAAAZwFigAAAAABn8VOAAAAAAGjhRIAAAAAAadE1gAAAAABqwSaAAAAAAGuxF4AAAAAAbKEIgAAAAABtkPmAAAAAAG6A6oAAAAAAb3DbgAAAAABwagcAAAAAAHFZ+AAAAAAAcknpAAAAAABzOdoAAAAAAHQpywAAAAAAdRm8AAAAAAB2Ca0AAAAAAHb5ngAAAAAAd+mPAAAAAAB42YAAAAAAAHnJcQAAAAAAerliAAAAAAB7so2AAAAAAHyifoAAAAAAfZJvgAAAAAB+gmCAAAAAAH9yUYADAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAgECAQIBAACNxAAAAACasAEEAACMoAAJAACMoAAJTE1UAEFFRFQAQUVTVAAAAQEACkFFU1QtMTBBRURULE0xMC4xLjAsTTQuMS4wLzMK"
14+
1315fn get_database ( ) -> database . TzDatabase {
1416 let assert Ok ( tzdata ) = bit_array . base64_decode ( tzsample )
1517 let assert Ok ( tz_ny ) = parser . parse ( tzdata )
1618
1719 let assert Ok ( tzdata2 ) = bit_array . base64_decode ( tzsample2 )
1820 let assert Ok ( tz_utc ) = parser . parse ( tzdata2 )
1921
22+ let assert Ok ( tzdata3 ) = bit_array . base64_decode ( canberra )
23+ let assert Ok ( tz_au ) = parser . parse ( tzdata3 )
24+
2025 database . new ( )
2126 |> database . add_tzfile ( "America/New_York" , tz_ny )
2227 |> database . add_tzfile ( "UTC" , tz_utc )
28+ |> database . add_tzfile ( "Australia/Canberra" , tz_au )
2329}
2430
2531pub fn get_time_in_local_zone_test ( ) {
@@ -67,3 +73,196 @@ pub fn get_time_only_in_utc_zone_test() {
6773 calendar.TimeOfDay(5, 18, 0, 0),
6874 ))
6975}
76+
77+ pub fn timestamp_from_calendar_test() {
78+ let db = get_database()
79+ assert tzcalendar.from_calendar(
80+ calendar.Date(2025, calendar.January, 23),
81+ calendar.TimeOfDay(13, 0, 0, 0),
82+ "America/New_York",
83+ db,
84+ )
85+ == Ok([timestamp.from_unix_seconds(1_737_655_200)])
86+ }
87+
88+ pub fn us_daylight_start_test() {
89+ let db = get_database()
90+ let dst_start_date = calendar.Date(2025, calendar.March, 9)
91+
92+ let one = calendar.TimeOfDay(1, 0, 0, 0)
93+ let one_thirty = calendar.TimeOfDay(1, 30, 0, 0)
94+ let two = calendar.TimeOfDay(2, 0, 0, 0)
95+ let two_thirty = calendar.TimeOfDay(2, 30, 0, 0)
96+ let three = calendar.TimeOfDay(3, 0, 0, 0)
97+ let three_thirty = calendar.TimeOfDay(3, 30, 0, 0)
98+
99+ assert tzcalendar.from_calendar(dst_start_date, one, "America/New_York", db)
100+ == Ok([timestamp.from_unix_seconds(1_741_500_000)])
101+ assert tzcalendar.from_calendar(
102+ dst_start_date,
103+ one_thirty,
104+ "America/New_York",
105+ db,
106+ )
107+ == Ok([timestamp.from_unix_seconds(1_741_501_800)])
108+ assert tzcalendar.from_calendar(dst_start_date, two, "America/New_York", db)
109+ == Ok([])
110+ assert tzcalendar.from_calendar(
111+ dst_start_date,
112+ two_thirty,
113+ "America/New_York",
114+ db,
115+ )
116+ == Ok([])
117+ assert tzcalendar.from_calendar(dst_start_date, three, "America/New_York", db)
118+ == Ok([timestamp.from_unix_seconds(1_741_503_600)])
119+ assert tzcalendar.from_calendar(
120+ dst_start_date,
121+ three_thirty,
122+ "America/New_York",
123+ db,
124+ )
125+ == Ok([timestamp.from_unix_seconds(1_741_505_400)])
126+ }
127+
128+ pub fn us_daylight_stop_test() {
129+ let db = get_database()
130+ let dst_start_date = calendar.Date(2025, calendar.November, 2)
131+
132+ let one = calendar.TimeOfDay(1, 0, 0, 0)
133+ let one_thirty = calendar.TimeOfDay(1, 30, 0, 0)
134+ let two = calendar.TimeOfDay(2, 0, 0, 0)
135+ let two_thirty = calendar.TimeOfDay(2, 30, 0, 0)
136+ let three = calendar.TimeOfDay(3, 0, 0, 0)
137+ let three_thirty = calendar.TimeOfDay(3, 30, 0, 0)
138+
139+ assert tzcalendar.from_calendar(dst_start_date, one, "America/New_York", db)
140+ == Ok([
141+ timestamp.from_unix_seconds(1_762_059_600),
142+ timestamp.from_unix_seconds(1_762_063_200),
143+ ])
144+ assert tzcalendar.from_calendar(
145+ dst_start_date,
146+ one_thirty,
147+ "America/New_York",
148+ db,
149+ )
150+ == Ok([
151+ timestamp.from_unix_seconds(1_762_061_400),
152+ timestamp.from_unix_seconds(1_762_065_000),
153+ ])
154+ assert tzcalendar.from_calendar(dst_start_date, two, "America/New_York", db)
155+ == Ok([timestamp.from_unix_seconds(1_762_066_800)])
156+ assert tzcalendar.from_calendar(
157+ dst_start_date,
158+ two_thirty,
159+ "America/New_York",
160+ db,
161+ )
162+ == Ok([timestamp.from_unix_seconds(1_762_068_600)])
163+ assert tzcalendar.from_calendar(dst_start_date, three, "America/New_York", db)
164+ == Ok([timestamp.from_unix_seconds(1_762_070_400)])
165+ assert tzcalendar.from_calendar(
166+ dst_start_date,
167+ three_thirty,
168+ "America/New_York",
169+ db,
170+ )
171+ == Ok([timestamp.from_unix_seconds(1_762_072_200)])
172+ }
173+
174+ pub fn au_daylight_start_test() {
175+ let db = get_database()
176+ let dst_start_date = calendar.Date(2025, calendar.October, 5)
177+
178+ let one = calendar.TimeOfDay(1, 0, 0, 0)
179+ let one_thirty = calendar.TimeOfDay(1, 30, 0, 0)
180+ let two = calendar.TimeOfDay(2, 0, 0, 0)
181+ let two_thirty = calendar.TimeOfDay(2, 30, 0, 0)
182+ let three = calendar.TimeOfDay(3, 0, 0, 0)
183+ let three_thirty = calendar.TimeOfDay(3, 30, 0, 0)
184+
185+ assert tzcalendar.from_calendar(dst_start_date, one, "Australia/Canberra", db)
186+ == Ok([timestamp.from_unix_seconds(1_759_590_000)])
187+ assert tzcalendar.from_calendar(
188+ dst_start_date,
189+ one_thirty,
190+ "Australia/Canberra",
191+ db,
192+ )
193+ == Ok([timestamp.from_unix_seconds(1_759_591_800)])
194+ assert tzcalendar.from_calendar(dst_start_date, two, "Australia/Canberra", db)
195+ == Ok([])
196+ assert tzcalendar.from_calendar(
197+ dst_start_date,
198+ two_thirty,
199+ "Australia/Canberra",
200+ db,
201+ )
202+ == Ok([])
203+ assert tzcalendar.from_calendar(
204+ dst_start_date,
205+ three,
206+ "Australia/Canberra",
207+ db,
208+ )
209+ == Ok([timestamp.from_unix_seconds(1_759_593_600)])
210+ assert tzcalendar.from_calendar(
211+ dst_start_date,
212+ three_thirty,
213+ "Australia/Canberra",
214+ db,
215+ )
216+ == Ok([timestamp.from_unix_seconds(1_759_595_400)])
217+ }
218+
219+ pub fn au_daylight_stop_test() {
220+ let db = get_database()
221+ let dst_start_date = calendar.Date(2025, calendar.April, 6)
222+
223+ let one = calendar.TimeOfDay(1, 0, 0, 0)
224+ let one_thirty = calendar.TimeOfDay(1, 30, 0, 0)
225+ let two = calendar.TimeOfDay(2, 0, 0, 0)
226+ let two_thirty = calendar.TimeOfDay(2, 30, 0, 0)
227+ let three = calendar.TimeOfDay(3, 0, 0, 0)
228+ let three_thirty = calendar.TimeOfDay(3, 30, 0, 0)
229+
230+ assert tzcalendar.from_calendar(dst_start_date, one, "Australia/Canberra", db)
231+ == Ok([timestamp.from_unix_seconds(1_743_861_600)])
232+ assert tzcalendar.from_calendar(
233+ dst_start_date,
234+ one_thirty,
235+ "Australia/Canberra",
236+ db,
237+ )
238+ == Ok([timestamp.from_unix_seconds(1_743_863_400)])
239+ assert tzcalendar.from_calendar(dst_start_date, two, "Australia/Canberra", db)
240+ == Ok([
241+ timestamp.from_unix_seconds(1_743_865_200),
242+ timestamp.from_unix_seconds(1_743_868_800),
243+ ])
244+ assert tzcalendar.from_calendar(
245+ dst_start_date,
246+ two_thirty,
247+ "Australia/Canberra",
248+ db,
249+ )
250+ == Ok([
251+ timestamp.from_unix_seconds(1_743_867_000),
252+ timestamp.from_unix_seconds(1_743_870_600),
253+ ])
254+ assert tzcalendar.from_calendar(
255+ dst_start_date,
256+ three,
257+ "Australia/Canberra",
258+ db,
259+ )
260+ == Ok([timestamp.from_unix_seconds(1_743_872_400)])
261+ assert tzcalendar.from_calendar(
262+ dst_start_date,
263+ three_thirty,
264+ "Australia/Canberra",
265+ db,
266+ )
267+ == Ok( [ timestamp. from_unix_seconds( 1_743_874_200) ] )
268+ }
0 commit comments