[common] allow general ISO 8601 values for 'date-min' & '-max'

and parse them as UTC times instead of local time
This commit is contained in:
Mike Fährmann
2025-11-09 21:33:11 +01:00
parent 3942e6ddc0
commit 89ece8f900
4 changed files with 91 additions and 8 deletions

View File

@@ -1503,12 +1503,19 @@ extractor.*.date-format
Type
``string``
Default
``"%Y-%m-%dT%H:%M:%S"``
``null``
Description
Format string used to parse ``string`` values of
`date-min` and `date-max`.
See |strptime|_ for a list of formatting directives.
Special Values
``null``
| Parse `date-min` and `date-max` according to
`ISO 8601 <https://en.wikipedia.org/wiki/ISO_8601>`__
| See
`datetime.fromisoformat() <https://docs.python.org/3/library/datetime.html#datetime.datetime.fromisoformat>`__
for details and examples.
Note
Despite its name, this option does **not** control how
``{date}`` metadata fields are formatted.

View File

@@ -681,7 +681,7 @@
"embeds" : true,
"date-min" : 0,
"date-max" : 253402210800,
"date-format" : "%Y-%m-%dT%H:%M:%S",
"date-format" : null,
"id-min" : null,
"id-max" : null,
"limit" : null,

View File

@@ -697,13 +697,16 @@ class Extractor():
def get(key, default):
ts = self.config(key, default)
if isinstance(ts, str):
try:
ts = int(dt.parse(ts, fmt).timestamp())
except ValueError as exc:
self.log.warning("Unable to parse '%s': %s", key, exc)
dt_obj = dt.parse_iso(ts) if fmt is None else dt.parse(ts, fmt)
if dt_obj is dt.NONE:
self.log.warning(
"Unable to parse '%s': Invalid %s string '%s'",
key, "isoformat" if fmt is None else "date", ts)
ts = default
else:
ts = int(dt.to_ts(dt_obj))
return ts
fmt = self.config("date-format", "%Y-%m-%dT%H:%M:%S")
fmt = self.config("date-format")
return get("date-min", dmin), get("date-max", dmax)
@classmethod

View File

@@ -16,7 +16,7 @@ import time
import string
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from gallery_dl import extractor, util, dt # noqa E402
from gallery_dl import extractor, util, dt, config # noqa E402
from gallery_dl.extractor import mastodon # noqa E402
from gallery_dl.extractor.common import Extractor, Message # noqa E402
from gallery_dl.extractor.directlink import DirectlinkExtractor # noqa E402
@@ -261,6 +261,79 @@ class TestExtractorWait(unittest.TestCase):
return int(parts[0]) * 3600 + int(parts[1]) * 60 + int(parts[2])
class TextExtractorCommonDateminmax(unittest.TestCase):
def setUp(self):
config.clear()
tearDown = setUp
def test_date_min_max_default(self):
extr = extractor.find("generic:https://example.org/")
dmin, dmax = extr._get_date_min_max()
self.assertEqual(dmin, None)
self.assertEqual(dmax, None)
dmin, dmax = extr._get_date_min_max(..., -1)
self.assertEqual(dmin, ...)
self.assertEqual(dmax, -1)
def test_date_min_max_timestamp(self):
extr = extractor.find("generic:https://example.org/")
config.set((), "date-min", 1262304000)
config.set((), "date-max", 1262304000.123)
dmin, dmax = extr._get_date_min_max()
self.assertEqual(dmin, 1262304000)
self.assertEqual(dmax, 1262304000.123)
def test_date_min_max_iso(self):
extr = extractor.find("generic:https://example.org/")
config.set((), "date-min", "2010-01-01")
config.set((), "date-max", "2010-01-01T00:01:03")
dmin, dmax = extr._get_date_min_max()
self.assertEqual(dmin, 1262304000)
self.assertEqual(dmax, 1262304063)
def test_date_min_max_iso_invalid(self):
extr = extractor.find("generic:https://example.org/")
config.set((), "date-min", "2010-01-01")
config.set((), "date-max", "2010-01")
with self.assertLogs() as log_info:
dmin, dmax = extr._get_date_min_max()
self.assertEqual(dmin, 1262304000)
self.assertEqual(dmax, None)
self.assertEqual(len(log_info.output), 1)
self.assertEqual(
log_info.output[0],
"WARNING:generic:Unable to parse 'date-max': "
"Invalid isoformat string '2010-01'")
def test_date_min_max_fmt(self):
extr = extractor.find("generic:https://example.org/")
config.set((), "date-format", "%B %d %Y")
config.set((), "date-min", "January 01 2010")
config.set((), "date-max", "August 18 2022")
dmin, dmax = extr._get_date_min_max()
self.assertEqual(dmin, 1262304000)
self.assertEqual(dmax, 1660780800)
def test_date_min_max_mix(self):
extr = extractor.find("generic:https://example.org/")
config.set((), "date-format", "%B %d %Y")
config.set((), "date-min", "January 01 2010")
config.set((), "date-max", 1262304061)
dmin, dmax = extr._get_date_min_max()
self.assertEqual(dmin, 1262304000)
self.assertEqual(dmax, 1262304061)
class TextExtractorOAuth(unittest.TestCase):
def test_oauth1(self):