NumPy has datetimes, called
datetime64 to avoid
confusion with the Python datetime module and class. But it only uses
ISO 8601 formats
for text entries.
i.e.: 2013-06-19T16:14:32.00-0700. It will also
take a Python
datetime.datetime() or
numpy.datetime64() as an argument, but NumPy will always
shift the date/time to the local timezone. If the Python
datetime.datetime() object is naive (IE no
tzinfo
) then NumPy will assume it is UTC (Zulu, GMT or +0000). Calling
numpy.datetime64().item() will return the UTC equivalent
Python
datetime.datetime() object.
Examples with np.datetime64 dtype:
>>> import numpy as np
>>> from datetime import datetime
>>> np.datetime64(datetime.today().isoformat())
numpy.datetime64('2013-06-19T16:17:27.612000-0700')
Examples with np.array:
>>> dt = np.dtype([('dates', 'datetime64[D]'), ('dni', float)])
>>> data = [('2001-01-01', 834.34),
... ('2001-01-02', 635.12)]
>>> npdata = np.array(data, dt)
array([(datetime.date(2001, 1, 1), 834.34),
(datetime.date(2001, 1, 2), 635.12)],
dtype=[('dates', '<M8[D]'), ('dni', '<f8')])
Repeat that with a datetime using Zulu time.
>>> dt = np.dtype([('dates', 'datetime64[m]'), ('dni', float)])
>>> data = [('2001-01-01T00:30Z', 834.34),
... ('2001-01-01T01:30Z', 635.12)]
>>> npdata = np.array(data, dt)
array([(datetime.datetime(2001, 1, 1, 0, 30), 834.34),
(datetime.datetime(2001, 1, 1, 1, 30), 635.12)],
dtype=[('dates', '<M8[m]'), ('dni', '<f8')])
Repeat that with a datetime using UTC offset
(+0000) for Zulu.
>>> dt = np.dtype([('dates', 'datetime64[m]'), ('dni', float)])
>>> data = [('2001-01-01T00:30-0000', 834.34),
... ('2001-01-01T01:30-0000', 635.12)]
>>> npdata = np.array(data, dt)
array([(datetime.datetime(2001, 1, 1, 0, 30), 834.34),
(datetime.datetime(2001, 1, 1, 1, 30), 635.12)],
dtype=[('dates', '<M8[m]'), ('dni', '<f8')])
n.b.: Numpy converts strings for you, so you don't have to use
np.datetime64 to cast them as
datetime64 dtypes. Also it converts them to
Python
datetime.datetime or
datetime.date, depending on your date units and shifts them to
GMT
(or Zulu) time. NumPy seems to handle dates and datetimes with the default units of day,
e.g.: [D], but for structured arrays you must specify the datetime units
e.g.: [D],
[m],
[s] or
[ms] (see
datetime units) in addition to
datetime64 as the
dtype
or NumPy gives you this cryptic error:
Value Error: Cannot create a
NumPy datetime other than NaT with generic units
Thanks to
this answer
on SO for unriddling that puzzle. If you make a NumPy datetime with nothing, you'll discover that
NaT means "Not a time". In addition you may get this error, which is a bit more informative.
TypeError: Cannot cast datetime.datetime object from metadata [us] to [D] according to the rule 'same_kind'
This is because
datetime.datetime uses micro-seconds
[us] as its default, but NumPy uses days
[D]. Specify the dtype using
[us] or some form of seconds units, e.g.:
[s],
[ms], and it should work.
This is an undocumented function that uses
dateutils to
convert a string to a floating decimal number that matplotlib uses to treat
dates, similar to MATLAB and Excel. The function can also be imported via
pylab.
>>> import pylab
>>> import pytz
>>> pst = pytz.timezone('US/Pacific')
>>> some_date = pylab.datestr2num('1998-1-1 12:15-0800')
>>> pylab.num2date(some_date, pst)
datetime.datetime(1998, 1, 1, 12, 15, tzinfo=<DstTzInfo 'US/Pacific' PST-1 day, 16:00:00 STD>)
>>> same_date = pylab.datestr2num('1/1/1998 12:15-0800')
>>> pylab.num2date(some_date, pst)
datetime.datetime(1998, 1, 1, 12, 15, tzinfo=<DstTzInfo 'US/Pacific' PST-1 day, 16:00:00 STD>)
Pretty nifty! Works better than I thought! In fact I like it way better than
NumPy or Python for that matter. Note how using
pytz helps matplotlib
set the timezone; the
tz class from
dateutils can also be used to set
tzinfo. Also note that if we hadn't set the UTC offset in the string,
then it would have output 4:15 AM instead of 12:15, since it would have assumed
GMT. Also matplotlib is pretty smart about determining the format; the default
is month/day/year.
Python datetime
The lame way to do this is with Python's
datetime.strptime(), but it doesn't support the
%z directive for UTC offset (
that's only for strftime()
functions of datetime, date
and time instances), and it only has an
abstract class
tzinfo for timezone, which can be
replaced by pytz.
>>> dt = datetime.strptime('1998-1-1 12:15', '%Y-%m-%d %H:%M') # naive datetime instance
>>> print dt
1998-01-01 12:15:00
>>> new_dt = datetime(*dt.timetuple()[0:6], tzinfo=pst) # aware datetime instance
>>> print new_dt
1998-01-01 12:15:00-08:00
>>> new_dt.toordinal()
729390
The ordinal of the datetime is the date and hour part but matplotlib also
outputs the fractional sub-day portion. The
strptime()
classmethod lets you set the format, which is very nice.
Time
When working with times, it will assume 1900-01-01, while NumPy assumes 1970
and matplotlib will default to today's date. But it's actually hard to create a
NumPy time only as in Python
datetime.time. Maybe
there is a correct way to do it, but I could only make
datetime.date and
datetime.datetime with
numpy.datetime64.
NumPy time example:
>>> np.array(datetime.time(8, 30), dtype='datetime64[m]')
Could not convert object to NumPy datetime
The only way I could do it was with
timedelta64.
>>> t = np.timedelta64(8, 'h') + np.timedelta64(30, 'm')
>>> print t
510 minutes
>>> np.array(t, dtype='datetime64')
>>> array(datetime.datetime(1970, 1, 1, 8, 30), dtype='datetime64[m]')
So you can see, NumPy just randomly chose 1970 to be the year! As I said,
Python reverts to 1900. For these examples I have to use
datetime.time, so reimport
datetime by
itself. Also I assume that pytz was imported and
pst
is a
pytz.timezone instance of 'US/Pacific'
as in the sections above.
Python datetime.time example:
>>> import datetime
>>> t = datetime.time(8, 30, tzinfo=pst)
>>> t.strftime('%Y-%m-%d %H:%M %Z')
'1900-01-01 08:30 US/Pacific'
The timezone name,
%Z, worked but I couldn't get
%z to show the UTC offset. But both worked for
datetime.datetime.
>>> dt = datetime.datetime.strptime('8:30','%H:%M')
>>> dt.replace(tzinfo=pst).strftime('%m/%d/%Y %H:%M:%S %z (%Z)')
'01/01/1900 08:30:00 -0800 (PST)'
Finally, as I said, matplotlib assumes whatever the current date. Notice too,
that since it knows that it's currently daylight savings time!
matplotlib time example:
>>> md = pylab.num2date(pylab.datestr2num('8:30 -0700'), pst)
>>> md
datetime.datetime(2013, 6, 19, 8, 30, tzinfo=<DstTzInfo 'US/Pacific' PDT-1 day, 17:00:00 DST>)
You can use
datetime.replace() to swap out the date for whatever
you want.
>>> print md.replace(1998, 1, 1)
1998-01-01 08:30:00-07:00
This works for
tzinfo too.
>>> print dt.replace(tzinfo=pst) # aware datetime instance
1998-01-01 12:15:00-08:00
ISO 8601 Format
All of the datetime classes and therefore matplotlib too, all have an isoformat
function.
>>> md.isoformat()
'2013-06-19T08:30:00-07:00'
Timezone
Hope you noticed that there are lots of timezone info.
>>> t.tzname()
'US/Pacific'
>>> md.tzname()
'PDT'
Please see the
pytz and
dateutils packages for complete details on using timezones, as there are package specific methods other than replacing
tzinfo. For example, pytz exposes the
localize method to create a datetime directly from a timezone object.
>>> pst.localize(datetime(2013,4,20,12,30))
datetime.datetime(2013, 4, 20, 12, 30, tzinfo=<DstTzInfo 'US/Pacific' PDT-1 day, 17:00:00 DST>)
This is a separate module for timing CPU operations. Also IPython has its own
magical time, which can be called using
%time. You
can use
time.clock() to measure how
fast code runs on most platforms, and
time.sleep() will make it pause.
Wow! I hope I can remember all of this!