main
1"""
2Copied from https://github.com/pydantic/pydantic/blob/v1.10.22/tests/test_datetime_parse.py
3with modifications so it works without pydantic v1 imports.
4"""
5
6from typing import Type, Union
7from datetime import date, datetime, timezone, timedelta
8
9import pytest
10
11from openai._utils import parse_date, parse_datetime
12
13
14def create_tz(minutes: int) -> timezone:
15 return timezone(timedelta(minutes=minutes))
16
17
18@pytest.mark.parametrize(
19 "value,result",
20 [
21 # Valid inputs
22 ("1494012444.883309", date(2017, 5, 5)),
23 (b"1494012444.883309", date(2017, 5, 5)),
24 (1_494_012_444.883_309, date(2017, 5, 5)),
25 ("1494012444", date(2017, 5, 5)),
26 (1_494_012_444, date(2017, 5, 5)),
27 (0, date(1970, 1, 1)),
28 ("2012-04-23", date(2012, 4, 23)),
29 (b"2012-04-23", date(2012, 4, 23)),
30 ("2012-4-9", date(2012, 4, 9)),
31 (date(2012, 4, 9), date(2012, 4, 9)),
32 (datetime(2012, 4, 9, 12, 15), date(2012, 4, 9)),
33 # Invalid inputs
34 ("x20120423", ValueError),
35 ("2012-04-56", ValueError),
36 (19_999_999_999, date(2603, 10, 11)), # just before watershed
37 (20_000_000_001, date(1970, 8, 20)), # just after watershed
38 (1_549_316_052, date(2019, 2, 4)), # nowish in s
39 (1_549_316_052_104, date(2019, 2, 4)), # nowish in ms
40 (1_549_316_052_104_324, date(2019, 2, 4)), # nowish in μs
41 (1_549_316_052_104_324_096, date(2019, 2, 4)), # nowish in ns
42 ("infinity", date(9999, 12, 31)),
43 ("inf", date(9999, 12, 31)),
44 (float("inf"), date(9999, 12, 31)),
45 ("infinity ", date(9999, 12, 31)),
46 (int("1" + "0" * 100), date(9999, 12, 31)),
47 (1e1000, date(9999, 12, 31)),
48 ("-infinity", date(1, 1, 1)),
49 ("-inf", date(1, 1, 1)),
50 ("nan", ValueError),
51 ],
52)
53def test_date_parsing(value: Union[str, bytes, int, float], result: Union[date, Type[Exception]]) -> None:
54 if type(result) == type and issubclass(result, Exception): # pyright: ignore[reportUnnecessaryIsInstance]
55 with pytest.raises(result):
56 parse_date(value)
57 else:
58 assert parse_date(value) == result
59
60
61@pytest.mark.parametrize(
62 "value,result",
63 [
64 # Valid inputs
65 # values in seconds
66 ("1494012444.883309", datetime(2017, 5, 5, 19, 27, 24, 883_309, tzinfo=timezone.utc)),
67 (1_494_012_444.883_309, datetime(2017, 5, 5, 19, 27, 24, 883_309, tzinfo=timezone.utc)),
68 ("1494012444", datetime(2017, 5, 5, 19, 27, 24, tzinfo=timezone.utc)),
69 (b"1494012444", datetime(2017, 5, 5, 19, 27, 24, tzinfo=timezone.utc)),
70 (1_494_012_444, datetime(2017, 5, 5, 19, 27, 24, tzinfo=timezone.utc)),
71 # values in ms
72 ("1494012444000.883309", datetime(2017, 5, 5, 19, 27, 24, 883, tzinfo=timezone.utc)),
73 ("-1494012444000.883309", datetime(1922, 8, 29, 4, 32, 35, 999117, tzinfo=timezone.utc)),
74 (1_494_012_444_000, datetime(2017, 5, 5, 19, 27, 24, tzinfo=timezone.utc)),
75 ("2012-04-23T09:15:00", datetime(2012, 4, 23, 9, 15)),
76 ("2012-4-9 4:8:16", datetime(2012, 4, 9, 4, 8, 16)),
77 ("2012-04-23T09:15:00Z", datetime(2012, 4, 23, 9, 15, 0, 0, timezone.utc)),
78 ("2012-4-9 4:8:16-0320", datetime(2012, 4, 9, 4, 8, 16, 0, create_tz(-200))),
79 ("2012-04-23T10:20:30.400+02:30", datetime(2012, 4, 23, 10, 20, 30, 400_000, create_tz(150))),
80 ("2012-04-23T10:20:30.400+02", datetime(2012, 4, 23, 10, 20, 30, 400_000, create_tz(120))),
81 ("2012-04-23T10:20:30.400-02", datetime(2012, 4, 23, 10, 20, 30, 400_000, create_tz(-120))),
82 (b"2012-04-23T10:20:30.400-02", datetime(2012, 4, 23, 10, 20, 30, 400_000, create_tz(-120))),
83 (datetime(2017, 5, 5), datetime(2017, 5, 5)),
84 (0, datetime(1970, 1, 1, 0, 0, 0, tzinfo=timezone.utc)),
85 # Invalid inputs
86 ("x20120423091500", ValueError),
87 ("2012-04-56T09:15:90", ValueError),
88 ("2012-04-23T11:05:00-25:00", ValueError),
89 (19_999_999_999, datetime(2603, 10, 11, 11, 33, 19, tzinfo=timezone.utc)), # just before watershed
90 (20_000_000_001, datetime(1970, 8, 20, 11, 33, 20, 1000, tzinfo=timezone.utc)), # just after watershed
91 (1_549_316_052, datetime(2019, 2, 4, 21, 34, 12, 0, tzinfo=timezone.utc)), # nowish in s
92 (1_549_316_052_104, datetime(2019, 2, 4, 21, 34, 12, 104_000, tzinfo=timezone.utc)), # nowish in ms
93 (1_549_316_052_104_324, datetime(2019, 2, 4, 21, 34, 12, 104_324, tzinfo=timezone.utc)), # nowish in μs
94 (1_549_316_052_104_324_096, datetime(2019, 2, 4, 21, 34, 12, 104_324, tzinfo=timezone.utc)), # nowish in ns
95 ("infinity", datetime(9999, 12, 31, 23, 59, 59, 999999)),
96 ("inf", datetime(9999, 12, 31, 23, 59, 59, 999999)),
97 ("inf ", datetime(9999, 12, 31, 23, 59, 59, 999999)),
98 (1e50, datetime(9999, 12, 31, 23, 59, 59, 999999)),
99 (float("inf"), datetime(9999, 12, 31, 23, 59, 59, 999999)),
100 ("-infinity", datetime(1, 1, 1, 0, 0)),
101 ("-inf", datetime(1, 1, 1, 0, 0)),
102 ("nan", ValueError),
103 ],
104)
105def test_datetime_parsing(value: Union[str, bytes, int, float], result: Union[datetime, Type[Exception]]) -> None:
106 if type(result) == type and issubclass(result, Exception): # pyright: ignore[reportUnnecessaryIsInstance]
107 with pytest.raises(result):
108 parse_datetime(value)
109 else:
110 assert parse_datetime(value) == result