-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Properly handle UTC conversion in date2num. #6262
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -212,47 +212,31 @@ def _to_ordinalf(dt): | |
days, preserving hours, minutes, seconds and microseconds. Return value | ||
is a :func:`float`. | ||
""" | ||
|
||
if hasattr(dt, 'tzinfo') and dt.tzinfo is not None: | ||
delta = dt.tzinfo.utcoffset(dt) | ||
if delta is not None: | ||
dt -= delta | ||
# Convert to UTC | ||
tzi = getattr(dt, 'tzinfo', None) | ||
if tzi is not None: | ||
dt = dt.astimezone(UTC) | ||
tzi = UTC | ||
|
||
base = float(dt.toordinal()) | ||
if isinstance(dt, datetime.datetime): | ||
# Get a datetime object at midnight in the same time zone as dt. | ||
cdate = dt.date() | ||
midnight_time = datetime.time(0, 0, 0, tzinfo=dt.tzinfo) | ||
|
||
# If it's sufficiently datetime-like, it will have a `date()` method | ||
cdate = getattr(dt, 'date', lambda: None)() | ||
if cdate is not None: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Based on the line above, I don't think cdate will ever be None--it can return None. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it is calling the attribute it obtains before assigning to cdate. On Mon, May 16, 2016 at 3:29 PM, Eric Firing notifications@github.com
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can be more explicit about this if you'd prefer. |
||
# Get a datetime object at midnight UTC | ||
midnight_time = datetime.time(0, tzinfo=tzi) | ||
|
||
rdt = datetime.datetime.combine(cdate, midnight_time) | ||
td_remainder = _total_seconds(dt - rdt) | ||
|
||
if td_remainder > 0: | ||
base += td_remainder / SEC_PER_DAY | ||
# Append the seconds as a fraction of a day | ||
base += (dt - rdt).total_seconds() / SEC_PER_DAY | ||
|
||
return base | ||
|
||
|
||
# a version of _to_ordinalf that can operate on numpy arrays | ||
_to_ordinalf_np_vectorized = np.vectorize(_to_ordinalf) | ||
|
||
try: | ||
# Available as a native method in Python >= 2.7. | ||
_total_seconds = datetime.timedelta.total_seconds | ||
except AttributeError: | ||
def _total_seconds(tdelta): | ||
""" | ||
Alias providing support for datetime.timedelta.total_seconds() function | ||
calls even in Python < 2.7. | ||
|
||
The input `tdelta` is a datetime.timedelta object, and returns a float | ||
containing the total number of seconds representing the `tdelta` | ||
duration. For large durations (> 270 on most platforms), this loses | ||
microsecond accuracy. | ||
""" | ||
return (tdelta.microseconds + | ||
(tdelta.seconds + tdelta.days * SEC_PER_DAY) * 1e6) * 1e-6 | ||
|
||
|
||
def _from_ordinalf(x, tz=None): | ||
""" | ||
|
@@ -432,7 +416,7 @@ def drange(dstart, dend, delta): | |
""" | ||
f1 = _to_ordinalf(dstart) | ||
f2 = _to_ordinalf(dend) | ||
step = _total_seconds(delta) / SEC_PER_DAY | ||
step = delta.total_seconds() / SEC_PER_DAY | ||
|
||
# calculate the difference between dend and dstart in times of delta | ||
num = int(np.ceil((f2 - f1) / step)) | ||
|
@@ -1061,8 +1045,8 @@ def get_locator(self, dmin, dmax): | |
numDays = tdelta.days # Avoids estimates of days/month, days/year | ||
numHours = (numDays * HOURS_PER_DAY) + delta.hours | ||
numMinutes = (numHours * MIN_PER_HOUR) + delta.minutes | ||
numSeconds = np.floor(_total_seconds(tdelta)) | ||
numMicroseconds = np.floor(_total_seconds(tdelta) * 1e6) | ||
numSeconds = np.floor(tdelta.total_seconds()) | ||
numMicroseconds = np.floor(tdelta.total_seconds() * 1e6) | ||
|
||
nums = [numYears, numMonths, numDays, numHours, numMinutes, | ||
numSeconds, numMicroseconds] | ||
|
@@ -1402,7 +1386,7 @@ def _close_to_dt(d1, d2, epsilon=5): | |
Assert that datetimes *d1* and *d2* are within *epsilon* microseconds. | ||
""" | ||
delta = d2 - d1 | ||
mus = abs(_total_seconds(delta) * 1e6) | ||
mus = abs(delta.total_seconds() * 1e6) | ||
assert mus < epsilon | ||
|
||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think Python 2.7
datetime.date
has theastimezone
method.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
date
also doesn't havetzinfo
, so theastimezone
line will never fire.Though, actually,
datetime.datetime.timetz()
returns an object that hastzinfo
and notastimezone
. I'm not really sure how to deal with that, though. Aretime
objects an acceptable input here? I think the offset returned will beNone
if you try and get theutcoffset
of a non-fixed-offset baretime
object.