#802 Implement PEP 495 to handle ambiguous datetimes

Merged Chris systemcatch

No flags found

Use flags to group coverage reports by test type, project and/or folders.
Then setup custom commit statuses and notifications for each flag.

e.g., #unittest #integration

#production #enterprise

#frontend #backend

Learn more about Codecov Flags here.

Showing 1 of 4 files from the diff.
Other files ignored by Codecov
setup.py has changed.
docs/index.rst has changed.

@@ -41,8 +41,9 @@
Loading
41 41
    :param hour: (optional) the hour. Defaults to 0.
42 42
    :param minute: (optional) the minute, Defaults to 0.
43 43
    :param second: (optional) the second, Defaults to 0.
44 -
    :param microsecond: (optional) the microsecond. Defaults 0.
44 +
    :param microsecond: (optional) the microsecond. Defaults to 0.
45 45
    :param tzinfo: (optional) A timezone expression.  Defaults to UTC.
46 +
    :param fold: (optional) 0 or 1, used to disambiguate repeated times. Defaults to 0.
46 47
47 48
    .. _tz-expr:
48 49
@@ -74,7 +75,16 @@
Loading
74 75
    _SECS_PER_YEAR = float(60 * 60 * 24 * 365.25)
75 76
76 77
    def __init__(
77 -
        self, year, month, day, hour=0, minute=0, second=0, microsecond=0, tzinfo=None
78 +
        self,
79 +
        year,
80 +
        month,
81 +
        day,
82 +
        hour=0,
83 +
        minute=0,
84 +
        second=0,
85 +
        microsecond=0,
86 +
        tzinfo=None,
87 +
        **kwargs
78 88
    ):
79 89
        if tzinfo is None:
80 90
            tzinfo = dateutil_tz.tzutc()
@@ -89,8 +99,12 @@
Loading
89 99
        elif util.isstr(tzinfo):
90 100
            tzinfo = parser.TzinfoParser.parse(tzinfo)
91 101
92 -
        self._datetime = datetime(
93 -
            year, month, day, hour, minute, second, microsecond, tzinfo
102 +
        fold = kwargs.get("fold", 0)
103 +
104 +
        # use enfold here to cover direct arrow.Arrow init on 2.7/3.5
105 +
        self._datetime = dateutil_tz.enfold(
106 +
            datetime(year, month, day, hour, minute, second, microsecond, tzinfo),
107 +
            fold=fold,
94 108
        )
95 109
96 110
    # factories: single object, both original and from datetime.
@@ -111,6 +125,7 @@
Loading
111 125
112 126
        if tzinfo is None:
113 127
            tzinfo = dateutil_tz.tzlocal()
128 +
114 129
        dt = datetime.now(tzinfo)
115 130
116 131
        return cls(
@@ -122,6 +137,7 @@
Loading
122 137
            dt.second,
123 138
            dt.microsecond,
124 139
            dt.tzinfo,
140 +
            fold=getattr(dt, "fold", 0),
125 141
        )
126 142
127 143
    @classmethod
@@ -147,6 +163,7 @@
Loading
147 163
            dt.second,
148 164
            dt.microsecond,
149 165
            dt.tzinfo,
166 +
            fold=getattr(dt, "fold", 0),
150 167
        )
151 168
152 169
    @classmethod
@@ -180,6 +197,7 @@
Loading
180 197
            dt.second,
181 198
            dt.microsecond,
182 199
            dt.tzinfo,
200 +
            fold=getattr(dt, "fold", 0),
183 201
        )
184 202
185 203
    @classmethod
@@ -207,6 +225,7 @@
Loading
207 225
            dt.second,
208 226
            dt.microsecond,
209 227
            dateutil_tz.tzutc(),
228 +
            fold=getattr(dt, "fold", 0),
210 229
        )
211 230
212 231
    @classmethod
@@ -242,6 +261,7 @@
Loading
242 261
            dt.second,
243 262
            dt.microsecond,
244 263
            tzinfo,
264 +
            fold=getattr(dt, "fold", 0),
245 265
        )
246 266
247 267
    @classmethod
@@ -288,6 +308,7 @@
Loading
288 308
            dt.second,
289 309
            dt.microsecond,
290 310
            tzinfo,
311 +
            fold=getattr(dt, "fold", 0),
291 312
        )
292 313
293 314
    # factories: ranges and spans
@@ -587,6 +608,20 @@
Loading
587 608
588 609
        return self.timestamp + float(self.microsecond) / 1000000
589 610
611 +
    @property
612 +
    def fold(self):
613 +
        """ Returns the ``fold`` value of the :class:`Arrow <arrow.arrow.Arrow>` object. """
614 +
615 +
        # in python < 3.6 _datetime will be a _DatetimeWithFold if fold=1 and a datetime with no fold attribute
616 +
        # otherwise, so we need to return zero to cover the latter case
617 +
        return getattr(self._datetime, "fold", 0)
618 +
619 +
    @property
620 +
    def ambiguous(self):
621 +
        """ Returns a boolean indicating whether the :class:`Arrow <arrow.arrow.Arrow>` object is ambiguous"""
622 +
623 +
        return dateutil_tz.datetime_ambiguous(self._datetime)
624 +
590 625
    # mutation and duplication.
591 626
592 627
    def clone(self):
@@ -630,7 +665,7 @@
Loading
630 665
                absolute_kwargs[key] = value
631 666
            elif key in ["week", "quarter"]:
632 667
                raise AttributeError("setting absolute {} is not supported".format(key))
633 -
            elif key != "tzinfo":
668 +
            elif key not in ["tzinfo", "fold"]:
634 669
                raise AttributeError('unknown attribute: "{}"'.format(key))
635 670
636 671
        current = self._datetime.replace(**absolute_kwargs)
@@ -641,6 +676,12 @@
Loading
641 676
            tzinfo = self._get_tzinfo(tzinfo)
642 677
            current = current.replace(tzinfo=tzinfo)
643 678
679 +
        fold = kwargs.get("fold")
680 +
681 +
        # TODO revisit this once we drop support for 2.7/3.5
682 +
        if fold is not None:
683 +
            current = dateutil_tz.enfold(current, fold=fold)
684 +
644 685
        return self.fromdatetime(current)
645 686
646 687
    def shift(self, **kwargs):
@@ -740,6 +781,7 @@
Loading
740 781
            dt.second,
741 782
            dt.microsecond,
742 783
            dt.tzinfo,
784 +
            fold=getattr(dt, "fold", 0),
743 785
        )
744 786
745 787
    @classmethod

Everything is accounted for!

No changes detected that need to be reviewed.
What changes does Codecov check for?
Lines, not adjusted in diff, that have changed coverage data.
Files that introduced coverage data that had none before.
Files that have missing coverage data that once were tracked.

18 Commits

+1
+1
+5
+5
-1 Files
-5
-5
-6
-6
+36
+36
+6
+6
+15
+15
+1
+1
Hiding 4 contexual commits
+1 Files
-43
-43
Pull Request Base Commit
Files Coverage
arrow 100.00%
Project Totals (9 files) 100.00%
Loading