diff --git a/docs/formatting.md b/docs/formatting.md index 9b8372d7..00fc9dfb 100644 --- a/docs/formatting.md +++ b/docs/formatting.md @@ -160,10 +160,16 @@ Format specifiers can be used for advanced formatting by using the options provi {foo:Ro/()/} F()() Bar + + D<format>/ + Parse a string value to a datetime object according to <format> + {updated:D%b %d %Y %I:%M %p/} + 2010-01-01 00:00:00 + -All special format specifiers (`?`, `L`, `J`, `R`) can be chained and combined with one another, but must always come before any standard format specifiers: +All special format specifiers (`?`, `L`, `J`, `R`, `D`) can be chained and combined with one another, but must always come before any standard format specifiers: For example `{foo:?//RF/B/Ro/e/> 10}` -> `   Bee Bar` - `?//` - Tests if `foo` has a value diff --git a/gallery_dl/formatter.py b/gallery_dl/formatter.py index f5d961ac..c2b4d99e 100644 --- a/gallery_dl/formatter.py +++ b/gallery_dl/formatter.py @@ -274,6 +274,8 @@ def build_format_func(format_spec): return _parse_join(format_spec) if fmt == "R": return _parse_replace(format_spec) + if fmt == "D": + return _parse_datetime(format_spec) return _default_format(format_spec) return format @@ -319,6 +321,16 @@ def _parse_replace(format_spec): return replace +def _parse_datetime(format_spec): + dt_format, _, format_spec = format_spec.partition("/") + dt_format = dt_format[1:] + fmt = build_format_func(format_spec) + + def dt(obj): + return fmt(text.parse_datetime(obj, dt_format)) + return dt + + def _default_format(format_spec): def wrap(obj): return format(obj, format_spec) diff --git a/test/test_formatter.py b/test/test_formatter.py index 088b45ba..8464b1b6 100644 --- a/test/test_formatter.py +++ b/test/test_formatter.py @@ -29,6 +29,7 @@ class TestFormatter(unittest.TestCase): "u": "'< / >'", "t": 1262304000, "dt": datetime.datetime(2010, 1, 1), + "ds": "2010-01-01T01:00:00+0100", "name": "Name", "title1": "Title", "title2": "", @@ -162,6 +163,11 @@ class TestFormatter(unittest.TestCase): self._run_test("{a!l:Rl//}" , "heo word") self._run_test("{name:Rame/othing/}", "Nothing") + def test_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}", "2010-01-01T01:00:00+0100") + self._run_test("{l:D%Y}", "None") + def test_chain_special(self): # multiple replacements self._run_test("{a:Rh/C/RE/e/RL/l/}", "Cello wOrld") @@ -174,6 +180,9 @@ class TestFormatter(unittest.TestCase): self._run_test("{d[a]:?/L1/too long/}", "") self._run_test("{d[c]:?/L5/too long/}", "") + # parse and format datetime + self._run_test("{ds:D%Y-%m-%dT%H:%M:%S%z/%Y%m%d}", "20100101") + def test_globals_env(self): os.environ["FORMATTER_TEST"] = value = self.kwdict["a"] @@ -259,7 +268,7 @@ def noarg(): sys.path.pop(0) self.assertEqual(fmt1.format_map(self.kwdict), "'Title' by Name") - self.assertEqual(fmt2.format_map(self.kwdict), "65") + self.assertEqual(fmt2.format_map(self.kwdict), "89") with self.assertRaises(TypeError): self.assertEqual(fmt3.format_map(self.kwdict), "")