From 54d14349e26643704526e25ebe045ff02ef633d7 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 14 Jun 2020 22:18:46 +0530 Subject: [PATCH] calibredb set_metadata: When converting a string into a datetime if the string is a full ISO 8601 date with timezone do not adjust the date to make it timezone neutral. Fixes #1883433 [Can't Set timestamp field to first or last of month via CLI](https://bugs.launchpad.net/calibre/+bug/1883433) --- src/calibre/ebooks/metadata/book/base.py | 8 ++++++-- src/calibre/utils/iso8601.py | 4 +++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/calibre/ebooks/metadata/book/base.py b/src/calibre/ebooks/metadata/book/base.py index 4eafdab282..b8f85dc05b 100644 --- a/src/calibre/ebooks/metadata/book/base.py +++ b/src/calibre/ebooks/metadata/book/base.py @@ -822,8 +822,12 @@ def field_from_string(field, raw, field_metadata): elif dt == 'rating': val = float(raw) * 2 elif dt == 'datetime': - from calibre.utils.date import parse_only_date - val = parse_only_date(raw) + from calibre.utils.iso8601 import parse_iso8601 + try: + val = parse_iso8601(raw, require_aware=True) + except Exception: + from calibre.utils.date import parse_only_date + val = parse_only_date(raw) elif dt == 'bool': if raw.lower() in {'true', 'yes', 'y'}: val = True diff --git a/src/calibre/utils/iso8601.py b/src/calibre/utils/iso8601.py index eb4ffeca95..fc8ef91c93 100644 --- a/src/calibre/utils/iso8601.py +++ b/src/calibre/utils/iso8601.py @@ -42,7 +42,7 @@ del tzutc, tzlocal UNDEFINED_DATE = datetime(101,1,1, tzinfo=utc_tz) -def parse_iso8601(date_string, assume_utc=False, as_utc=True): +def parse_iso8601(date_string, assume_utc=False, as_utc=True, require_aware=False): if not date_string: return UNDEFINED_DATE dt, aware, tzseconds = speedup.parse_iso8601(date_string) @@ -54,6 +54,8 @@ def parse_iso8601(date_string, assume_utc=False, as_utc=True): sign = '-' if tzseconds < 0 else '+' description = "%s%02d:%02d" % (sign, abs(tzseconds) // 3600, (abs(tzseconds) % 3600) // 60) tz = tzoffset(description, tzseconds) + elif require_aware: + raise ValueError('{} does not specify a time zone'.format(date_string)) dt = dt.replace(tzinfo=tz) if as_utc and tz is utc_tz: return dt