From 9e62f283ffd07ddb19de8b9f03db377aad369cc1 Mon Sep 17 00:00:00 2001 From: colethedj Date: Tue, 6 Apr 2021 18:45:15 +1200 Subject: [PATCH] [utils] Add `datetime_from_str` to parse relative time (#221) and `datetime_add_months` to accurately add/subtract months Authored by: colethedj --- test/test_utils.py | 15 ++++++-- yt_dlp/utils.py | 86 ++++++++++++++++++++++++++++++++++++---------- 2 files changed, 81 insertions(+), 20 deletions(-) diff --git a/test/test_utils.py b/test/test_utils.py index 795d2b46a..d0571c6f2 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -23,6 +23,7 @@ from yt_dlp.utils import ( clean_html, clean_podcast_url, date_from_str, + datetime_from_str, DateRange, detect_exe_version, determine_ext, @@ -311,8 +312,18 @@ class TestUtil(unittest.TestCase): self.assertEqual(date_from_str('yesterday'), date_from_str('now-1day')) self.assertEqual(date_from_str('now+7day'), date_from_str('now+1week')) self.assertEqual(date_from_str('now+14day'), date_from_str('now+2week')) - self.assertEqual(date_from_str('now+365day'), date_from_str('now+1year')) - self.assertEqual(date_from_str('now+30day'), date_from_str('now+1month')) + self.assertEqual(date_from_str('20200229+365day'), date_from_str('20200229+1year')) + self.assertEqual(date_from_str('20210131+28day'), date_from_str('20210131+1month')) + + def test_datetime_from_str(self): + self.assertEqual(datetime_from_str('yesterday', precision='day'), datetime_from_str('now-1day', precision='auto')) + self.assertEqual(datetime_from_str('now+7day', precision='day'), datetime_from_str('now+1week', precision='auto')) + self.assertEqual(datetime_from_str('now+14day', precision='day'), datetime_from_str('now+2week', precision='auto')) + self.assertEqual(datetime_from_str('20200229+365day', precision='day'), datetime_from_str('20200229+1year', precision='auto')) + self.assertEqual(datetime_from_str('20210131+28day', precision='day'), datetime_from_str('20210131+1month', precision='auto')) + self.assertEqual(datetime_from_str('20210131+59day', precision='day'), datetime_from_str('20210131+2month', precision='auto')) + self.assertEqual(datetime_from_str('now+1day', precision='hour'), datetime_from_str('now+24hours', precision='auto')) + self.assertEqual(datetime_from_str('now+23hours', precision='hour'), datetime_from_str('now+23hours', precision='auto')) def test_daterange(self): _20century = DateRange("19000101", "20000101") diff --git a/yt_dlp/utils.py b/yt_dlp/utils.py index c14fdb509..3ba2a1ec8 100644 --- a/yt_dlp/utils.py +++ b/yt_dlp/utils.py @@ -3052,33 +3052,83 @@ def subtitles_filename(filename, sub_lang, sub_format, expected_real_ext=None): return replace_extension(filename, sub_lang + '.' + sub_format, expected_real_ext) -def date_from_str(date_str): +def datetime_from_str(date_str, precision='auto', format='%Y%m%d'): """ Return a datetime object from a string in the format YYYYMMDD or - (now|today)[+-][0-9](day|week|month|year)(s)?""" - today = datetime.date.today() + (now|today|date)[+-][0-9](microsecond|second|minute|hour|day|week|month|year)(s)? + + format: string date format used to return datetime object from + precision: round the time portion of a datetime object. + auto|microsecond|second|minute|hour|day. + auto: round to the unit provided in date_str (if applicable). + """ + auto_precision = False + if precision == 'auto': + auto_precision = True + precision = 'microsecond' + today = datetime_round(datetime.datetime.now(), precision) if date_str in ('now', 'today'): return today if date_str == 'yesterday': return today - datetime.timedelta(days=1) - match = re.match(r'(now|today)(?P[+-])(?P