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