diff --git a/dateparser/date_parser.py b/dateparser/date_parser.py index 7c1b817df..82bc22860 100644 --- a/dateparser/date_parser.py +++ b/dateparser/date_parser.py @@ -19,7 +19,7 @@ def parse(self, date_string, parse_method, settings=None): date_string = strip_braces(date_string) date_string, ptz = pop_tz_offset_from_string(date_string) - date_obj, period = parse_method(date_string, settings=settings) + date_obj, period = parse_method(date_string, settings=settings, tz=ptz) _settings_tz = settings.TIMEZONE.lower() diff --git a/dateparser/parser.py b/dateparser/parser.py index 30536cab7..5c0aeba23 100644 --- a/dateparser/parser.py +++ b/dateparser/parser.py @@ -63,11 +63,11 @@ def resolve_date_order(order, lst=None): return chart_list[order] if lst else date_order_chart[order] -def _parse_absolute(datestring, settings): - return _parser.parse(datestring, settings) +def _parse_absolute(datestring, settings, tz=None): + return _parser.parse(datestring, settings, tz) -def _parse_nospaces(datestring, settings): +def _parse_nospaces(datestring, settings, tz=None): return _no_spaces_parser.parse(datestring, settings) @@ -417,7 +417,7 @@ def _results(self): return self._get_datetime_obj(**params) - def _correct_for_time_frame(self, dateobj): + def _correct_for_time_frame(self, dateobj, tz): days = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'] token_weekday, _ = getattr(self, '_token_weekday', (None, None)) @@ -490,11 +490,16 @@ def _correct_for_time_frame(self, dateobj): self._token_month, self._token_day, hasattr(self, '_token_weekday')]): + # Convert dateobj to utc time to compare with self.now + if tz: + dateobj_time = (dateobj - tz.utcoffset(dateobj)).time() + else: + dateobj_time = dateobj.time() if 'past' in self.settings.PREFER_DATES_FROM: - if self.now.time() < dateobj.time(): + if self.now.time() < dateobj_time: dateobj = dateobj + timedelta(days=-1) if 'future' in self.settings.PREFER_DATES_FROM: - if self.now.time() > dateobj.time(): + if self.now.time() > dateobj_time: dateobj = dateobj + timedelta(days=1) # Reset dateobj to the original value, thus removing any offset awareness that may @@ -517,13 +522,13 @@ def _correct_for_day(self, dateobj): return dateobj @classmethod - def parse(cls, datestring, settings): + def parse(cls, datestring, settings, tz=None): tokens = tokenizer(datestring) po = cls(tokens.tokenize(), settings) dateobj = po._results() # correction for past, future if applicable - dateobj = po._correct_for_time_frame(dateobj) + dateobj = po._correct_for_time_frame(dateobj, tz) # correction for preference of day: beginning, current, end dateobj = po._correct_for_day(dateobj) diff --git a/tests/test_date_parser.py b/tests/test_date_parser.py index d33deeb8d..e43fb343e 100644 --- a/tests/test_date_parser.py +++ b/tests/test_date_parser.py @@ -863,6 +863,32 @@ def test_parsing_strings_containing_only_separator_tokens(self, date_string, exp self.then_period_is('day') self.then_date_obj_exactly_is(expected) + @parameterized.expand([ + param('4pm EDT', datetime(2021, 10, 19, 20, 0)), + ]) + def test_date_skip_ahead(self, date_string, expected): + self.given_parser(settings={'PREFER_DATES_FROM': 'future', + 'TO_TIMEZONE': 'etc/utc', + 'RETURN_AS_TIMEZONE_AWARE': False, + 'RELATIVE_BASE': datetime(2021, 10, 19, 18, 0), + }) + self.when_date_is_parsed(date_string) + self.then_date_was_parsed_by_date_parser() + self.then_date_obj_exactly_is(expected) + + @parameterized.expand([ + param('11pm AEDT', datetime(2021, 10, 19, 12, 0)), + ]) + def test_date_step_back(self, date_string, expected): + self.given_parser(settings={'PREFER_DATES_FROM': 'past', + 'TO_TIMEZONE': 'etc/utc', + 'RETURN_AS_TIMEZONE_AWARE': False, + 'RELATIVE_BASE': datetime(2021, 10, 19, 18, 0), + }) + self.when_date_is_parsed(date_string) + self.then_date_was_parsed_by_date_parser() + self.then_date_obj_exactly_is(expected) + def given_local_tz_offset(self, offset): self.add_patch( patch.object(dateparser.timezone_parser,