summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/release/1.11.0-notes.rst37
-rw-r--r--doc/source/reference/arrays.datetime.rst62
-rw-r--r--numpy/core/arrayprint.py14
-rw-r--r--numpy/core/src/multiarray/datetime.c32
-rw-r--r--numpy/core/src/multiarray/datetime_strings.c228
-rw-r--r--numpy/core/src/multiarray/datetime_strings.h7
-rw-r--r--numpy/core/src/multiarray/dtype_transfer.c6
-rw-r--r--numpy/core/src/multiarray/scalartypes.c.src22
-rw-r--r--numpy/core/tests/test_datetime.py369
-rw-r--r--numpy/core/tests/test_deprecations.py29
10 files changed, 349 insertions, 457 deletions
diff --git a/doc/release/1.11.0-notes.rst b/doc/release/1.11.0-notes.rst
index b5d22d770..ac3c1578c 100644
--- a/doc/release/1.11.0-notes.rst
+++ b/doc/release/1.11.0-notes.rst
@@ -7,6 +7,8 @@ This release supports Python 2.6 - 2.7 and 3.2 - 3.5.
Highlights
==========
+* The datetime64 type is now timezone naive. See "datetime64 changes" below
+ for more details.
Dropped Support
===============
@@ -25,6 +27,41 @@ Future Changes
Compatibility notes
===================
+datetime64 changes
+~~~~~~~~~~~~~~~~~~
+
+In prior versions of NumPy the experimental datetime64 type always stored
+times in UTC. By default, creating a datetime64 object from a string or
+printing it would convert from or to local time::
+
+ # old behavior
+ >>>> np.datetime64('2000-01-01T00:00:00')
+ numpy.datetime64('2000-01-01T00:00:00-0800') # note the timezone offset -08:00
+
+A concensus of datetime64 users agreed that this behavior is undesirable
+and at odds with how datetime64 is usually used (e.g., by pandas_). For
+most use cases, a timezone naive datetime type is preferred, similar to the
+``datetime.datetime`` type in the Python standard library. Accordingly,
+datetime64 no longer assumes that input is in local time, nor does it print
+local times::
+
+ >>>> np.datetime64('2000-01-01T00:00:00')
+ numpy.datetime64('2000-01-01T00:00:00')
+
+For backwards compatibility, datetime64 still parses timezone offsets, which
+it handles by converting to UTC. However, the resulting datetime is timezone
+naive::
+
+ >>> np.datetime64('2000-01-01T00:00:00-08')
+ DeprecationWarning: parsing timezone aware datetimes is deprecated; this will raise an error in the future
+ numpy.datetime64('2000-01-01T08:00:00')
+
+As a corollary to this change, we no longer prohibit casting between datetimes
+with date units and datetimes with timeunits. With timezone naive datetimes,
+the rule for casting from dates to times is no longer ambiguous.
+
+pandas_: http://pandas.pydata.org
+
DeprecationWarning to error
~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/doc/source/reference/arrays.datetime.rst b/doc/source/reference/arrays.datetime.rst
index 0e8050b01..f5b454875 100644
--- a/doc/source/reference/arrays.datetime.rst
+++ b/doc/source/reference/arrays.datetime.rst
@@ -45,16 +45,10 @@ some additional SI-prefix seconds-based units.
>>> np.datetime64('2005-02', 'D')
numpy.datetime64('2005-02-01')
- Using UTC "Zulu" time:
-
- >>> np.datetime64('2005-02-25T03:30Z')
- numpy.datetime64('2005-02-24T21:30-0600')
-
- ISO 8601 specifies to use the local time zone
- if none is explicitly given:
+ From a date and time:
>>> np.datetime64('2005-02-25T03:30')
- numpy.datetime64('2005-02-25T03:30-0600')
+ numpy.datetime64('2005-02-25T03:30')
When creating an array of datetimes from a string, it is still possible
to automatically select the unit from the inputs, by using the
@@ -100,23 +94,6 @@ because the moment of time is still being represented exactly.
>>> np.datetime64('2010-03-14T15Z') == np.datetime64('2010-03-14T15:00:00.00Z')
True
-An important exception to this rule is between datetimes with
-:ref:`date units <arrays.dtypes.dateunits>` and datetimes with
-:ref:`time units <arrays.dtypes.timeunits>`. This is because this kind
-of conversion generally requires a choice of timezone and
-particular time of day on the given date.
-
-.. admonition:: Example
-
- >>> np.datetime64('2003-12-25', 's')
- Traceback (most recent call last):
- File "<stdin>", line 1, in <module>
- TypeError: Cannot parse "2003-12-25" as unit 's' using casting rule 'same_kind'
-
- >>> np.datetime64('2003-12-25') == np.datetime64('2003-12-25T00Z')
- False
-
-
Datetime and Timedelta Arithmetic
=================================
@@ -353,6 +330,41 @@ Some examples::
# any amount of whitespace is allowed; abbreviations are case-sensitive.
weekmask = "MonTue Wed Thu\tFri"
+Changes with NumPy 1.11
+=======================
+
+In prior versions of NumPy, the datetime64 type always stored
+times in UTC. By default, creating a datetime64 object from a string or
+printing it would convert from or to local time::
+
+ # old behavior
+ >>>> np.datetime64('2000-01-01T00:00:00')
+ numpy.datetime64('2000-01-01T00:00:00-0800') # note the timezone offset -08:00
+
+A concensus of datetime64 users agreed that this behavior is undesirable
+and at odds with how datetime64 is usually used (e.g., by pandas_). For
+most use cases, a timezone naive datetime type is preferred, similar to the
+``datetime.datetime`` type in the Python standard library. Accordingly,
+datetime64 no longer assumes that input is in local time, nor does it print
+local times::
+
+ >>>> np.datetime64('2000-01-01T00:00:00')
+ numpy.datetime64('2000-01-01T00:00:00')
+
+For backwards compatibility, datetime64 still parses timezone offsets, which
+it handles by converting to UTC. However, the resulting datetime is timezone
+naive::
+
+ >>> np.datetime64('2000-01-01T00:00:00-08')
+ DeprecationWarning: parsing timezone aware datetimes is deprecated; this will raise an error in the future
+ numpy.datetime64('2000-01-01T08:00:00')
+
+As a corollary to this change, we no longer prohibit casting between datetimes
+with date units and datetimes with timeunits. With timezone naive datetimes,
+the rule for casting from dates to times is no longer ambiguous.
+
+pandas_: http://pandas.pydata.org
+
Differences Between 1.6 and 1.7 Datetimes
=========================================
diff --git a/numpy/core/arrayprint.py b/numpy/core/arrayprint.py
index c5b5b5a8f..74a9d3da3 100644
--- a/numpy/core/arrayprint.py
+++ b/numpy/core/arrayprint.py
@@ -708,9 +708,9 @@ class ComplexFormat(object):
i = i + 'j'
return r + i
+
class DatetimeFormat(object):
- def __init__(self, x, unit=None,
- timezone=None, casting='same_kind'):
+ def __init__(self, x, unit=None, timezone=None, casting='same_kind'):
# Get the unit from the dtype
if unit is None:
if x.dtype.kind == 'M':
@@ -718,15 +718,9 @@ class DatetimeFormat(object):
else:
unit = 's'
- # If timezone is default, make it 'local' or 'UTC' based on the unit
if timezone is None:
- # Date units -> UTC, time units -> local
- if unit in ('Y', 'M', 'W', 'D'):
- self.timezone = 'UTC'
- else:
- self.timezone = 'local'
- else:
- self.timezone = timezone
+ timezone = 'naive'
+ self.timezone = timezone
self.unit = unit
self.casting = casting
diff --git a/numpy/core/src/multiarray/datetime.c b/numpy/core/src/multiarray/datetime.c
index 264178d30..3cf9a2bd5 100644
--- a/numpy/core/src/multiarray/datetime.c
+++ b/numpy/core/src/multiarray/datetime.c
@@ -1316,9 +1316,6 @@ datetime_metadata_divides(
/*
* This provides the casting rules for the DATETIME data type units.
- *
- * Notably, there is a barrier between 'date units' and 'time units'
- * for all but 'unsafe' casting.
*/
NPY_NO_EXPORT npy_bool
can_cast_datetime64_units(NPY_DATETIMEUNIT src_unit,
@@ -1331,31 +1328,26 @@ can_cast_datetime64_units(NPY_DATETIMEUNIT src_unit,
return 1;
/*
- * Only enforce the 'date units' vs 'time units' barrier with
- * 'same_kind' casting.
+ * Can cast between all units with 'same_kind' casting.
*/
case NPY_SAME_KIND_CASTING:
if (src_unit == NPY_FR_GENERIC || dst_unit == NPY_FR_GENERIC) {
return src_unit == NPY_FR_GENERIC;
}
else {
- return (src_unit <= NPY_FR_D && dst_unit <= NPY_FR_D) ||
- (src_unit > NPY_FR_D && dst_unit > NPY_FR_D);
+ return 1;
}
/*
- * Enforce the 'date units' vs 'time units' barrier and that
- * casting is only allowed towards more precise units with
- * 'safe' casting.
+ * Casting is only allowed towards more precise units with 'safe'
+ * casting.
*/
case NPY_SAFE_CASTING:
if (src_unit == NPY_FR_GENERIC || dst_unit == NPY_FR_GENERIC) {
return src_unit == NPY_FR_GENERIC;
}
else {
- return (src_unit <= dst_unit) &&
- ((src_unit <= NPY_FR_D && dst_unit <= NPY_FR_D) ||
- (src_unit > NPY_FR_D && dst_unit > NPY_FR_D));
+ return (src_unit <= dst_unit);
}
/* Enforce equality with 'no' or 'equiv' casting */
@@ -2254,6 +2246,14 @@ convert_pydatetime_to_datetimestruct(PyObject *obj, npy_datetimestruct *out,
PyObject *offset;
int seconds_offset, minutes_offset;
+ /* 2016-01-14, 1.11 */
+ PyErr_Clear();
+ if (DEPRECATE(
+ "parsing timezone aware datetimes is deprecated; "
+ "this will raise an error in the future") < 0) {
+ return -1;
+ }
+
/* The utcoffset function should return a timedelta */
offset = PyObject_CallMethod(tmp, "utcoffset", "O", obj);
if (offset == NULL) {
@@ -2386,7 +2386,7 @@ convert_pyobject_to_datetime(PyArray_DatetimeMetaData *meta, PyObject *obj,
/* Parse the ISO date */
if (parse_iso_8601_datetime(str, len, meta->base, casting,
- &dts, NULL, &bestunit, NULL) < 0) {
+ &dts, &bestunit, NULL) < 0) {
Py_DECREF(bytes);
return -1;
}
@@ -3500,7 +3500,7 @@ find_string_array_datetime64_type(PyArrayObject *arr,
tmp_meta.base = -1;
if (parse_iso_8601_datetime(tmp_buffer, maxlen, -1,
- NPY_UNSAFE_CASTING, &dts, NULL,
+ NPY_UNSAFE_CASTING, &dts,
&tmp_meta.base, NULL) < 0) {
goto fail;
}
@@ -3509,7 +3509,7 @@ find_string_array_datetime64_type(PyArrayObject *arr,
else {
tmp_meta.base = -1;
if (parse_iso_8601_datetime(data, tmp - data, -1,
- NPY_UNSAFE_CASTING, &dts, NULL,
+ NPY_UNSAFE_CASTING, &dts,
&tmp_meta.base, NULL) < 0) {
goto fail;
}
diff --git a/numpy/core/src/multiarray/datetime_strings.c b/numpy/core/src/multiarray/datetime_strings.c
index 54587cb5c..09ddc46d4 100644
--- a/numpy/core/src/multiarray/datetime_strings.c
+++ b/numpy/core/src/multiarray/datetime_strings.c
@@ -111,82 +111,6 @@ fail:
}
/*
- * Wraps `gmtime` functionality for multiple platforms. This
- * converts a time value to a time structure in UTC.
- *
- * Returns 0 on success, -1 on failure.
- */
-static int
-get_gmtime(NPY_TIME_T *ts, struct tm *tms)
-{
- char *func_name = "<unknown>";
-#if defined(_WIN32)
- #if defined(_MSC_VER) && (_MSC_VER >= 1400)
- if (gmtime_s(tms, ts) != 0) {
- func_name = "gmtime_s";
- goto fail;
- }
- #elif defined(NPY_MINGW_USE_CUSTOM_MSVCR)
- if (_gmtime64_s(tms, ts) != 0) {
- func_name = "_gmtime64_s";
- goto fail;
- }
- #else
- struct tm *tms_tmp;
- tms_tmp = gmtime(ts);
- if (tms_tmp == NULL) {
- func_name = "gmtime";
- goto fail;
- }
- memcpy(tms, tms_tmp, sizeof(struct tm));
- #endif
-#else
- if (gmtime_r(ts, tms) == NULL) {
- func_name = "gmtime_r";
- goto fail;
- }
-#endif
-
- return 0;
-
-fail:
- PyErr_Format(PyExc_OSError, "Failed to use '%s' to convert "
- "to a UTC time", func_name);
- return -1;
-}
-
-/*
- * Wraps `mktime` functionality for multiple platforms. This
- * converts a local time struct to an UTC value.
- *
- * Returns timestamp on success, -1 on failure.
- */
-static NPY_TIME_T
-get_mktime(struct tm *tms)
-{
- char *func_name = "<unknown>";
- NPY_TIME_T ts;
-#if defined(NPY_MINGW_USE_CUSTOM_MSVCR)
- ts = _mktime64(tms);
- if (ts == -1) {
- func_name = "_mktime64";
- goto fail;
- }
-#else
- ts = mktime(tms);
- if (ts == -1) {
- func_name = "mktime";
- goto fail;
- }
-#endif
- return ts;
-fail:
- PyErr_Format(PyExc_OSError, "Failed to use '%s' to convert "
- "local time to UTC", func_name);
- return -1;
-}
-
-/*
* Converts a datetimestruct in UTC to a datetimestruct in local time,
* also returning the timezone offset applied. This function works for any year
* > 1970 on all platforms and both 32 and 64 bits. If the year < 1970, then it
@@ -263,85 +187,6 @@ convert_datetimestruct_utc_to_local(npy_datetimestruct *out_dts_local,
}
/*
- * Converts a datetimestruct in local time to a datetimestruct in UTC.
- *
- * Returns 0 on success, -1 on failure.
- */
-static int
-convert_datetimestruct_local_to_utc(npy_datetimestruct *out_dts_utc,
- const npy_datetimestruct *dts_local)
-{
- npy_int64 year_correction = 0;
-
- /* Make a copy of the input 'dts' to modify */
- *out_dts_utc = *dts_local;
-
- /*
- * For 32 bit NPY_TIME_T, the get_mktime()/get_gmtime() functions do not
- * work for years later than 2038. So if the year >= 2038, we instead call
- * get_mktime()/get_gmtime() for the year 2036 or 2037 (depending on the
- * leap year) which must work and at the end we add the 'year_correction'
- * back.
- */
- if (sizeof(NPY_TIME_T) == 4 && out_dts_utc->year >= 2038) {
- if (is_leapyear(out_dts_utc->year)) {
- /* 2036 is a leap year */
- year_correction = out_dts_utc->year - 2036;
- out_dts_utc->year -= year_correction; /* = 2036 */
- }
- else {
- /* 2037 is not a leap year */
- year_correction = out_dts_utc->year - 2037;
- out_dts_utc->year -= year_correction; /* = 2037 */
- }
- }
-
- /*
- * ISO 8601 states to treat date-times without a timezone offset
- * or 'Z' for UTC as local time. The C standard libary functions
- * mktime and gmtime allow us to do this conversion.
- *
- * Only do this timezone adjustment for recent and future years.
- * In this case, "recent" is defined to be 1970 and later, because
- * on MS Windows, mktime raises an error when given an earlier date.
- */
- if (out_dts_utc->year >= 1970) {
- NPY_TIME_T rawtime = 0;
- struct tm tm_;
-
- tm_.tm_sec = out_dts_utc->sec;
- tm_.tm_min = out_dts_utc->min;
- tm_.tm_hour = out_dts_utc->hour;
- tm_.tm_mday = out_dts_utc->day;
- tm_.tm_mon = out_dts_utc->month - 1;
- tm_.tm_year = out_dts_utc->year - 1900;
- tm_.tm_isdst = -1;
-
- /* mktime converts a local 'struct tm' into a time_t */
- rawtime = get_mktime(&tm_);
- if (rawtime == -1) {
- return -1;
- }
-
- /* gmtime converts a 'time_t' into a UTC 'struct tm' */
- if (get_gmtime(&rawtime, &tm_) < 0) {
- return -1;
- }
- out_dts_utc->sec = tm_.tm_sec;
- out_dts_utc->min = tm_.tm_min;
- out_dts_utc->hour = tm_.tm_hour;
- out_dts_utc->day = tm_.tm_mday;
- out_dts_utc->month = tm_.tm_mon + 1;
- out_dts_utc->year = tm_.tm_year + 1900;
- }
-
- /* Reapply the year 2038 year correction */
- out_dts_utc->year += year_correction;
-
- return 0;
-}
-
-/*
* Parses (almost) standard ISO 8601 date strings. The differences are:
*
* + The date "20100312" is parsed as the year 20100312, not as
@@ -363,10 +208,6 @@ convert_datetimestruct_local_to_utc(npy_datetimestruct *out_dts_utc,
* to be cast to the 'unit' parameter.
*
* 'out' gets filled with the parsed date-time.
- * 'out_local' gets set to 1 if the parsed time was in local time,
- * to 0 otherwise. The values 'now' and 'today' don't get counted
- * as local, and neither do UTC +/-#### timezone offsets, because
- * they aren't using the computer's local timezone offset.
* 'out_bestunit' gives a suggested unit based on the amount of
* resolution provided in the string, or -1 for NaT.
* 'out_special' gets set to 1 if the parsed time was 'today',
@@ -381,7 +222,6 @@ parse_iso_8601_datetime(char *str, Py_ssize_t len,
NPY_DATETIMEUNIT unit,
NPY_CASTING casting,
npy_datetimestruct *out,
- npy_bool *out_local,
NPY_DATETIMEUNIT *out_bestunit,
npy_bool *out_special)
{
@@ -411,9 +251,6 @@ parse_iso_8601_datetime(char *str, Py_ssize_t len,
* Indicate that this was a special value, and
* recommend generic units.
*/
- if (out_local != NULL) {
- *out_local = 0;
- }
if (out_bestunit != NULL) {
*out_bestunit = NPY_FR_GENERIC;
}
@@ -462,9 +299,6 @@ parse_iso_8601_datetime(char *str, Py_ssize_t len,
* Indicate that this was a special value, and
* is a date (unit 'D').
*/
- if (out_local != NULL) {
- *out_local = 0;
- }
if (out_bestunit != NULL) {
*out_bestunit = bestunit;
}
@@ -505,9 +339,6 @@ parse_iso_8601_datetime(char *str, Py_ssize_t len,
* use 's' because the time() function has resolution
* seconds.
*/
- if (out_local != NULL) {
- *out_local = 0;
- }
if (out_bestunit != NULL) {
*out_bestunit = bestunit;
}
@@ -569,9 +400,6 @@ parse_iso_8601_datetime(char *str, Py_ssize_t len,
/* Next character must be a '-' or the end of the string */
if (sublen == 0) {
- if (out_local != NULL) {
- *out_local = 0;
- }
bestunit = NPY_FR_Y;
goto finish;
}
@@ -606,9 +434,6 @@ parse_iso_8601_datetime(char *str, Py_ssize_t len,
/* Next character must be a '-' or the end of the string */
if (sublen == 0) {
- if (out_local != NULL) {
- *out_local = 0;
- }
bestunit = NPY_FR_M;
goto finish;
}
@@ -644,9 +469,6 @@ parse_iso_8601_datetime(char *str, Py_ssize_t len,
/* Next character must be a 'T', ' ', or end of string */
if (sublen == 0) {
- if (out_local != NULL) {
- *out_local = 0;
- }
bestunit = NPY_FR_D;
goto finish;
}
@@ -811,25 +633,20 @@ parse_iso_8601_datetime(char *str, Py_ssize_t len,
parse_timezone:
if (sublen == 0) {
- if (convert_datetimestruct_local_to_utc(out, out) < 0) {
- goto error;
- }
-
- /* Since neither "Z" nor a time-zone was specified, it's local */
- if (out_local != NULL) {
- *out_local = 1;
- }
-
goto finish;
}
+ else {
+ /* 2016-01-14, 1.11 */
+ PyErr_Clear();
+ if (DEPRECATE(
+ "parsing timezone aware datetimes is deprecated; "
+ "this will raise an error in the future") < 0) {
+ return -1;
+ }
+ }
/* UTC specifier */
if (*substr == 'Z') {
- /* "Z" means not local */
- if (out_local != NULL) {
- *out_local = 0;
- }
-
if (sublen == 1) {
goto finish;
}
@@ -842,14 +659,6 @@ parse_timezone:
else if (*substr == '-' || *substr == '+') {
int offset_neg = 0, offset_hour = 0, offset_minute = 0;
- /*
- * Since "local" means local with respect to the current
- * machine, we say this is non-local.
- */
- if (out_local != NULL) {
- *out_local = 0;
- }
-
if (*substr == '-') {
offset_neg = 1;
}
@@ -1056,7 +865,9 @@ lossless_unit_from_datetimestruct(npy_datetimestruct *dts)
* the number of year digits is >= 4 instead of strictly 4.
*
* If 'local' is non-zero, it produces a string in local time with
- * a +-#### timezone offset, otherwise it uses timezone Z (UTC).
+ * a +-#### timezone offset. If 'local' is zero and 'utc' is non-zero,
+ * produce a string ending with 'Z' to denote UTC. By default, no time
+ * zone information is attached.
*
* 'base' restricts the output to that unit. Set 'base' to
* -1 to auto-detect a base after which all the values are zero.
@@ -1075,7 +886,7 @@ lossless_unit_from_datetimestruct(npy_datetimestruct *dts)
*/
NPY_NO_EXPORT int
make_iso_8601_datetime(npy_datetimestruct *dts, char *outstr, int outlen,
- int local, NPY_DATETIMEUNIT base, int tzoffset,
+ int local, int utc, NPY_DATETIMEUNIT base, int tzoffset,
NPY_CASTING casting)
{
npy_datetimestruct dts_local;
@@ -1491,7 +1302,7 @@ add_time_zone:
sublen -= 4;
}
/* UTC "Zulu" time */
- else {
+ else if (utc) {
if (sublen < 1) {
goto string_too_short;
}
@@ -1528,6 +1339,7 @@ array_datetime_as_string(PyObject *NPY_UNUSED(self), PyObject *args,
NPY_CASTING casting = NPY_SAME_KIND_CASTING;
int local = 0;
+ int utc = 0;
PyArray_DatetimeMetaData *meta;
int strsize;
@@ -1643,11 +1455,19 @@ array_datetime_as_string(PyObject *NPY_UNUSED(self), PyObject *args,
if (strcmp(str, "local") == 0) {
local = 1;
+ utc = 0;
Py_DECREF(timezone_obj);
timezone_obj = NULL;
}
else if (strcmp(str, "UTC") == 0) {
local = 0;
+ utc = 1;
+ Py_DECREF(timezone_obj);
+ timezone_obj = NULL;
+ }
+ else if (strcmp(str, "naive") == 0) {
+ local = 0;
+ utc = 0;
Py_DECREF(timezone_obj);
timezone_obj = NULL;
}
@@ -1738,7 +1558,7 @@ array_datetime_as_string(PyObject *NPY_UNUSED(self), PyObject *args,
memset(dataptr[1], 0, strsize);
/* Convert that into a string */
if (make_iso_8601_datetime(&dts, (char *)dataptr[1], strsize,
- local, unit, tzoffset, casting) < 0) {
+ local, utc, unit, tzoffset, casting) < 0) {
goto fail;
}
} while(iternext(iter));
diff --git a/numpy/core/src/multiarray/datetime_strings.h b/numpy/core/src/multiarray/datetime_strings.h
index 4280f6de4..d7608565c 100644
--- a/numpy/core/src/multiarray/datetime_strings.h
+++ b/numpy/core/src/multiarray/datetime_strings.h
@@ -23,10 +23,6 @@
* to be cast to the 'unit' parameter.
*
* 'out' gets filled with the parsed date-time.
- * 'out_local' gets set to 1 if the parsed time was in local time,
- * to 0 otherwise. The values 'now' and 'today' don't get counted
- * as local, and neither do UTC +/-#### timezone offsets, because
- * they aren't using the computer's local timezone offset.
* 'out_bestunit' gives a suggested unit based on the amount of
* resolution provided in the string, or -1 for NaT.
* 'out_special' gets set to 1 if the parsed time was 'today',
@@ -41,7 +37,6 @@ parse_iso_8601_datetime(char *str, Py_ssize_t len,
NPY_DATETIMEUNIT unit,
NPY_CASTING casting,
npy_datetimestruct *out,
- npy_bool *out_local,
NPY_DATETIMEUNIT *out_bestunit,
npy_bool *out_special);
@@ -76,7 +71,7 @@ get_datetime_iso_8601_strlen(int local, NPY_DATETIMEUNIT base);
*/
NPY_NO_EXPORT int
make_iso_8601_datetime(npy_datetimestruct *dts, char *outstr, int outlen,
- int local, NPY_DATETIMEUNIT base, int tzoffset,
+ int local, int utc, NPY_DATETIMEUNIT base, int tzoffset,
NPY_CASTING casting);
/*
diff --git a/numpy/core/src/multiarray/dtype_transfer.c b/numpy/core/src/multiarray/dtype_transfer.c
index f11ea395f..bfb22ac30 100644
--- a/numpy/core/src/multiarray/dtype_transfer.c
+++ b/numpy/core/src/multiarray/dtype_transfer.c
@@ -868,7 +868,7 @@ _strided_to_strided_datetime_to_string(char *dst, npy_intp dst_stride,
* to use PyErr_Occurred().
*/
make_iso_8601_datetime(&dts, dst, dst_itemsize,
- 0, d->src_meta.base, -1,
+ 0, 0, d->src_meta.base, -1,
NPY_UNSAFE_CASTING);
dst += dst_stride;
@@ -901,7 +901,7 @@ _strided_to_strided_string_to_datetime(char *dst, npy_intp dst_stride,
if (parse_iso_8601_datetime(tmp_buffer, src_itemsize,
d->dst_meta.base, NPY_SAME_KIND_CASTING,
- &dts, NULL, NULL, NULL) < 0) {
+ &dts, NULL, NULL) < 0) {
dt = NPY_DATETIME_NAT;
}
}
@@ -909,7 +909,7 @@ _strided_to_strided_string_to_datetime(char *dst, npy_intp dst_stride,
else {
if (parse_iso_8601_datetime(src, tmp - src,
d->dst_meta.base, NPY_SAME_KIND_CASTING,
- &dts, NULL, NULL, NULL) < 0) {
+ &dts, NULL, NULL) < 0) {
dt = NPY_DATETIME_NAT;
}
}
diff --git a/numpy/core/src/multiarray/scalartypes.c.src b/numpy/core/src/multiarray/scalartypes.c.src
index 7c73822dd..2b3dc1817 100644
--- a/numpy/core/src/multiarray/scalartypes.c.src
+++ b/numpy/core/src/multiarray/scalartypes.c.src
@@ -647,7 +647,6 @@ datetimetype_repr(PyObject *self)
npy_datetimestruct dts;
PyObject *ret;
char iso[NPY_DATETIME_MAX_ISO8601_STRLEN];
- int local;
NPY_DATETIMEUNIT unit;
if (!PyArray_IsScalar(self, Datetime)) {
@@ -663,16 +662,8 @@ datetimetype_repr(PyObject *self)
return NULL;
}
- local = (scal->obmeta.base > NPY_FR_D);
- /*
- * Because we're defaulting to local time, display hours with
- * minutes precision, so that 30-minute timezone offsets can work.
- */
unit = scal->obmeta.base;
- if (unit == NPY_FR_h) {
- unit = NPY_FR_m;
- }
- if (make_iso_8601_datetime(&dts, iso, sizeof(iso), local,
+ if (make_iso_8601_datetime(&dts, iso, sizeof(iso), 0, 0,
unit, -1, NPY_SAFE_CASTING) < 0) {
return NULL;
}
@@ -758,7 +749,6 @@ datetimetype_str(PyObject *self)
PyDatetimeScalarObject *scal;
npy_datetimestruct dts;
char iso[NPY_DATETIME_MAX_ISO8601_STRLEN];
- int local;
NPY_DATETIMEUNIT unit;
if (!PyArray_IsScalar(self, Datetime)) {
@@ -774,16 +764,8 @@ datetimetype_str(PyObject *self)
return NULL;
}
- local = (scal->obmeta.base > NPY_FR_D);
- /*
- * Because we're defaulting to local time, display hours with
- * minutes precision, so that 30-minute timezone offsets can work.
- */
unit = scal->obmeta.base;
- if (unit == NPY_FR_h) {
- unit = NPY_FR_m;
- }
- if (make_iso_8601_datetime(&dts, iso, sizeof(iso), local,
+ if (make_iso_8601_datetime(&dts, iso, sizeof(iso), 0, 0,
unit, -1, NPY_SAFE_CASTING) < 0) {
return NULL;
}
diff --git a/numpy/core/tests/test_datetime.py b/numpy/core/tests/test_datetime.py
index 65b1d460a..3a4dcc8d3 100644
--- a/numpy/core/tests/test_datetime.py
+++ b/numpy/core/tests/test_datetime.py
@@ -9,7 +9,7 @@ import datetime
from numpy.compat import asbytes
from numpy.testing import (
TestCase, run_module_suite, assert_, assert_equal, assert_raises,
- dec
+ assert_warns, dec
)
# Use pytz to test out various time zones if available
@@ -99,9 +99,8 @@ class TestDateTime(TestCase):
# Can't cast timedelta same_kind from months/years to days
assert_(not np.can_cast('m8[M]', 'm8[D]', casting='same_kind'))
assert_(not np.can_cast('m8[Y]', 'm8[D]', casting='same_kind'))
- # Can't cast datetime same_kind across the date/time boundary
- assert_(not np.can_cast('M8[D]', 'M8[h]', casting='same_kind'))
- assert_(not np.can_cast('M8[h]', 'M8[D]', casting='same_kind'))
+ # Can cast datetime same_kind across the date/time boundary
+ assert_(np.can_cast('M8[D]', 'M8[h]', casting='same_kind'))
# Can cast timedelta same_kind across the date/time boundary
assert_(np.can_cast('m8[D]', 'm8[h]', casting='same_kind'))
assert_(np.can_cast('m8[h]', 'm8[D]', casting='same_kind'))
@@ -140,8 +139,8 @@ class TestDateTime(TestCase):
# Construct with different units
assert_equal(np.datetime64('1950-03-12', 'D'),
np.datetime64('1950-03-12'))
- assert_equal(np.datetime64('1950-03-12T13Z', 's'),
- np.datetime64('1950-03-12T13Z', 'm'))
+ assert_equal(np.datetime64('1950-03-12T13', 's'),
+ np.datetime64('1950-03-12T13', 'm'))
# Default construction means NaT
assert_equal(np.datetime64(), np.datetime64('NaT'))
@@ -166,8 +165,8 @@ class TestDateTime(TestCase):
# When constructing from a scalar or zero-dimensional array,
# it either keeps the units or you can override them.
- a = np.datetime64('2000-03-18T16Z', 'h')
- b = np.array('2000-03-18T16Z', dtype='M8[h]')
+ a = np.datetime64('2000-03-18T16', 'h')
+ b = np.array('2000-03-18T16', dtype='M8[h]')
assert_equal(a.dtype, np.dtype('M8[h]'))
assert_equal(b.dtype, np.dtype('M8[h]'))
@@ -190,22 +189,36 @@ class TestDateTime(TestCase):
assert_equal(np.datetime64('2045-03-25', 'D'),
np.datetime64(datetime.date(2045, 3, 25), 'D'))
# Construction from datetime.datetime
- assert_equal(np.datetime64('1980-01-25T14:36:22.5Z'),
+ assert_equal(np.datetime64('1980-01-25T14:36:22.5'),
np.datetime64(datetime.datetime(1980, 1, 25,
14, 36, 22, 500000)))
- # Construction with time units from a date raises
- assert_raises(TypeError, np.datetime64, '1920-03-13', 'h')
- assert_raises(TypeError, np.datetime64, '1920-03', 'm')
- assert_raises(TypeError, np.datetime64, '1920', 's')
- assert_raises(TypeError, np.datetime64, datetime.date(2045, 3, 25), 'ms')
- # Construction with date units from a datetime raises
- assert_raises(TypeError, np.datetime64, '1920-03-13T18Z', 'D')
- assert_raises(TypeError, np.datetime64, '1920-03-13T18:33Z', 'W')
- assert_raises(TypeError, np.datetime64, '1920-03-13T18:33:12Z', 'M')
- assert_raises(TypeError, np.datetime64, '1920-03-13T18:33:12.5Z', 'Y')
- assert_raises(TypeError, np.datetime64,
- datetime.datetime(1920, 4, 14, 13, 20), 'D')
+ # Construction with time units from a date is okay
+ assert_equal(np.datetime64('1920-03-13', 'h'),
+ np.datetime64('1920-03-13T00'))
+ assert_equal(np.datetime64('1920-03', 'm'),
+ np.datetime64('1920-03-01T00:00'))
+ assert_equal(np.datetime64('1920', 's'),
+ np.datetime64('1920-01-01T00:00:00'))
+ assert_equal(np.datetime64(datetime.date(2045, 3, 25), 'ms'),
+ np.datetime64('2045-03-25T00:00:00.000'))
+
+ # Construction with date units from a datetime is also okay
+ assert_equal(np.datetime64('1920-03-13T18', 'D'),
+ np.datetime64('1920-03-13'))
+ assert_equal(np.datetime64('1920-03-13T18:33:12', 'M'),
+ np.datetime64('1920-03'))
+ assert_equal(np.datetime64('1920-03-13T18:33:12.5', 'Y'),
+ np.datetime64('1920'))
+
+ def test_datetime_scalar_construction_timezone(self):
+ # verify that supplying an explicit timezone works, but is deprecated
+ with assert_warns(DeprecationWarning):
+ assert_equal(np.datetime64('2000-01-01T00Z'),
+ np.datetime64('2000-01-01T00'))
+ with assert_warns(DeprecationWarning):
+ assert_equal(np.datetime64('2000-01-01T00-08'),
+ np.datetime64('2000-01-01T08'))
def test_datetime_array_find_type(self):
dt = np.datetime64('1970-01-01', 'M')
@@ -324,57 +337,57 @@ class TestDateTime(TestCase):
np.dtype('M8[D]'))
assert_equal(np.datetime64('2010-03-12T17').dtype,
np.dtype('M8[h]'))
- assert_equal(np.datetime64('2010-03-12T17:15Z').dtype,
+ assert_equal(np.datetime64('2010-03-12T17:15').dtype,
np.dtype('M8[m]'))
- assert_equal(np.datetime64('2010-03-12T17:15:08Z').dtype,
+ assert_equal(np.datetime64('2010-03-12T17:15:08').dtype,
np.dtype('M8[s]'))
- assert_equal(np.datetime64('2010-03-12T17:15:08.1Z').dtype,
+ assert_equal(np.datetime64('2010-03-12T17:15:08.1').dtype,
np.dtype('M8[ms]'))
- assert_equal(np.datetime64('2010-03-12T17:15:08.12Z').dtype,
+ assert_equal(np.datetime64('2010-03-12T17:15:08.12').dtype,
np.dtype('M8[ms]'))
- assert_equal(np.datetime64('2010-03-12T17:15:08.123Z').dtype,
+ assert_equal(np.datetime64('2010-03-12T17:15:08.123').dtype,
np.dtype('M8[ms]'))
- assert_equal(np.datetime64('2010-03-12T17:15:08.1234Z').dtype,
+ assert_equal(np.datetime64('2010-03-12T17:15:08.1234').dtype,
np.dtype('M8[us]'))
- assert_equal(np.datetime64('2010-03-12T17:15:08.12345Z').dtype,
+ assert_equal(np.datetime64('2010-03-12T17:15:08.12345').dtype,
np.dtype('M8[us]'))
- assert_equal(np.datetime64('2010-03-12T17:15:08.123456Z').dtype,
+ assert_equal(np.datetime64('2010-03-12T17:15:08.123456').dtype,
np.dtype('M8[us]'))
- assert_equal(np.datetime64('1970-01-01T00:00:02.1234567Z').dtype,
+ assert_equal(np.datetime64('1970-01-01T00:00:02.1234567').dtype,
np.dtype('M8[ns]'))
- assert_equal(np.datetime64('1970-01-01T00:00:02.12345678Z').dtype,
+ assert_equal(np.datetime64('1970-01-01T00:00:02.12345678').dtype,
np.dtype('M8[ns]'))
- assert_equal(np.datetime64('1970-01-01T00:00:02.123456789Z').dtype,
+ assert_equal(np.datetime64('1970-01-01T00:00:02.123456789').dtype,
np.dtype('M8[ns]'))
- assert_equal(np.datetime64('1970-01-01T00:00:02.1234567890Z').dtype,
+ assert_equal(np.datetime64('1970-01-01T00:00:02.1234567890').dtype,
np.dtype('M8[ps]'))
- assert_equal(np.datetime64('1970-01-01T00:00:02.12345678901Z').dtype,
+ assert_equal(np.datetime64('1970-01-01T00:00:02.12345678901').dtype,
np.dtype('M8[ps]'))
- assert_equal(np.datetime64('1970-01-01T00:00:02.123456789012Z').dtype,
+ assert_equal(np.datetime64('1970-01-01T00:00:02.123456789012').dtype,
np.dtype('M8[ps]'))
assert_equal(np.datetime64(
- '1970-01-01T00:00:02.1234567890123Z').dtype,
+ '1970-01-01T00:00:02.1234567890123').dtype,
np.dtype('M8[fs]'))
assert_equal(np.datetime64(
- '1970-01-01T00:00:02.12345678901234Z').dtype,
+ '1970-01-01T00:00:02.12345678901234').dtype,
np.dtype('M8[fs]'))
assert_equal(np.datetime64(
- '1970-01-01T00:00:02.123456789012345Z').dtype,
+ '1970-01-01T00:00:02.123456789012345').dtype,
np.dtype('M8[fs]'))
assert_equal(np.datetime64(
- '1970-01-01T00:00:02.1234567890123456Z').dtype,
+ '1970-01-01T00:00:02.1234567890123456').dtype,
np.dtype('M8[as]'))
assert_equal(np.datetime64(
- '1970-01-01T00:00:02.12345678901234567Z').dtype,
+ '1970-01-01T00:00:02.12345678901234567').dtype,
np.dtype('M8[as]'))
assert_equal(np.datetime64(
- '1970-01-01T00:00:02.123456789012345678Z').dtype,
+ '1970-01-01T00:00:02.123456789012345678').dtype,
np.dtype('M8[as]'))
# Python date object
@@ -390,18 +403,10 @@ class TestDateTime(TestCase):
assert_equal(np.datetime64('today').dtype,
np.dtype('M8[D]'))
- assert_raises(TypeError, np.datetime64, 'today', 'h')
- assert_raises(TypeError, np.datetime64, 'today', 's')
- assert_raises(TypeError, np.datetime64, 'today', 'as')
-
# 'now' special value
assert_equal(np.datetime64('now').dtype,
np.dtype('M8[s]'))
- assert_raises(TypeError, np.datetime64, 'now', 'Y')
- assert_raises(TypeError, np.datetime64, 'now', 'M')
- assert_raises(TypeError, np.datetime64, 'now', 'D')
-
def test_datetime_nat_casting(self):
a = np.array('NaT', dtype='M8[D]')
b = np.datetime64('NaT', '[D]')
@@ -508,9 +513,9 @@ class TestDateTime(TestCase):
#a = np.array(['now', datetime.datetime.now()], dtype='M8[s]')
#assert_equal(a[0], a[1])
- # A datetime.date will raise if you try to give it time units
- assert_raises(TypeError, np.array, datetime.date(1960, 3, 12),
- dtype='M8[s]')
+ # we can give a datetime.date time units
+ assert_equal(np.array(datetime.date(1960, 3, 12), dtype='M8[s]'),
+ np.array(np.datetime64('1960-03-12T00:00:00')))
def test_datetime_string_conversion(self):
a = ['2011-03-16', '1920-01-01', '2013-05-19']
@@ -547,7 +552,7 @@ class TestDateTime(TestCase):
a = np.array(['2011-03-16', '1920-01-01', '2013-05-19'], dtype='M')
assert_equal(str(a), "['2011-03-16' '1920-01-01' '2013-05-19']")
- a = np.array(['2011-03-16T13:55Z', '1920-01-01T03:12Z'], dtype='M')
+ a = np.array(['2011-03-16T13:55', '1920-01-01T03:12'], dtype='M')
assert_equal(np.array2string(a, separator=', ',
formatter={'datetime': lambda x:
"'%s'" % np.datetime_as_string(x, timezone='UTC')}),
@@ -667,14 +672,14 @@ class TestDateTime(TestCase):
for unit in ['M8[as]', 'M8[16fs]', 'M8[ps]', 'M8[us]',
'M8[300as]', 'M8[20us]']:
b = a.copy().view(dtype=unit)
- b[0] = '-0001-01-01T00Z'
- b[1] = '-0001-12-31T00Z'
- b[2] = '0000-01-01T00Z'
- b[3] = '0001-01-01T00Z'
- b[4] = '1969-12-31T23:59:59.999999Z'
- b[5] = '1970-01-01T00Z'
- b[6] = '9999-12-31T23:59:59.999999Z'
- b[7] = '10000-01-01T00Z'
+ b[0] = '-0001-01-01T00'
+ b[1] = '-0001-12-31T00'
+ b[2] = '0000-01-01T00'
+ b[3] = '0001-01-01T00'
+ b[4] = '1969-12-31T23:59:59.999999'
+ b[5] = '1970-01-01T00'
+ b[6] = '9999-12-31T23:59:59.999999'
+ b[7] = '10000-01-01T00'
b[8] = 'NaT'
assert_equal(b.astype(object).astype(unit), b,
@@ -685,13 +690,13 @@ class TestDateTime(TestCase):
assert_equal(np.array('1945-03-01', dtype='M8[M]'),
np.array('1945-03-31', dtype='M8[M]'))
assert_equal(np.array('1969-11-01', dtype='M8[M]'),
- np.array('1969-11-30T23:59:59.99999Z', dtype='M').astype('M8[M]'))
+ np.array('1969-11-30T23:59:59.99999', dtype='M').astype('M8[M]'))
assert_equal(np.array('1969-12-01', dtype='M8[M]'),
- np.array('1969-12-31T23:59:59.99999Z', dtype='M').astype('M8[M]'))
+ np.array('1969-12-31T23:59:59.99999', dtype='M').astype('M8[M]'))
assert_equal(np.array('1970-01-01', dtype='M8[M]'),
- np.array('1970-01-31T23:59:59.99999Z', dtype='M').astype('M8[M]'))
+ np.array('1970-01-31T23:59:59.99999', dtype='M').astype('M8[M]'))
assert_equal(np.array('1980-02-01', dtype='M8[M]'),
- np.array('1980-02-29T23:59:59.99999Z', dtype='M').astype('M8[M]'))
+ np.array('1980-02-29T23:59:59.99999', dtype='M').astype('M8[M]'))
def test_different_unit_comparison(self):
# Check some years with date units
@@ -720,32 +725,32 @@ class TestDateTime(TestCase):
dt1 = np.dtype('M8[%s]' % unit1)
for unit2 in ['h', 'm', 's', 'ms', 'us']:
dt2 = np.dtype('M8[%s]' % unit2)
- assert_equal(np.array('1945-03-12T18Z', dtype=dt1),
- np.array('1945-03-12T18Z', dtype=dt2))
- assert_equal(np.array('1970-03-12T18Z', dtype=dt1),
- np.array('1970-03-12T18Z', dtype=dt2))
- assert_equal(np.array('9999-03-12T18Z', dtype=dt1),
- np.array('9999-03-12T18Z', dtype=dt2))
- assert_equal(np.array('10000-01-01T00Z', dtype=dt1),
- np.array('10000-01-01T00Z', dtype=dt2))
- assert_equal(np.datetime64('1945-03-12T18Z', unit1),
- np.datetime64('1945-03-12T18Z', unit2))
- assert_equal(np.datetime64('1970-03-12T18Z', unit1),
- np.datetime64('1970-03-12T18Z', unit2))
- assert_equal(np.datetime64('9999-03-12T18Z', unit1),
- np.datetime64('9999-03-12T18Z', unit2))
- assert_equal(np.datetime64('10000-01-01T00Z', unit1),
- np.datetime64('10000-01-01T00Z', unit2))
+ assert_equal(np.array('1945-03-12T18', dtype=dt1),
+ np.array('1945-03-12T18', dtype=dt2))
+ assert_equal(np.array('1970-03-12T18', dtype=dt1),
+ np.array('1970-03-12T18', dtype=dt2))
+ assert_equal(np.array('9999-03-12T18', dtype=dt1),
+ np.array('9999-03-12T18', dtype=dt2))
+ assert_equal(np.array('10000-01-01T00', dtype=dt1),
+ np.array('10000-01-01T00', dtype=dt2))
+ assert_equal(np.datetime64('1945-03-12T18', unit1),
+ np.datetime64('1945-03-12T18', unit2))
+ assert_equal(np.datetime64('1970-03-12T18', unit1),
+ np.datetime64('1970-03-12T18', unit2))
+ assert_equal(np.datetime64('9999-03-12T18', unit1),
+ np.datetime64('9999-03-12T18', unit2))
+ assert_equal(np.datetime64('10000-01-01T00', unit1),
+ np.datetime64('10000-01-01T00', unit2))
# Check some days with units that won't overflow
for unit1 in ['D', '12h', 'h', 'm', 's', '4s', 'ms', 'us']:
dt1 = np.dtype('M8[%s]' % unit1)
for unit2 in ['D', 'h', 'm', 's', 'ms', 'us']:
dt2 = np.dtype('M8[%s]' % unit2)
assert_(np.equal(np.array('1932-02-17', dtype='M').astype(dt1),
- np.array('1932-02-17T00:00:00Z', dtype='M').astype(dt2),
+ np.array('1932-02-17T00:00:00', dtype='M').astype(dt2),
casting='unsafe'))
assert_(np.equal(np.array('10000-04-27', dtype='M').astype(dt1),
- np.array('10000-04-27T00:00:00Z', dtype='M').astype(dt2),
+ np.array('10000-04-27T00:00:00', dtype='M').astype(dt2),
casting='unsafe'))
# Shouldn't be able to compare datetime and timedelta
@@ -807,7 +812,7 @@ class TestDateTime(TestCase):
# One-dimensional arrays
(np.array(['2012-12-21'], dtype='M8[D]'),
np.array(['2012-12-24'], dtype='M8[D]'),
- np.array(['2012-12-21T11Z'], dtype='M8[h]'),
+ np.array(['2012-12-21T11'], dtype='M8[h]'),
np.array(['NaT'], dtype='M8[D]'),
np.array([3], dtype='m8[D]'),
np.array([11], dtype='m8[h]'),
@@ -815,7 +820,7 @@ class TestDateTime(TestCase):
# NumPy scalars
(np.datetime64('2012-12-21', '[D]'),
np.datetime64('2012-12-24', '[D]'),
- np.datetime64('2012-12-21T11Z', '[h]'),
+ np.datetime64('2012-12-21T11', '[h]'),
np.datetime64('NaT', '[D]'),
np.timedelta64(3, '[D]'),
np.timedelta64(11, '[h]'),
@@ -878,8 +883,8 @@ class TestDateTime(TestCase):
(np.array(['2012-12-21'], dtype='M8[D]'),
np.array(['2012-12-24'], dtype='M8[D]'),
np.array(['1940-12-24'], dtype='M8[D]'),
- np.array(['1940-12-24T00Z'], dtype='M8[h]'),
- np.array(['1940-12-23T13Z'], dtype='M8[h]'),
+ np.array(['1940-12-24T00'], dtype='M8[h]'),
+ np.array(['1940-12-23T13'], dtype='M8[h]'),
np.array(['NaT'], dtype='M8[D]'),
np.array([3], dtype='m8[D]'),
np.array([11], dtype='m8[h]'),
@@ -888,8 +893,8 @@ class TestDateTime(TestCase):
(np.datetime64('2012-12-21', '[D]'),
np.datetime64('2012-12-24', '[D]'),
np.datetime64('1940-12-24', '[D]'),
- np.datetime64('1940-12-24T00Z', '[h]'),
- np.datetime64('1940-12-23T13Z', '[h]'),
+ np.datetime64('1940-12-24T00', '[h]'),
+ np.datetime64('1940-12-23T13', '[h]'),
np.datetime64('NaT', '[D]'),
np.timedelta64(3, '[D]'),
np.timedelta64(11, '[h]'),
@@ -1071,12 +1076,12 @@ class TestDateTime(TestCase):
def test_datetime_compare(self):
# Test all the comparison operators
- a = np.datetime64('2000-03-12T18:00:00.000000-0600')
- b = np.array(['2000-03-12T18:00:00.000000-0600',
- '2000-03-12T17:59:59.999999-0600',
- '2000-03-12T18:00:00.000001-0600',
- '1970-01-11T12:00:00.909090-0600',
- '2016-01-11T12:00:00.909090-0600'],
+ a = np.datetime64('2000-03-12T18:00:00.000000')
+ b = np.array(['2000-03-12T18:00:00.000000',
+ '2000-03-12T17:59:59.999999',
+ '2000-03-12T18:00:00.000001',
+ '1970-01-11T12:00:00.909090',
+ '2016-01-11T12:00:00.909090'],
dtype='datetime64[us]')
assert_equal(np.equal(a, b), [1, 0, 0, 0, 0])
assert_equal(np.not_equal(a, b), [0, 1, 1, 1, 1])
@@ -1108,8 +1113,8 @@ class TestDateTime(TestCase):
def test_datetime_minmax(self):
# The metadata of the result should become the GCD
# of the operand metadata
- a = np.array('1999-03-12T13Z', dtype='M8[2m]')
- b = np.array('1999-03-12T12Z', dtype='M8[s]')
+ a = np.array('1999-03-12T13', dtype='M8[2m]')
+ b = np.array('1999-03-12T12', dtype='M8[s]')
assert_equal(np.minimum(a, b), b)
assert_equal(np.minimum(a, b).dtype, np.dtype('M8[s]'))
assert_equal(np.fmin(a, b), b)
@@ -1123,7 +1128,7 @@ class TestDateTime(TestCase):
assert_equal(np.minimum(a.view('i8'), b.view('i8')), a.view('i8'))
# Interaction with NaT
- a = np.array('1999-03-12T13Z', dtype='M8[2m]')
+ a = np.array('1999-03-12T13', dtype='M8[2m]')
dtnat = np.array('NaT', dtype='M8[h]')
assert_equal(np.minimum(a, dtnat), a)
assert_equal(np.minimum(dtnat, a), a)
@@ -1150,7 +1155,7 @@ class TestDateTime(TestCase):
# TODO: Allowing unsafe casting by
# default in ufuncs strikes again... :(
a = np.array(3, dtype='m8[h]')
- b = np.array('1999-03-12T12Z', dtype='M8[s]')
+ b = np.array('1999-03-12T12', dtype='M8[s]')
#assert_raises(TypeError, np.minimum, a, b)
#assert_raises(TypeError, np.maximum, a, b)
#assert_raises(TypeError, np.fmin, a, b)
@@ -1212,17 +1217,26 @@ class TestDateTime(TestCase):
assert_equal(np.array(['-1980-02-29T01:02:03'], np.dtype('M8[s]')),
np.array(['-1980-02-29 01:02:03'], np.dtype('M8[s]')))
# UTC specifier
- assert_equal(np.array(['-1980-02-29T01:02:03Z'], np.dtype('M8[s]')),
- np.array(['-1980-02-29 01:02:03Z'], np.dtype('M8[s]')))
+ with assert_warns(DeprecationWarning):
+ assert_equal(
+ np.array(['-1980-02-29T01:02:03'], np.dtype('M8[s]')),
+ np.array(['-1980-02-29 01:02:03Z'], np.dtype('M8[s]')))
# Time zone offset
- assert_equal(np.array(['1980-02-29T02:02:03Z'], np.dtype('M8[s]')),
- np.array(['1980-02-29 00:32:03-0130'], np.dtype('M8[s]')))
- assert_equal(np.array(['1980-02-28T22:32:03Z'], np.dtype('M8[s]')),
- np.array(['1980-02-29 00:02:03+01:30'], np.dtype('M8[s]')))
- assert_equal(np.array(['1980-02-29T02:32:03.506Z'], np.dtype('M8[s]')),
- np.array(['1980-02-29 00:32:03.506-02'], np.dtype('M8[s]')))
- assert_equal(np.datetime64('1977-03-02T12:30-0230'),
- np.datetime64('1977-03-02T15:00Z'))
+ with assert_warns(DeprecationWarning):
+ assert_equal(
+ np.array(['1980-02-29T02:02:03'], np.dtype('M8[s]')),
+ np.array(['1980-02-29 00:32:03-0130'], np.dtype('M8[s]')))
+ with assert_warns(DeprecationWarning):
+ assert_equal(
+ np.array(['1980-02-28T22:32:03'], np.dtype('M8[s]')),
+ np.array(['1980-02-29 00:02:03+01:30'], np.dtype('M8[s]')))
+ with assert_warns(DeprecationWarning):
+ assert_equal(
+ np.array(['1980-02-29T02:32:03.506'], np.dtype('M8[s]')),
+ np.array(['1980-02-29 00:32:03.506-02'], np.dtype('M8[s]')))
+ with assert_warns(DeprecationWarning):
+ assert_equal(np.datetime64('1977-03-02T12:30-0230'),
+ np.datetime64('1977-03-02T15:00'))
def test_string_parser_error_check(self):
# Arbitrary bad string
@@ -1291,19 +1305,24 @@ class TestDateTime(TestCase):
assert_raises(ValueError, np.array, ['1980-02-03 01:01:60'],
np.dtype('M8[us]'))
# Timezone offset must within a reasonable range
- assert_raises(ValueError, np.array, ['1980-02-03 01:01:00+0661'],
- np.dtype('M8[us]'))
- assert_raises(ValueError, np.array, ['1980-02-03 01:01:00+2500'],
- np.dtype('M8[us]'))
- assert_raises(ValueError, np.array, ['1980-02-03 01:01:00-0070'],
- np.dtype('M8[us]'))
- assert_raises(ValueError, np.array, ['1980-02-03 01:01:00-3000'],
- np.dtype('M8[us]'))
- assert_raises(ValueError, np.array, ['1980-02-03 01:01:00-25:00'],
- np.dtype('M8[us]'))
+ with assert_warns(DeprecationWarning):
+ assert_raises(ValueError, np.array, ['1980-02-03 01:01:00+0661'],
+ np.dtype('M8[us]'))
+ with assert_warns(DeprecationWarning):
+ assert_raises(ValueError, np.array, ['1980-02-03 01:01:00+2500'],
+ np.dtype('M8[us]'))
+ with assert_warns(DeprecationWarning):
+ assert_raises(ValueError, np.array, ['1980-02-03 01:01:00-0070'],
+ np.dtype('M8[us]'))
+ with assert_warns(DeprecationWarning):
+ assert_raises(ValueError, np.array, ['1980-02-03 01:01:00-3000'],
+ np.dtype('M8[us]'))
+ with assert_warns(DeprecationWarning):
+ assert_raises(ValueError, np.array, ['1980-02-03 01:01:00-25:00'],
+ np.dtype('M8[us]'))
def test_creation_overflow(self):
- date = '1980-03-23 20:00:00Z'
+ date = '1980-03-23 20:00:00'
timesteps = np.array([date], dtype='datetime64[s]')[0].astype(np.int64)
for unit in ['ms', 'us', 'ns']:
timesteps *= 1000
@@ -1317,7 +1336,7 @@ class TestDateTime(TestCase):
def test_datetime_as_string(self):
# Check all the units with default string conversion
date = '1959-10-13'
- datetime = '1959-10-13T12:34:56.789012345678901234Z'
+ datetime = '1959-10-13T12:34:56.789012345678901234'
assert_equal(np.datetime_as_string(np.datetime64(date, 'Y')),
'1959')
@@ -1326,45 +1345,45 @@ class TestDateTime(TestCase):
assert_equal(np.datetime_as_string(np.datetime64(date, 'D')),
'1959-10-13')
assert_equal(np.datetime_as_string(np.datetime64(datetime, 'h')),
- '1959-10-13T12Z')
+ '1959-10-13T12')
assert_equal(np.datetime_as_string(np.datetime64(datetime, 'm')),
- '1959-10-13T12:34Z')
+ '1959-10-13T12:34')
assert_equal(np.datetime_as_string(np.datetime64(datetime, 's')),
- '1959-10-13T12:34:56Z')
+ '1959-10-13T12:34:56')
assert_equal(np.datetime_as_string(np.datetime64(datetime, 'ms')),
- '1959-10-13T12:34:56.789Z')
+ '1959-10-13T12:34:56.789')
assert_equal(np.datetime_as_string(np.datetime64(datetime, 'us')),
- '1959-10-13T12:34:56.789012Z')
+ '1959-10-13T12:34:56.789012')
- datetime = '1969-12-31T23:34:56.789012345678901234Z'
+ datetime = '1969-12-31T23:34:56.789012345678901234'
assert_equal(np.datetime_as_string(np.datetime64(datetime, 'ns')),
- '1969-12-31T23:34:56.789012345Z')
+ '1969-12-31T23:34:56.789012345')
assert_equal(np.datetime_as_string(np.datetime64(datetime, 'ps')),
- '1969-12-31T23:34:56.789012345678Z')
+ '1969-12-31T23:34:56.789012345678')
assert_equal(np.datetime_as_string(np.datetime64(datetime, 'fs')),
- '1969-12-31T23:34:56.789012345678901Z')
+ '1969-12-31T23:34:56.789012345678901')
- datetime = '1969-12-31T23:59:57.789012345678901234Z'
+ datetime = '1969-12-31T23:59:57.789012345678901234'
assert_equal(np.datetime_as_string(np.datetime64(datetime, 'as')),
datetime)
- datetime = '1970-01-01T00:34:56.789012345678901234Z'
+ datetime = '1970-01-01T00:34:56.789012345678901234'
assert_equal(np.datetime_as_string(np.datetime64(datetime, 'ns')),
- '1970-01-01T00:34:56.789012345Z')
+ '1970-01-01T00:34:56.789012345')
assert_equal(np.datetime_as_string(np.datetime64(datetime, 'ps')),
- '1970-01-01T00:34:56.789012345678Z')
+ '1970-01-01T00:34:56.789012345678')
assert_equal(np.datetime_as_string(np.datetime64(datetime, 'fs')),
- '1970-01-01T00:34:56.789012345678901Z')
+ '1970-01-01T00:34:56.789012345678901')
- datetime = '1970-01-01T00:00:05.789012345678901234Z'
+ datetime = '1970-01-01T00:00:05.789012345678901234'
assert_equal(np.datetime_as_string(np.datetime64(datetime, 'as')),
datetime)
# String conversion with the unit= parameter
- a = np.datetime64('2032-07-18T12:23:34.123456Z', 'us')
+ a = np.datetime64('2032-07-18T12:23:34.123456', 'us')
assert_equal(np.datetime_as_string(a, unit='Y', casting='unsafe'),
'2032')
assert_equal(np.datetime_as_string(a, unit='M', casting='unsafe'),
@@ -1373,62 +1392,66 @@ class TestDateTime(TestCase):
'2032-07-18')
assert_equal(np.datetime_as_string(a, unit='D', casting='unsafe'),
'2032-07-18')
- assert_equal(np.datetime_as_string(a, unit='h'), '2032-07-18T12Z')
+ assert_equal(np.datetime_as_string(a, unit='h'), '2032-07-18T12')
assert_equal(np.datetime_as_string(a, unit='m'),
- '2032-07-18T12:23Z')
+ '2032-07-18T12:23')
assert_equal(np.datetime_as_string(a, unit='s'),
- '2032-07-18T12:23:34Z')
+ '2032-07-18T12:23:34')
assert_equal(np.datetime_as_string(a, unit='ms'),
- '2032-07-18T12:23:34.123Z')
+ '2032-07-18T12:23:34.123')
assert_equal(np.datetime_as_string(a, unit='us'),
- '2032-07-18T12:23:34.123456Z')
+ '2032-07-18T12:23:34.123456')
assert_equal(np.datetime_as_string(a, unit='ns'),
- '2032-07-18T12:23:34.123456000Z')
+ '2032-07-18T12:23:34.123456000')
assert_equal(np.datetime_as_string(a, unit='ps'),
- '2032-07-18T12:23:34.123456000000Z')
+ '2032-07-18T12:23:34.123456000000')
assert_equal(np.datetime_as_string(a, unit='fs'),
- '2032-07-18T12:23:34.123456000000000Z')
+ '2032-07-18T12:23:34.123456000000000')
assert_equal(np.datetime_as_string(a, unit='as'),
- '2032-07-18T12:23:34.123456000000000000Z')
+ '2032-07-18T12:23:34.123456000000000000')
# unit='auto' parameter
assert_equal(np.datetime_as_string(
- np.datetime64('2032-07-18T12:23:34.123456Z', 'us'), unit='auto'),
- '2032-07-18T12:23:34.123456Z')
+ np.datetime64('2032-07-18T12:23:34.123456', 'us'), unit='auto'),
+ '2032-07-18T12:23:34.123456')
assert_equal(np.datetime_as_string(
- np.datetime64('2032-07-18T12:23:34.12Z', 'us'), unit='auto'),
- '2032-07-18T12:23:34.120Z')
+ np.datetime64('2032-07-18T12:23:34.12', 'us'), unit='auto'),
+ '2032-07-18T12:23:34.120')
assert_equal(np.datetime_as_string(
- np.datetime64('2032-07-18T12:23:34Z', 'us'), unit='auto'),
- '2032-07-18T12:23:34Z')
+ np.datetime64('2032-07-18T12:23:34', 'us'), unit='auto'),
+ '2032-07-18T12:23:34')
assert_equal(np.datetime_as_string(
- np.datetime64('2032-07-18T12:23:00Z', 'us'), unit='auto'),
- '2032-07-18T12:23Z')
+ np.datetime64('2032-07-18T12:23:00', 'us'), unit='auto'),
+ '2032-07-18T12:23')
# 'auto' doesn't split up hour and minute
assert_equal(np.datetime_as_string(
- np.datetime64('2032-07-18T12:00:00Z', 'us'), unit='auto'),
- '2032-07-18T12:00Z')
+ np.datetime64('2032-07-18T12:00:00', 'us'), unit='auto'),
+ '2032-07-18T12:00')
assert_equal(np.datetime_as_string(
- np.datetime64('2032-07-18T00:00:00Z', 'us'), unit='auto'),
+ np.datetime64('2032-07-18T00:00:00', 'us'), unit='auto'),
'2032-07-18')
# 'auto' doesn't split up the date
assert_equal(np.datetime_as_string(
- np.datetime64('2032-07-01T00:00:00Z', 'us'), unit='auto'),
+ np.datetime64('2032-07-01T00:00:00', 'us'), unit='auto'),
'2032-07-01')
assert_equal(np.datetime_as_string(
- np.datetime64('2032-01-01T00:00:00Z', 'us'), unit='auto'),
+ np.datetime64('2032-01-01T00:00:00', 'us'), unit='auto'),
'2032-01-01')
@dec.skipif(not _has_pytz, "The pytz module is not available.")
def test_datetime_as_string_timezone(self):
# timezone='local' vs 'UTC'
- a = np.datetime64('2010-03-15T06:30Z', 'm')
+ a = np.datetime64('2010-03-15T06:30', 'm')
+ assert_equal(np.datetime_as_string(a),
+ '2010-03-15T06:30')
+ assert_equal(np.datetime_as_string(a, timezone='naive'),
+ '2010-03-15T06:30')
assert_equal(np.datetime_as_string(a, timezone='UTC'),
'2010-03-15T06:30Z')
assert_(np.datetime_as_string(a, timezone='local') !=
- '2010-03-15T06:30Z')
+ '2010-03-15T06:30')
- b = np.datetime64('2010-02-15T06:30Z', 'm')
+ b = np.datetime64('2010-02-15T06:30', 'm')
assert_equal(np.datetime_as_string(a, timezone=tz('US/Central')),
'2010-03-15T01:30-0500')
@@ -1493,7 +1516,7 @@ class TestDateTime(TestCase):
assert_raises(TypeError, np.arange, np.datetime64('2011-03-01', 'D'),
np.timedelta64(5, 'M'))
assert_raises(TypeError, np.arange,
- np.datetime64('2012-02-03T14Z', 's'),
+ np.datetime64('2012-02-03T14', 's'),
np.timedelta64(5, 'Y'))
def test_datetime_arange_no_dtype(self):
@@ -1845,21 +1868,23 @@ class TestDateTime(TestCase):
def test_datetime_y2038(self):
# Test parsing on either side of the Y2038 boundary
- a = np.datetime64('2038-01-19T03:14:07Z')
+ a = np.datetime64('2038-01-19T03:14:07')
assert_equal(a.view(np.int64), 2**31 - 1)
- a = np.datetime64('2038-01-19T03:14:08Z')
+ a = np.datetime64('2038-01-19T03:14:08')
assert_equal(a.view(np.int64), 2**31)
# Test parsing on either side of the Y2038 boundary with
# a manually specified timezone offset
- a = np.datetime64('2038-01-19T04:14:07+0100')
- assert_equal(a.view(np.int64), 2**31 - 1)
- a = np.datetime64('2038-01-19T04:14:08+0100')
- assert_equal(a.view(np.int64), 2**31)
-
- # Test parsing a date after Y2038 in the local timezone
+ with assert_warns(DeprecationWarning):
+ a = np.datetime64('2038-01-19T04:14:07+0100')
+ assert_equal(a.view(np.int64), 2**31 - 1)
+ with assert_warns(DeprecationWarning):
+ a = np.datetime64('2038-01-19T04:14:08+0100')
+ assert_equal(a.view(np.int64), 2**31)
+
+ # Test parsing a date after Y2038
a = np.datetime64('2038-01-20T13:21:14')
- assert_equal(str(a)[:-5], '2038-01-20T13:21:14')
+ assert_equal(str(a), '2038-01-20T13:21:14')
class TestDateTimeData(TestCase):
diff --git a/numpy/core/tests/test_deprecations.py b/numpy/core/tests/test_deprecations.py
index 65ddc1e77..f0998901d 100644
--- a/numpy/core/tests/test_deprecations.py
+++ b/numpy/core/tests/test_deprecations.py
@@ -5,6 +5,7 @@ to document how deprecations should eventually be turned into errors.
"""
from __future__ import division, absolute_import, print_function
+import datetime
import sys
import operator
import warnings
@@ -12,7 +13,13 @@ import warnings
import numpy as np
from numpy.testing import (
run_module_suite, assert_raises, assert_warns, assert_no_warnings,
- assert_array_equal, assert_)
+ assert_array_equal, assert_, dec)
+
+try:
+ import pytz
+ _has_pytz = True
+except ImportError:
+ _has_pytz = False
class _DeprecationTestCase(object):
@@ -386,6 +393,26 @@ class TestFullDefaultDtype(object):
assert_no_warnings(np.full, 1, 1, float)
+class TestDatetime64Timezone(_DeprecationTestCase):
+ """Parsing of datetime64 with timezones deprecated in 1.11.0, because
+ datetime64 is now timezone naive rather than UTC only.
+
+ It will be quite a while before we can remove this, because, at the very
+ least, a lot of existing code uses the 'Z' modifier to avoid conversion
+ from local time to UTC, even if otherwise it handles time in a timezone
+ naive fashion.
+ """
+ def test_string(self):
+ self.assert_deprecated(np.datetime64, args=('2000-01-01T00+01',))
+ self.assert_deprecated(np.datetime64, args=('2000-01-01T00Z',))
+
+ @dec.skipif(not _has_pytz, "The pytz module is not available.")
+ def test_datetime(self):
+ tz = pytz.timezone('US/Eastern')
+ dt = datetime.datetime(2000, 1, 1, 0, 0, tzinfo=tz)
+ self.assert_deprecated(np.datetime64, args=(dt,))
+
+
class TestNonCContiguousViewDeprecation(_DeprecationTestCase):
"""View of non-C-contiguous arrays deprecated in 1.11.0.