diff --git a/gallery_dl/dt.py b/gallery_dl/dt.py index 0008cf57..9f1cd09e 100644 --- a/gallery_dl/dt.py +++ b/gallery_dl/dt.py @@ -12,6 +12,14 @@ import sys import time from datetime import datetime, date, timedelta, timezone # noqa F401 + +class NullDatetime(datetime): + + def __bool__(self): + return False + + +NONE = NullDatetime(101, 1, 1) EPOCH = datetime(1970, 1, 1) SECOND = timedelta(0, 1) @@ -29,7 +37,7 @@ def normalize(dt): def convert(value): """Convert 'value' to a naive UTC datetime object""" if not value: - return EPOCH + return NONE if isinstance(value, datetime): return value @@ -51,7 +59,7 @@ def parse(dt_string, format): try: return normalize(datetime.strptime(dt_string, format)) except Exception: - return EPOCH + return NONE if sys.hexversion < 0x30c0000: @@ -64,7 +72,7 @@ if sys.hexversion < 0x30c0000: dt_string = dt_string[:-1] return normalize(datetime.fromisoformat(dt_string)) except Exception: - return EPOCH + return NONE def parse_compat(dt_string, format): """Parse 'dt_string' as ISO 8601 value using 'format'""" @@ -80,7 +88,7 @@ else: try: return normalize(datetime.fromisoformat(dt_string)) except Exception: - return EPOCH + return NONE def parse_compat(dt_string, format): """Parse 'dt_string' as ISO 8601 value""" @@ -94,7 +102,7 @@ else: now = from_ts -def parse_ts(ts, default=EPOCH): +def parse_ts(ts, default=NONE): """Create a datetime object from a Unix timestamp""" try: return from_ts(int(ts)) diff --git a/test/test_dt.py b/test/test_dt.py index b9cc4d2c..6eea4df4 100644 --- a/test/test_dt.py +++ b/test/test_dt.py @@ -44,14 +44,14 @@ class TestDatetime(unittest.TestCase): _assert("2010-01-01T00:00:00Z" , d) _assert("2010-01-01T00:00:00.123456Z" , d) - _assert(0 , dt.EPOCH) - _assert("" , dt.EPOCH) - _assert("foo", dt.EPOCH) - _assert(None , dt.EPOCH) - _assert(() , dt.EPOCH) - _assert([] , dt.EPOCH) - _assert({} , dt.EPOCH) - _assert((1, 2, 3), dt.EPOCH) + _assert(0 , dt.NONE) + _assert("" , dt.NONE) + _assert("foo", dt.NONE) + _assert(None , dt.NONE) + _assert(() , dt.NONE) + _assert([] , dt.NONE) + _assert({} , dt.NONE) + _assert((1, 2, 3), dt.NONE) @unittest.skipIf(sys.hexversion < 0x30b0000, "extended fromisoformat timezones") @@ -101,7 +101,7 @@ class TestDatetime(unittest.TestCase): self.assertEqual(f("1555816235"), value) for value in ((), [], {}, None, ""): - self.assertEqual(f(value), dt.EPOCH) + self.assertEqual(f(value), dt.NONE) self.assertEqual(f(value, "foo"), "foo") def test_parse(self, f=dt.parse): @@ -119,7 +119,7 @@ class TestDatetime(unittest.TestCase): ) for value in ((), [], {}, None, 1, 2.3): - self.assertEqual(f(value, "%Y"), dt.EPOCH) + self.assertEqual(f(value, "%Y"), dt.NONE) def test_parse_iso(self, f=dt.parse_iso): null = dt.from_ts(0) @@ -140,12 +140,16 @@ class TestDatetime(unittest.TestCase): datetime.datetime(2019, 5, 7, 21, 25, 2), ) self.assertEqual( - f("1970.01.01"), + f("1970-01-01"), dt.EPOCH, ) + self.assertEqual( + f("1970.01.01"), + dt.NONE, + ) for value in ((), [], {}, None, 1, 2.3): - self.assertEqual(f(value), dt.EPOCH) + self.assertEqual(f(value), dt.NONE) def test_parse_compat(self, f=dt.parse_compat): self.assertEqual( @@ -153,6 +157,11 @@ class TestDatetime(unittest.TestCase): datetime.datetime(2019, 5, 7, 12, 25, 2), ) + def test_none(self): + self.assertFalse(dt.NONE) + self.assertIsInstance(dt.NONE, dt.datetime) + self.assertEqual(str(dt.NONE), "0101-01-01 00:00:00") + if __name__ == "__main__": unittest.main() diff --git a/test/test_formatter.py b/test/test_formatter.py index 7a286190..e4444346 100644 --- a/test/test_formatter.py +++ b/test/test_formatter.py @@ -271,8 +271,8 @@ class TestFormatter(unittest.TestCase): def test_specifier_datetime(self): self._run_test("{ds:D%Y-%m-%dT%H:%M:%S%z}", "2010-01-01 00:00:00") - self._run_test("{ds:D%Y}", "1970-01-01 00:00:00") - self._run_test("{l:D%Y}", "1970-01-01 00:00:00") + self._run_test("{ds:D%Y}", "0101-01-01 00:00:00") + self._run_test("{l2:D%Y}", "0101-01-01 00:00:00") def test_specifier_offset(self): self._run_test("{dt:O 01:00}", "2010-01-01 01:00:00")