Repository: numpy/numpy

Issue:
Timezones and Datetime64
A new version of datetime64 dtype was added to numpy recently, and as of 1.7, is considered experimental.

As of 1.7, datetime64 attempts to handle timezones by:
- Assuming all datetime64 objects are in UTC
- Applying timezone offsets when parsing ISO 8601 strings
- Applying the Locale timezone offset when the ISO string does not specify a TZ.
- Applying the Locale timezone offset when printing, etc.

(note that no timezone handling is done when converting to/from the stdlib datetime object)

However, this behavior makes it very difficult to use datetime64 in a timezone agnostic way, or if you need to work with a timezone that is not the system Locale one.

Complete and proper timezone management could be a very useful, but the current system is only useful in a few small cases, and makes common use cases very difficult. Good timezone handling is a large and difficult problem -- it is unclear whether numpy wants to take it on.

There has been much discussion on the numpy mailing list, and a new datetime64 NEP is progress, but in the meantime, I propose we make the following changes to make datetime64 far more useful and less prone to error:
- Assume that datetime64 is timezone "naive", as the standard library datetime object does -- it is up to the user to do any time zone offset conversions.
- Do not apply a timezone offset when converting to an ISO string
- Never use the Locale settings for anything, without the user explicitly asking for it.
- raise an exception when parsing an ISO 8601 string that has a timezone offset other than 0 (Z)



Discussion:
If we're naive, shouldn't we also refuse to process a timezone offset of 0,
and only accept ISO 8601 strings that leave the offset unspecified?

"Naive" and "UTC" are different timezones... note that these return
different values:
  dateutil.parser.parse("2010-01-01T00:00:00")
  dateutil.parser.parse("2010-01-01T00:00:00Z")

On Mon, Apr 29, 2013 at 5:54 PM, Christopher H.Barker, PhD <
notifications@github.com> wrote:

> A new version of datetime64 dtype was added to numpy recently, and as of
> 1.7, is considered experimental.
> 
> As of 1.7, datetime64 attempts to handle timezones by:
> - Assuming all datetime64 objects are in UTC
> - Applying timezone offsets when parsing ISO 8601 strings
> - Applying the Locale timezone offset when the ISO string does not
>   specify a TZ.
> - Applying the Locale timezone offset when printing, etc.
> 
> (note that no timezone handling is done when converting to/from the stdlib
> datetime object)
> 
> However, this behavior makes it very difficult to use datetime64 in a
> timezone agnostic way, or if you need to work with a timezone that is not
> the system Locale one.
> 
> Complete and proper timezone management could be a very useful, but the
> current system is only useful in a few small cases, and makes common use
> cases very difficult. Good timezone handling is a large and difficult
> problem -- it is unclear whether numpy wants to take it on.
> 
> There has been much discussion on the numpy mailing list, and a new
> datetime64 NEP is progress, but in the meantime, I propose we make the
> following changes to make datetime64 far more useful and less prone to
> error:
> - Assume that datetime64 is timezone "naive", as the standard library
>   datetime object does -- it is up to the user to do any time zone offset
>   conversions.
> - Do not apply a timezone offset when converting to an ISO string
> - Never use the Locale settings for anything, without the user
>   explicitly asking for it.
> - raise an exception when parsing an ISO 8601 string that has a
>   timezone offset other than 0 (Z)
> 
> —
> Reply to this email directly or view it on GitHubhttps://github.com/numpy/numpy/issues/3290
> .

Well, dateutil returns a time-zone aware datetime object when you give it a time zone -- so it CAN return different values with and without a TZ offset.

I just figured it wouldn't change the value, so why not. But sure, perhaps it would be less likely to cause errors later on to not except ANY timezone offset in a ISO string.

I mean that it is a different value precisely in the sense that time-zone
aware datetimes and time-zone naive datetime objects are very different,
incommensurate things, even if they have some of the same numbers stashed
in them:

In [6]: dateutil.parser.parse("2010-01-01T00:00:00")
Out[6]: datetime.datetime(2010, 1, 1, 0, 0)

In [7]: dateutil.parser.parse("2010-01-01T00:00:00Z")
Out[7]: datetime.datetime(2010, 1, 1, 0, 0, tzinfo=tzutc())

In [8]: dateutil.parser.parse("2010-01-01T00:00:00") -
dateutil.parser.parse("2010-01-01T00:00:00Z")
TypeError: can't subtract offset-naive and offset-aware datetimes

Saying "oh well they're not _that_ different it might be convenient and who
will really notice anyway" is exactly the kind of hand-wavy reasoning that
got us into this mess :-).

On Tue, Apr 30, 2013 at 12:33 AM, Christopher H.Barker, PhD <
notifications@github.com> wrote:

> Well, dateutil returns a time-zone aware datetime object when you give it
> a time zone -- so it CAN return different values with and without a TZ
> offset.
> 
> I just figured it wouldn't change the value, so why not. But sure, perhaps
> it would be less likely to cause errors later on to not except ANY timezone
> offset in a ISO string.
> 
> —
> Reply to this email directly or view it on GitHubhttps://github.com/numpy/numpy/issues/3290#issuecomment-17209152
> .

@wesm: Do you have any opinion on the proposed changes? I'm extremely
reluctant to mess with this stuff further without pandas signing off.

On Tue, Apr 30, 2013 at 8:18 AM, Nathaniel Smith njs@pobox.com wrote:

> I mean that it is a different value precisely in the sense that time-zone
> aware datetimes and time-zone naive datetime objects are very different,
> incommensurate things, even if they have some of the same numbers stashed
> in them:
> 
> In [6]: dateutil.parser.parse("2010-01-01T00:00:00")
> Out[6]: datetime.datetime(2010, 1, 1, 0, 0)
> 
> In [7]: dateutil.parser.parse("2010-01-01T00:00:00Z")
> Out[7]: datetime.datetime(2010, 1, 1, 0, 0, tzinfo=tzutc())
> 
> In [8]: dateutil.parser.parse("2010-01-01T00:00:00") -
> dateutil.parser.parse("2010-01-01T00:00:00Z")
> TypeError: can't subtract offset-naive and offset-aware datetimes
> 
> Saying "oh well they're not _that_ different it might be convenient and
> who will really notice anyway" is exactly the kind of hand-wavy reasoning
> that got us into this mess :-).
> 
> On Tue, Apr 30, 2013 at 12:33 AM, Christopher H.Barker, PhD <
> notifications@github.com> wrote:
> 
> > Well, dateutil returns a time-zone aware datetime object when you give it
> > a time zone -- so it CAN return different values with and without a TZ
> > offset.
> > 
> > I just figured it wouldn't change the value, so why not. But sure,
> > perhaps it would be less likely to cause errors later on to not except ANY
> > timezone offset in a ISO string.
> > 
> > —
> > Reply to this email directly or view it on GitHubhttps://github.com/numpy/numpy/issues/3290#issuecomment-17209152
> > .

@njsmith ,

Yes. Naive and Tz-aware date times are quite different. But doing tz-awareness right is really hard. Even if we can Agree on what we want it to do.  This my proposal to stick with naive. Which, indeed it currently is--the current code simply uses some unfortunate defaults. I'd like to see that change to something far more useful.

If we go with naive, then really the only open question is when to raise errors when parsing ISO strings. If numpy only supports naive date times, then I see little chance of confusion if it accepts a tzoffset of 0 -- but consistancy is good, so no- offset-allowed is good too.

I think that `datetime64` should always be implicitly a UTC timestamp, and can be interpreted as being in some time zone as the user desires. That's the approach we're taking in pandas right now, e.g.:

```
In [2]: stamp = pd.Timestamp('2013-05-03T23:00-0500')

In [3]: stamp
Out[3]: <Timestamp: 2013-05-03 23:00:00-0500 , tz=tzoffset(None, -18000)>

In [4]: stamp.u
stamp.utcfromtimestamp  stamp.utcoffset         
stamp.utcnow            stamp.utctimetuple      

In [4]: stamp.value
Out[4]: 1367640000000000000

In [5]: stamp.tz_convert('utc')
Out[5]: <Timestamp: 2013-05-04 04:00:00+0000 UTC, tz=UTC>

In [6]: stamp.tz_convert('utc').value
Out[6]: 1367640000000000000
```

The `Timestamp` object is simply a user-friendly "box" and subclass of `datetime.datetime` that holds a UTC datetime64 timestamp (in nanoseconds). 

I should also add that unfortunately we had to kind of do everything ourselves in pandas because the NumPy datetime64 stuff has been in flux (I wrote earlier "mess" but that was putting it a bit strongly, sorry). I also disagreed with some of the decisions that Mark made in the API. I think interpreting a timestamp as naive and not localtime is a good idea, I didn't like the "convert this naive string to UTC given local timezone" which is how I recall numpy 1.7 working

@mwiebe Just a heads up to the discussion on the datetime issue.

Panda's proves the point: a naive datetime may not be as useful as a full-featured Tz-aware one but it is very useful, and users can patch their own TZ handling on top of it. Half-baked TZ support is next to useless. I'm using numpy1.7 datetime64, but frankly, I don't know that I'm buying anything over simply using a regular array that I interpret as seconds-since-the-epoc.

Maybe we should borrow Panda's code?

As for Naive vs. UTC -- they are almost exactly the same -- the only difference may be how you handle an ISO string as input: add/subtract the offset, or don't allow an offset. As long as you don't apply the locale offset without the user specifically asking for it, I'm good either way, though I think calling it "UTC" buys very little over naive, but does add a tiny bit of extra room for error.

So: I propose either Naive or UTC--implementer's choice.

-Chris

Wes I am curious about the motivation for allowing pd.to_datetime( ) to apparently select a timezone from the local system when supplied only a long. That is:  

> > > stamp = pd.Timestamp('2013-05-03T23:00')
> > > 
> > > pd.to_datetime( stamp, box = False )
> > >   Timestamp('2013-05-03 23:00:00', tz=None)

versus 

> > > pd.to_datetime( stamp.value, box = False )
> > >      numpy.datetime64('2013-05-03T19:00:00.000000000-0400')

Took me by surprise, but I'm sure you've thought it through. 

This is still under discussion/development for 1.9

On Sat, Feb 22, 2014 at 2:46 PM, Charles Harris notifications@github.comwrote:

> This is still under discussion/development for 1.9
> 
> great -- any kind of timeframe on that? I think we have a little more
> consensus building to to, but really the key blocker is someone that has
> the time and skills to sit down and do the work. It wuold be nice not to
> leave it ot the last minute like right before 1.8...

-Chris

## 

Christopher Barker, PhD

Python Language Consulting
- Teaching
- Scientific Software Development
- Desktop GUI and Web Development
- wxPython, numpy, scipy, Cython

The timeframe is "whenever someone with the time/skills/interest sits down
to do the work". If you can find them and ask them then that'd be great :-).

On Mon, Feb 24, 2014 at 7:08 PM, Christopher H.Barker, PhD <
notifications@github.com> wrote:

> On Sat, Feb 22, 2014 at 2:46 PM, Charles Harris <notifications@github.com
> 
> > wrote:
> > 
> > This is still under discussion/development for 1.9
> > 
> > great -- any kind of timeframe on that? I think we have a little more
> > consensus building to to, but really the key blocker is someone that has
> > the time and skills to sit down and do the work. It wuold be nice not to
> > leave it ot the last minute like right before 1.8...
> 
> -Chris
> 
> ## 
> 
> Christopher Barker, PhD
> 
> Python Language Consulting
> - Teaching
> - Scientific Software Development
> - Desktop GUI and Web Development
> - wxPython, numpy, scipy, Cython
> 
> —
> Reply to this email directly or view it on GitHubhttps://github.com/numpy/numpy/issues/3290#issuecomment-35959526
> .

## 

Nathaniel J. Smith
Postdoctoral researcher - Informatics - University of Edinburgh
http://vorpus.org

> Never use the Locale settings for anything, without the user explicitly asking for it.

Please can this be introduced! Numpy amuses itself by displaying timezone offsets for values which purposefully don't have time-zones - but it makes it look like they do. I happen to travel between time zones quite often (with the machine updating local accordingly) and it would be nice if my program would output the same thing twice rather than trying to be "helpful" in this way.

Also, strongly disagree with

> Naive vs. UTC -- they are almost exactly the same 

A naive datetime is one for which no timezone information is known or desired. It could be for instance you are running a theoretical model with no relation to a real location, so a timezone is meaningless.
 A UTC datetime is one where a timezone has been defined and is desired, and is chosen to match an international convention on the "baseline" time zone. A naive datetime should never, ever be presented with a "timezone offset" or anything like it because that makes no sense, while for a UTC datetime this does make sense.

Its precisely this kind of vagueness that makes dealing with times such a pain, because you end up with data where its never clear if the value you have is in UTC, naive, includes DST, etc - and part of that is because tools (like numpy) don't really help you out and everyone ends up throwing unix timestamps around till no one has a clue what's going on...

On Thu, Mar 12, 2015 at 11:42 AM, mangecoeur notifications@github.com
wrote:

> Never use the Locale settings for anything, without the user explicitly
> asking for it.
> 
> Please can this be introduced!
> 
> Well -- it takes someone to get in and fix the code....
> 
> Numpy amuses itself by displaying timezone offsets for values which
> purposefully don't have time-zones - but it makes it look like they do.
> 
> well, they sort of do -- currently numpy datetimes are ALWAYS UTC, and they
> use the Locale to set a time zone. THis is quite broken, as you know, but
> it's logical.

I happen to travel between time zones quite often (with the machine

> updating local accordingly) and it would be nice if my program would output
> the same thing twice rather than trying to be "helpful" in this way.
> 
> Also, strongly disagree with
> 
> Naive vs. UTC -- they are almost exactly the same
> 
> Fine -- conceptually they are very different. But implementation-wise,
> they are almost exactly the same. As you say:
> 
> A naive datetime should never, ever be presented with a "timezone
> offset" or anything like it because that makes no sense, while for a UTC
> datetime this does make sense.

and that, in fact, the the only difference implementation wise-  naive, you
numpy wouldn't add an TZ offset, UTC, it might. That's it. And a user code
could treat a naive DT as UTC and add the offset itself. That was my poiint.

> Its precisely this kind of vagueness
> 
> It's only vague if numpy doesn't make it clear which is in use- naive or
> UTC. My point was that either is just fine.
> 
> that makes dealing with times such a pain, because you end up with data
> where its never clear if the value you have is in UTC, naive, includes DST,
> etc
> 
> I see it as kind of like text encodings -- you need to know on IO and you
> need to be clear in your data files. It would be nice of the tools took car
> of al that for you, but that is very, very hard to do. So something useful
> is better than nothing.

-CHB

## 

Christopher Barker, PhD

Python Language Consulting
- Teaching
- Scientific Software Development
- Desktop GUI and Web Development
- wxPython, numpy, scipy, Cython

Just FYI, I'm working on implementing this in #6453.


Resolving patch:
diff --git a/numpy/core/arrayprint.py b/numpy/core/arrayprint.py
--- a/numpy/core/arrayprint.py
+++ b/numpy/core/arrayprint.py
@@ -708,9 +708,9 @@ def __call__(self, x):
             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 @@ def __init__(self, x, unit=None,
             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
 


Test patch:
diff --git a/numpy/core/tests/test_datetime.py b/numpy/core/tests/test_datetime.py
--- a/numpy/core/tests/test_datetime.py
+++ b/numpy/core/tests/test_datetime.py
@@ -9,7 +9,7 @@
 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 @@ def test_datetime_casting_rules(self):
         # 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 @@ def test_datetime_scalar_construction(self):
         # 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 @@ def test_datetime_scalar_construction(self):
 
         # 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 @@ def test_datetime_scalar_construction(self):
         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 @@ def test_timedelta_scalar_construction_units(self):
                      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 @@ def test_timedelta_scalar_construction_units(self):
         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 @@ def test_pydatetime_creation(self):
         #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 @@ def test_datetime_array_str(self):
         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 @@ def test_pyobject_roundtrip(self):
         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 @@ def test_month_truncation(self):
         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 @@ def test_different_unit_comparison(self):
             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 @@ def test_datetime_add(self):
                      # 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 @@ def test_datetime_add(self):
                      # 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 @@ def test_datetime_subtract(self):
                      (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 @@ def test_datetime_subtract(self):
                      (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 @@ def test_datetime_divide(self):
 
     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 @@ def test_datetime_compare_nat(self):
     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 @@ def test_datetime_minmax(self):
         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 @@ def test_datetime_minmax(self):
         # 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 @@ def test_string_parser_variants(self):
         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 @@ def test_string_parser_error_check(self):
         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 @@ def test_creation_overflow(self):
     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 @@ def test_datetime_as_string(self):
         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 @@ def test_datetime_as_string(self):
                             '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 @@ def test_datetime_arange(self):
         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 @@ def test_datetime_is_busday(self):
 
     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
--- a/numpy/core/tests/test_deprecations.py
+++ b/numpy/core/tests/test_deprecations.py
@@ -5,6 +5,7 @@
 """
 from __future__ import division, absolute_import, print_function
 
+import datetime
 import sys
 import operator
 import warnings
@@ -12,7 +13,13 @@
 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 @@ def test_full_default_dtype(self):
         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.
 
diff --git a/numpy/testing/tests/test_utils.py b/numpy/testing/tests/test_utils.py
--- a/numpy/testing/tests/test_utils.py
+++ b/numpy/testing/tests/test_utils.py
@@ -465,6 +465,21 @@ def f():
         assert_equal(before_filters, after_filters,
                      "assert_warns does not preserver warnings state")
 
+    def test_context_manager(self):
+
+        before_filters = sys.modules['warnings'].filters[:]
+        with assert_warns(UserWarning):
+            warnings.warn("yo")
+        after_filters = sys.modules['warnings'].filters
+
+        def no_warnings():
+            with assert_no_warnings():
+                warnings.warn("yo")
+
+        assert_raises(AssertionError, no_warnings)
+        assert_equal(before_filters, after_filters,
+                     "assert_warns does not preserver warnings state")
+
     def test_warn_wrong_warning(self):
         def f():
             warnings.warn("yo", DeprecationWarning)
diff --git a/numpy/testing/utils.py b/numpy/testing/utils.py
--- a/numpy/testing/utils.py
+++ b/numpy/testing/utils.py
@@ -1706,7 +1706,22 @@ def __exit__(self):
         self._module.showwarning = self._showwarning
 
 
-def assert_warns(warning_class, func, *args, **kw):
+@contextlib.contextmanager
+def _assert_warns_context(warning_class, name=None):
+    __tracebackhide__ = True  # Hide traceback for py.test
+    with warnings.catch_warnings(record=True) as l:
+        warnings.simplefilter('always')
+        yield
+        if not len(l) > 0:
+            name_str = " when calling %s" % name if name is not None else ""
+            raise AssertionError("No warning raised" + name_str)
+        if not l[0].category is warning_class:
+            name_str = "%s " % name if name is not None else ""
+            raise AssertionError("First warning %sis not a %s (is %s)"
+                                 % (name_str, warning_class, l[0]))
+
+
+def assert_warns(warning_class, *args, **kwargs):
     """
     Fail unless the given callable throws the specified warning.
 
@@ -1715,6 +1730,14 @@ def assert_warns(warning_class, func, *args, **kw):
     If a different type of warning is thrown, it will not be caught, and the
     test case will be deemed to have suffered an error.
 
+    If called with all arguments other than the warning class omitted, may be
+    used as a context manager:
+
+        with assert_warns(SomeWarning):
+            do_something()
+
+    The ability to be used as a context manager is new in NumPy v1.11.0.
+
     .. versionadded:: 1.4.0
 
     Parameters
@@ -1733,22 +1756,37 @@ def assert_warns(warning_class, func, *args, **kw):
     The value returned by `func`.
 
     """
+    if not args:
+        return _assert_warns_context(warning_class)
+
+    func = args[0]
+    args = args[1:]
+    with _assert_warns_context(warning_class, name=func.__name__):
+        return func(*args, **kwargs)
+
+
+@contextlib.contextmanager
+def _assert_no_warnings_context(name=None):
     __tracebackhide__ = True  # Hide traceback for py.test
     with warnings.catch_warnings(record=True) as l:
         warnings.simplefilter('always')
-        result = func(*args, **kw)
-        if not len(l) > 0:
-            raise AssertionError("No warning raised when calling %s"
-                    % func.__name__)
-        if not l[0].category is warning_class:
-            raise AssertionError("First warning for %s is not a "
-                    "%s( is %s)" % (func.__name__, warning_class, l[0]))
-    return result
+        yield
+        if len(l) > 0:
+            name_str = " when calling %s" % name if name is not None else ""
+            raise AssertionError("Got warnings%s: %s" % (name_str, l))
 
-def assert_no_warnings(func, *args, **kw):
+
+def assert_no_warnings(*args, **kwargs):
     """
     Fail if the given callable produces any warnings.
 
+    If called with all arguments omitted, may be used as a context manager:
+
+        with assert_no_warnings():
+            do_something()
+
+    The ability to be used as a context manager is new in NumPy v1.11.0.
+
     .. versionadded:: 1.7.0
 
     Parameters
@@ -1765,14 +1803,13 @@ def assert_no_warnings(func, *args, **kw):
     The value returned by `func`.
 
     """
-    __tracebackhide__ = True  # Hide traceback for py.test
-    with warnings.catch_warnings(record=True) as l:
-        warnings.simplefilter('always')
-        result = func(*args, **kw)
-        if len(l) > 0:
-            raise AssertionError("Got warnings when calling %s: %s"
-                    % (func.__name__, l))
-    return result
+    if not args:
+        return _assert_no_warnings_context()
+
+    func = args[0]
+    args = args[1:]
+    with _assert_no_warnings_context(name=func.__name__):
+        return func(*args, **kwargs)
 
 
 def _gen_alignment_data(dtype=float32, type='binary', max_size=24):