diff --git a/cftime/_cftime.pyx b/cftime/_cftime.pyx index 4a98fca9..60080a6d 100644 --- a/cftime/_cftime.pyx +++ b/cftime/_cftime.pyx @@ -94,7 +94,7 @@ def _dateparse(timestr): (units, isostring) = _datesplit(timestr) # parse the date string. - year, month, day, hour, minute, second, utc_offset =\ + year, month, day, hour, minute, second, microsecond, utc_offset =\ _parse_date( isostring.strip() ) if year >= MINYEAR: basedate = real_datetime(year, month, day, hour, minute, second) @@ -122,7 +122,7 @@ cdef _parse_date_and_units(timestr,calendar='standard'): raise ValueError( "units must be one of 'seconds', 'minutes', 'hours' or 'days' (or singular version of these), got '%s'" % units) # parse the date string. - year, month, day, hour, minute, second, utc_offset = _parse_date( + year, month, day, hour, minute, second, microsecond, utc_offset = _parse_date( isostring.strip()) return units, utc_offset, datetime(year, month, day, hour, minute, second) @@ -916,7 +916,12 @@ cpdef _parse_date(datestring): The timezone is parsed from the date string, assuming UTC by default. + Note that a seconds element with a fractional component + (e.g. 12.5) is converted into integer seconds and integer + microseconds. + Adapted from pyiso8601 (http://code.google.com/p/pyiso8601/) + """ if not isinstance(datestring, str) and not isinstance(datestring, unicode): raise ValueError("Expecting a string %r" % datestring) @@ -931,13 +936,14 @@ cpdef _parse_date(datestring): groups["minute"] = 0 if groups["second"] is None: groups["second"] = 0 - # if groups["fraction"] is None: - # groups["fraction"] = 0 - # else: - # groups["fraction"] = int(float("0.%s" % groups["fraction"]) * 1e6) + if groups["fraction"] is None: + groups["fraction"] = 0 + else: + groups["fraction"] = int(float("0.%s" % groups["fraction"]) * 1e6) iyear = int(groups["year"]) return iyear, int(groups["month"]), int(groups["day"]),\ int(groups["hour"]), int(groups["minute"]), int(groups["second"]),\ + int(groups["fraction"]),\ tzoffset_mins cdef _check_index(indices, times, nctime, calendar, select): diff --git a/test/test_cftime.py b/test/test_cftime.py index d78b1e05..94a8588b 100644 --- a/test/test_cftime.py +++ b/test/test_cftime.py @@ -1233,25 +1233,25 @@ def test_parse_date_tz(self): "Test timezone parsing in _parse_date" # these should succeed and are ISO8601 compliant - expected_parsed_date = (2017, 5, 1, 0, 0, 0, 60.0) + expected_parsed_date = (2017, 5, 1, 0, 0, 0, 0, 60.0) for datestr in ("2017-05-01 00:00+01:00", "2017-05-01 00:00+0100", "2017-05-01 00:00+01"): d = _parse_date(datestr) assert_equal(d, expected_parsed_date) # some more tests with non-zero minutes, should all be ISO compliant and work - expected_parsed_date = (2017, 5, 1, 0, 0, 0, 85.0) + expected_parsed_date = (2017, 5, 1, 0, 0, 0, 0, 85.0) for datestr in ("2017-05-01 00:00+01:25", "2017-05-01 00:00+0125"): d = _parse_date(datestr) assert_equal(d, expected_parsed_date) # these are NOT ISO8601 compliant and should not even be parseable but will be parsed with timezone anyway # because, due to support of other legacy time formats, they are difficult to reject # ATTENTION: only the hours part of this will be parsed, single-digit minutes will be ignored! - expected_parsed_date = (2017, 5, 1, 0, 0, 0, 60.0) + expected_parsed_date = (2017, 5, 1, 0, 0, 0, 0, 60.0) for datestr in ("2017-05-01 00:00+01:0", "2017-05-01 00:00+01:", "2017-05-01 00:00+01:5"): d = _parse_date(datestr) assert_equal(d, expected_parsed_date) # these should not even be parseable as datestrings but are parseable anyway with ignored timezone # this is because the module also supports some legacy, non-standard time strings - expected_parsed_date = (2017, 5, 1, 0, 0, 0, 0.0) + expected_parsed_date = (2017, 5, 1, 0, 0, 0, 0, 0.0) for datestr in ("2017-05-01 00:00+1",): d = _parse_date(datestr) assert_equal(d, expected_parsed_date) @@ -1486,6 +1486,7 @@ def test_dayofwk_after_replace(date_type): original_dayofwk = date.dayofwk expected = (original_dayofwk + 1) % 7 result = date.replace(day=2).dayofwk + print ('dch', repr(date), original_dayofwk, expected, result, repr(date.replace(day=2)), cftime.__file__) assert result == expected