1
0
mirror of https://github.com/mikf/gallery-dl.git synced 2024-11-22 18:53:21 +01:00

[formatter] implement 'D' format specifier

To be able to parse any string into a 'datetime' object
and format it as necessary.

Example:

{created_at:D%Y-%m-%dT%H:%M:%S%z}
->
"2010-01-01 00:00:00"

{created_at:D%Y-%m-%dT%H:%M:%S%z/%b %d %Y %I:%M %p}
->
"Jan 01 2010 12:00 AM"

with 'created_at' == "2010-01-01T01:00:00+0100"
This commit is contained in:
Mike Fährmann 2021-11-20 23:04:34 +01:00
parent 3a7a19c7b9
commit 3842cdcd8f
No known key found for this signature in database
GPG Key ID: 5680CA389D365A88
3 changed files with 29 additions and 2 deletions

View File

@ -160,10 +160,16 @@ Format specifiers can be used for advanced formatting by using the options provi
<td><code>{foo:Ro/()/}</code></td> <td><code>{foo:Ro/()/}</code></td>
<td><code>F()()&nbsp;Bar</code></td> <td><code>F()()&nbsp;Bar</code></td>
</tr> </tr>
<tr>
<td><code>D&lt;format&gt;/</code></td>
<td>Parse a string value to a <code>datetime</code> object according to <a href="https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes"><code>&lt;format&gt;</code></a></td>
<td><code>{updated:D%b %d %Y %I:%M %p/}</code></td>
<td><code>2010-01-01 00:00:00</code></td>
</tr>
</tbody> </tbody>
</table> </table>
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` For example `{foo:?//RF/B/Ro/e/> 10}` -> `   Bee Bar`
- `?//` - Tests if `foo` has a value - `?//` - Tests if `foo` has a value

View File

@ -274,6 +274,8 @@ def build_format_func(format_spec):
return _parse_join(format_spec) return _parse_join(format_spec)
if fmt == "R": if fmt == "R":
return _parse_replace(format_spec) return _parse_replace(format_spec)
if fmt == "D":
return _parse_datetime(format_spec)
return _default_format(format_spec) return _default_format(format_spec)
return format return format
@ -319,6 +321,16 @@ def _parse_replace(format_spec):
return replace 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 _default_format(format_spec):
def wrap(obj): def wrap(obj):
return format(obj, format_spec) return format(obj, format_spec)

View File

@ -29,6 +29,7 @@ class TestFormatter(unittest.TestCase):
"u": "&#x27;&lt; / &gt;&#x27;", "u": "&#x27;&lt; / &gt;&#x27;",
"t": 1262304000, "t": 1262304000,
"dt": datetime.datetime(2010, 1, 1), "dt": datetime.datetime(2010, 1, 1),
"ds": "2010-01-01T01:00:00+0100",
"name": "Name", "name": "Name",
"title1": "Title", "title1": "Title",
"title2": "", "title2": "",
@ -162,6 +163,11 @@ class TestFormatter(unittest.TestCase):
self._run_test("{a!l:Rl//}" , "heo word") self._run_test("{a!l:Rl//}" , "heo word")
self._run_test("{name:Rame/othing/}", "Nothing") 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): def test_chain_special(self):
# multiple replacements # multiple replacements
self._run_test("{a:Rh/C/RE/e/RL/l/}", "Cello wOrld") 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/}", "<too long>") self._run_test("{d[a]:?</>/L1/too long/}", "<too long>")
self._run_test("{d[c]:?</>/L5/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): def test_globals_env(self):
os.environ["FORMATTER_TEST"] = value = self.kwdict["a"] os.environ["FORMATTER_TEST"] = value = self.kwdict["a"]
@ -259,7 +268,7 @@ def noarg():
sys.path.pop(0) sys.path.pop(0)
self.assertEqual(fmt1.format_map(self.kwdict), "'Title' by Name") 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): with self.assertRaises(TypeError):
self.assertEqual(fmt3.format_map(self.kwdict), "") self.assertEqual(fmt3.format_map(self.kwdict), "")