From bce4f54b3ed2ad76d697dddc2363650e3bd8206a Mon Sep 17 00:00:00 2001 From: Chris Brown <30196510+systemcatch@users.noreply.github.com> Date: Thu, 29 Apr 2021 16:54:39 +0100 Subject: [PATCH 1/5] Fix bug in factory.get(datetime, tzinfo=...) --- arrow/factory.py | 2 +- tests/test_factory.py | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/arrow/factory.py b/arrow/factory.py index 27dea5c57..23467fa3d 100644 --- a/arrow/factory.py +++ b/arrow/factory.py @@ -236,7 +236,7 @@ def get(self, *args: Any, **kwargs: Any) -> Arrow: # (datetime) -> from datetime. elif isinstance(arg, datetime): - return self.type.fromdatetime(arg) + return self.type.fromdatetime(arg, tzinfo=tz) # (date) -> from date. elif isinstance(arg, date): diff --git a/tests/test_factory.py b/tests/test_factory.py index 5e0020d65..fb9d37360 100644 --- a/tests/test_factory.py +++ b/tests/test_factory.py @@ -172,6 +172,17 @@ def test_kwarg_normalize_whitespace(self): 2013, 5, 5, 12, 30, 45, 123456, tzinfo=tz.tzutc() ) + # regression test for #944 + def test_one_arg_datetime_tzinfo_kwarg(self): + + dt = datetime(2021, 4, 29, 6) + + result = self.factory.get(dt, tzinfo="America/Chicago") + + expected = datetime(2021, 4, 29, 6, tzinfo=tz.gettz("America/Chicago")) + + assert_datetime_equality(result._datetime, expected) + def test_one_arg_iso_str(self): dt = datetime.utcnow() From efcb355d22de7f4528bb846947501e470375f670 Mon Sep 17 00:00:00 2001 From: Chris Brown <30196510+systemcatch@users.noreply.github.com> Date: Thu, 29 Apr 2021 21:24:11 +0100 Subject: [PATCH 2/5] Fix bug in factory.get(Arrow, tzinfo=...) --- arrow/factory.py | 2 +- tests/test_factory.py | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/arrow/factory.py b/arrow/factory.py index 23467fa3d..5a4fa1b7e 100644 --- a/arrow/factory.py +++ b/arrow/factory.py @@ -232,7 +232,7 @@ def get(self, *args: Any, **kwargs: Any) -> Arrow: # (Arrow) -> from the object's datetime. elif isinstance(arg, Arrow): - return self.type.fromdatetime(arg.datetime) + return self.type.fromdatetime(arg.datetime, tzinfo=tz) # (datetime) -> from datetime. elif isinstance(arg, datetime): diff --git a/tests/test_factory.py b/tests/test_factory.py index fb9d37360..643d13f0a 100644 --- a/tests/test_factory.py +++ b/tests/test_factory.py @@ -4,6 +4,7 @@ import pytest from dateutil import tz +from arrow import Arrow from arrow.parser import ParserError from .utils import assert_datetime_equality @@ -183,6 +184,16 @@ def test_one_arg_datetime_tzinfo_kwarg(self): assert_datetime_equality(result._datetime, expected) + def test_one_arg_arrow_tzinfo_kwarg(self): + + arw = Arrow(2021, 4, 29, 6) + + result = self.factory.get(arw, tzinfo="America/Chicago") + + expected = datetime(2021, 4, 29, 6, tzinfo=tz.gettz("America/Chicago")) + + assert_datetime_equality(result._datetime, expected) + def test_one_arg_iso_str(self): dt = datetime.utcnow() From 3acad9df4d4581c553e1232716c86a1759a2df4d Mon Sep 17 00:00:00 2001 From: Chris Brown <30196510+systemcatch@users.noreply.github.com> Date: Sat, 1 May 2021 00:42:13 +0100 Subject: [PATCH 3/5] Change behaviour of factory.get() with date objects --- arrow/factory.py | 2 +- tests/test_factory.py | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/arrow/factory.py b/arrow/factory.py index 5a4fa1b7e..0747bb80a 100644 --- a/arrow/factory.py +++ b/arrow/factory.py @@ -240,7 +240,7 @@ def get(self, *args: Any, **kwargs: Any) -> Arrow: # (date) -> from date. elif isinstance(arg, date): - return self.type.fromdate(arg) + return self.type.fromdate(arg, tzinfo=tz) # (tzinfo) -> now, @ tzinfo. elif isinstance(arg, dt_tzinfo): diff --git a/tests/test_factory.py b/tests/test_factory.py index 643d13f0a..f8b43d1b1 100644 --- a/tests/test_factory.py +++ b/tests/test_factory.py @@ -194,6 +194,17 @@ def test_one_arg_arrow_tzinfo_kwarg(self): assert_datetime_equality(result._datetime, expected) + def test_one_arg_date_tzinfo_kwarg(self): + + da = date(2021, 4, 29) + + result = self.factory.get(da, tzinfo="America/Chicago") + + expected = Arrow(2021, 4, 29, tzinfo=tz.gettz("America/Chicago")) + + assert result.date() == expected.date() + assert result.tzinfo == expected.tzinfo + def test_one_arg_iso_str(self): dt = datetime.utcnow() From 374fb97b529bd2b237d19a408eece66323052578 Mon Sep 17 00:00:00 2001 From: Chris Brown <30196510+systemcatch@users.noreply.github.com> Date: Sat, 1 May 2021 17:45:21 +0100 Subject: [PATCH 4/5] Fix bug in factory.get(iso_calendar, tzinfo=...) --- arrow/factory.py | 2 +- tests/test_factory.py | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/arrow/factory.py b/arrow/factory.py index 0747bb80a..53b46bab6 100644 --- a/arrow/factory.py +++ b/arrow/factory.py @@ -258,7 +258,7 @@ def get(self, *args: Any, **kwargs: Any) -> Arrow: # (iso calendar) -> convert then from date elif isinstance(arg, tuple) and len(arg) == 3: d = iso_to_gregorian(*arg) - return self.type.fromdate(d) + return self.type.fromdate(d, tzinfo=tz) else: raise TypeError(f"Cannot parse single argument of type {type(arg)!r}.") diff --git a/tests/test_factory.py b/tests/test_factory.py index f8b43d1b1..4bb81e872 100644 --- a/tests/test_factory.py +++ b/tests/test_factory.py @@ -205,6 +205,14 @@ def test_one_arg_date_tzinfo_kwarg(self): assert result.date() == expected.date() assert result.tzinfo == expected.tzinfo + def test_one_arg_iso_calendar_tzinfo_kwarg(self): + + result = self.factory.get((2004, 1, 7), tzinfo="America/Chicago") + + expected = Arrow(2004, 1, 4, tzinfo="America/Chicago") + + assert_datetime_equality(result, expected) + def test_one_arg_iso_str(self): dt = datetime.utcnow() From 4d65c00eb3f0b5f9a5ef29b5495980d6514c6154 Mon Sep 17 00:00:00 2001 From: Jad Chaar Date: Sat, 1 May 2021 17:05:53 -0400 Subject: [PATCH 5/5] Make tzinfo kwarg clear in get() factory conditions --- arrow/factory.py | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/arrow/factory.py b/arrow/factory.py index 53b46bab6..5787dcf02 100644 --- a/arrow/factory.py +++ b/arrow/factory.py @@ -205,14 +205,14 @@ def get(self, *args: Any, **kwargs: Any) -> Arrow: if len(kwargs) == 1 and tz is None: arg_count = 3 - # () -> now, @ utc. + # () -> now, @ tzinfo or utc if arg_count == 0: if isinstance(tz, str): tz = parser.TzinfoParser.parse(tz) - return self.type.now(tz) + return self.type.now(tzinfo=tz) if isinstance(tz, dt_tzinfo): - return self.type.now(tz) + return self.type.now(tzinfo=tz) return self.type.utcnow() @@ -223,39 +223,39 @@ def get(self, *args: Any, **kwargs: Any) -> Arrow: if arg is None: raise TypeError("Cannot parse argument of type None.") - # try (int, float) -> from timestamp with tz + # try (int, float) -> from timestamp @ tzinfo elif not isinstance(arg, str) and is_timestamp(arg): if tz is None: # set to UTC by default tz = dateutil_tz.tzutc() return self.type.fromtimestamp(arg, tzinfo=tz) - # (Arrow) -> from the object's datetime. + # (Arrow) -> from the object's datetime @ tzinfo elif isinstance(arg, Arrow): return self.type.fromdatetime(arg.datetime, tzinfo=tz) - # (datetime) -> from datetime. + # (datetime) -> from datetime @ tzinfo elif isinstance(arg, datetime): return self.type.fromdatetime(arg, tzinfo=tz) - # (date) -> from date. + # (date) -> from date @ tzinfo elif isinstance(arg, date): return self.type.fromdate(arg, tzinfo=tz) - # (tzinfo) -> now, @ tzinfo. + # (tzinfo) -> now @ tzinfo elif isinstance(arg, dt_tzinfo): - return self.type.now(arg) + return self.type.now(tzinfo=arg) - # (str) -> parse. + # (str) -> parse @ tzinfo elif isinstance(arg, str): dt = parser.DateTimeParser(locale).parse_iso(arg, normalize_whitespace) - return self.type.fromdatetime(dt, tz) + return self.type.fromdatetime(dt, tzinfo=tz) # (struct_time) -> from struct_time elif isinstance(arg, struct_time): return self.type.utcfromtimestamp(calendar.timegm(arg)) - # (iso calendar) -> convert then from date + # (iso calendar) -> convert then from date @ tzinfo elif isinstance(arg, tuple) and len(arg) == 3: d = iso_to_gregorian(*arg) return self.type.fromdate(d, tzinfo=tz) @@ -269,9 +269,9 @@ def get(self, *args: Any, **kwargs: Any) -> Arrow: if isinstance(arg_1, datetime): - # (datetime, tzinfo/str) -> fromdatetime replace tzinfo. + # (datetime, tzinfo/str) -> fromdatetime @ tzinfo if isinstance(arg_2, (dt_tzinfo, str)): - return self.type.fromdatetime(arg_1, arg_2) + return self.type.fromdatetime(arg_1, tzinfo=arg_2) else: raise TypeError( f"Cannot parse two arguments of types 'datetime', {type(arg_2)!r}." @@ -279,7 +279,7 @@ def get(self, *args: Any, **kwargs: Any) -> Arrow: elif isinstance(arg_1, date): - # (date, tzinfo/str) -> fromdate replace tzinfo. + # (date, tzinfo/str) -> fromdate @ tzinfo if isinstance(arg_2, (dt_tzinfo, str)): return self.type.fromdate(arg_1, tzinfo=arg_2) else: @@ -287,7 +287,7 @@ def get(self, *args: Any, **kwargs: Any) -> Arrow: f"Cannot parse two arguments of types 'date', {type(arg_2)!r}." ) - # (str, format) -> parse. + # (str, format) -> parse @ tzinfo elif isinstance(arg_1, str) and isinstance(arg_2, (str, list)): dt = parser.DateTimeParser(locale).parse( args[0], args[1], normalize_whitespace @@ -299,7 +299,7 @@ def get(self, *args: Any, **kwargs: Any) -> Arrow: f"Cannot parse two arguments of types {type(arg_1)!r} and {type(arg_2)!r}." ) - # 3+ args -> datetime-like via constructor. + # 3+ args -> datetime-like via constructor else: return self.type(*args, **kwargs)