Skip to content

Commit

Permalink
Merge pull request #146 from Unidata/issue143
Browse files Browse the repository at this point in the history
format microseconds correctly, make sure num2date gives same answer for scalars and arrays
  • Loading branch information
jswhit authored Mar 14, 2020
2 parents 9f7c576 + 1f1823c commit bcb2003
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 8 deletions.
6 changes: 6 additions & 0 deletions Changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
version 1.1.1 (not yet released)
=====================================

* fix microsecond formatting issue, ensure identical results
computed for arrays and scales (issue #143, PR #146).

version 1.1.0 (release tag v1.1.0rel)
=====================================

Expand Down
15 changes: 8 additions & 7 deletions cftime/_cftime.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ cdef int32_t* days_per_month_array = [
_rop_lookup = {Py_LT: '__gt__', Py_LE: '__ge__', Py_EQ: '__eq__',
Py_GT: '__lt__', Py_GE: '__le__', Py_NE: '__ne__'}

__version__ = '1.1.0'
__version__ = '1.1.1'

# Adapted from http://delete.me.uk/2005/03/iso8601.html
# Note: This regex ensures that all ISO8601 timezone formats are accepted - but, due to legacy support for other timestrings, not all incorrect formats can be rejected.
Expand Down Expand Up @@ -539,9 +539,10 @@ def DateFromJulianDay(JD, calendar='standard', only_use_cftime_datetimes=True,
year[i],month[i],day[i],dayofwk[i],dayofyr[i] = _IntJulianDayToDate(ijd,calendar)

if calendar in ['standard', 'gregorian']:
ind_before = np.where(julian < 2299160.5)[0]
ind_before = np.where(julian < 2299160.5)
ind_before = np.asarray(ind_before).any()
else:
ind_before = None
ind_before = False

# compute hour, minute, second, microsecond, convert to int32
hour = np.clip((F * 24.).astype(np.int64), 0, 23)
Expand Down Expand Up @@ -572,8 +573,8 @@ def DateFromJulianDay(JD, calendar='standard', only_use_cftime_datetimes=True,
indxms = microsecond > 1000000-ms_eps
if indxms.any():
julian[indxms] = julian[indxms] + 2*ms_eps[indxms]/86400000000.
year,month,day,hour,minute,second,microsecond,dayofyr,dayofwk,ind_before =\
getdateinfo(julian)
year[indxms],month[indxms],day[indxms],hour[indxms],minute[indxms],second[indxms],microsecond2,dayofyr[indxms],dayofwk[indxms],ind_before2 =\
getdateinfo(julian[indxms])
microsecond[indxms] = 0

# check if input was scalar and change return accordingly
Expand All @@ -599,7 +600,7 @@ def DateFromJulianDay(JD, calendar='standard', only_use_cftime_datetimes=True,
# return a 'real' datetime instance if calendar is proleptic
# Gregorian or Gregorian and all dates are after the
# Julian/Gregorian transition
if len(ind_before) == 0 and not only_use_cftime_datetimes:
if ind_before and not only_use_cftime_datetimes:
is_real_datetime = True
datetime_type = real_datetime
else:
Expand Down Expand Up @@ -1327,7 +1328,7 @@ Gregorial calendar.
def __str__(self):
second = '{:02d}'.format(self.second)
if self.microsecond:
second += '.{}'.format(self.microsecond)
second += '.{:06d}'.format(self.microsecond)

return "{:04d}-{:02d}-{:02d} {:02d}:{:02d}:{}".format(
self.year, self.month, self.day, self.hour, self.minute, second)
Expand Down
16 changes: 15 additions & 1 deletion test/test_cftime.py
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,21 @@ def test_tz_naive(self):
d = datetime.strptime('2018-01-23 09:27:10.950000',"%Y-%m-%d %H:%M:%S.%f")
units = 'seconds since 2018-01-23 09:31:42.94'
assert(cftime.date2num(d, units) == -271.99)
# issue 143 - same answer for arrays vs scalars.
units = 'seconds since 1970-01-01 00:00:00'
times_in = [1261440000.0, 1261440001.0, 1261440002.0, 1261440003.0,
1261440004.0, 1261440005.0]
times_out1 = cftime.num2date(times_in, units)
times_out2 = []
for time_in in times_in:
times_out2.append(cftime.num2date(time_in, units))
dates1 = [str(d) for d in times_out1]
dates2 = [str(d) for d in times_out2]
assert(dates1 == dates2)
# issue #143 formatting of microseconds
d = cftime.num2date(1261440000.015625,units)
# on windows only 100 ms precision
assert(str(d)[0:24] == '2009-12-22 00:00:00.0156')

class TestDate2index(unittest.TestCase):

Expand Down Expand Up @@ -1518,6 +1533,5 @@ def test_replace_dayofyr_or_dayofwk_error(date_type, argument):
with pytest.raises(ValueError):
date_type(1, 1, 1).replace(**{argument: 3})


if __name__ == '__main__':
unittest.main()

0 comments on commit bcb2003

Please sign in to comment.