@@ -136,3 +136,111 @@ def test_timezones(date, hour, minute, offset):
136136)
137137def test_invalid_dates (date ):
138138 assert listparser .dates .parse_rfc822 (date ) is None
139+
140+
141+ @pytest .mark .parametrize (
142+ "date, expected" ,
143+ (
144+ pytest .param (
145+ "2025-04-07T19:52:30Z" ,
146+ datetime .datetime (2025 , 4 , 7 , 19 , 52 , 30 , tzinfo = datetime .timezone .utc ),
147+ id = "simple" ,
148+ ),
149+ pytest .param (
150+ "2025-04-07T19:52:30.941Z" ,
151+ datetime .datetime (
152+ 2025 , 4 , 7 , 19 , 52 , 30 , 941000 , tzinfo = datetime .timezone .utc
153+ ),
154+ id = "milliseconds" ,
155+ ),
156+ pytest .param (
157+ "2025-04-07T19:52:30.941378073Z" ,
158+ datetime .datetime (
159+ 2025 , 4 , 7 , 19 , 52 , 30 , 941378 , tzinfo = datetime .timezone .utc
160+ ),
161+ id = "truncated milliseconds" ,
162+ ),
163+ pytest .param (
164+ "2025-04-07T19:52:30+02:00" ,
165+ datetime .datetime (
166+ 2025 ,
167+ 4 ,
168+ 7 ,
169+ 19 ,
170+ 52 ,
171+ 30 ,
172+ tzinfo = datetime .timezone (datetime .timedelta (hours = 2 )),
173+ ),
174+ id = "timezone offset with colon" ,
175+ ),
176+ pytest .param (
177+ "2025-04-07T19:52:30-0700" ,
178+ datetime .datetime (
179+ 2025 ,
180+ 4 ,
181+ 7 ,
182+ 19 ,
183+ 52 ,
184+ 30 ,
185+ tzinfo = datetime .timezone (datetime .timedelta (hours = - 7 )),
186+ ),
187+ id = "timezone offset without colon" ,
188+ ),
189+ pytest .param (
190+ "2025-01-01T00:00:00" ,
191+ datetime .datetime (2025 , 1 , 1 , 0 , 0 , 0 ),
192+ id = "no timezone" ,
193+ ),
194+ pytest .param (
195+ "2025-04-07 19:52:30Z" ,
196+ datetime .datetime (2025 , 4 , 7 , 19 , 52 , 30 , tzinfo = datetime .timezone .utc ),
197+ id = "space instead of 'T'" ,
198+ ),
199+ pytest .param (
200+ "0001-01-01T00:00:00+23:59" ,
201+ datetime .datetime (
202+ 1 ,
203+ 1 ,
204+ 1 ,
205+ 0 ,
206+ 0 ,
207+ 0 ,
208+ tzinfo = datetime .timezone (datetime .timedelta (hours = 23 , minutes = 59 )),
209+ ),
210+ id = "earliest possible date" ,
211+ ),
212+ pytest .param (
213+ "9999-12-31T23:59:59-23:59" ,
214+ datetime .datetime (
215+ 9999 ,
216+ 12 ,
217+ 31 ,
218+ 23 ,
219+ 59 ,
220+ 59 ,
221+ tzinfo = datetime .timezone (- datetime .timedelta (hours = 23 , minutes = 59 )),
222+ ),
223+ id = "latest possible date" ,
224+ ),
225+ ),
226+ )
227+ def test_rfc3339_dates (date : str , expected : datetime .datetime ):
228+ assert listparser .dates .parse_rfc3339 (date ) == expected
229+
230+
231+ @pytest .mark .parametrize (
232+ "date" ,
233+ (
234+ pytest .param ("0000-01-01T01:01:01Z" , id = "invalid year" ),
235+ pytest .param ("2025-99-01T01:01:01Z" , id = "invalid month" ),
236+ pytest .param ("2025-01-99T01:01:01Z" , id = "invalid day" ),
237+ pytest .param ("2025-01-01T99:01:01Z" , id = "invalid hour" ),
238+ pytest .param ("2025-01-01T01:99:01Z" , id = "invalid minute" ),
239+ pytest .param ("2025-01-01T01:01:99Z" , id = "invalid seconds" ),
240+ pytest .param ("2025-01-01T01:01:01+99:00" , id = "invalid timezone offset hours" ),
241+ pytest .param ("2025-01-01TT01:01:01Z" , id = "invalid separator" ),
242+ pytest .param ("tomorrow-ish" , id = "invalid format" ),
243+ ),
244+ )
245+ def test_rfc3339_invalid_dates (date : str ):
246+ assert listparser .dates .parse_rfc3339 (date ) is None
0 commit comments