Difference between revisions of "Python - datetime"
Jump to navigation
Jump to search
PeterHarding (talk | contribs) |
PeterHarding (talk | contribs) |
||
(5 intermediate revisions by the same user not shown) | |||
Line 2: | Line 2: | ||
* http://seehuhn.de/pages/pdate#sec:1.6.0 | * http://seehuhn.de/pages/pdate#sec:1.6.0 | ||
* http://www.tutorialspoint.com/python/time_strptime.htm - A good summary of codes/directives... | |||
=Precision= | |||
Here's a simple two-liner to calculate roughly how many YEARS you can squeeze into what's left of the 53 bits of precsion in an IEEE754 64-bit float: | |||
>>> import math | |||
>>> 10 ** (math.log10(2 ** 53) - math.log10(60 * 60 * 24) - 6) / 365.25 | |||
285.42092094268787 | |||
>>> | |||
Watch out for round-off; add the smallest non-zero numbers first: | |||
return timedelta.seconds + timedelta.microseconds / 1E6 + timedelta.days * 86400 | |||
=Examples= | =Examples= | ||
Line 214: | Line 228: | ||
* [http://www.python.org/doc/2.5/lib/node85.html time.strptime()] | * [http://www.python.org/doc/2.5/lib/node85.html time.strptime()] | ||
* [http://www.python.org/doc/2.5/lib/module-datetime.html datetime module] | * [http://www.python.org/doc/2.5/lib/module-datetime.html datetime module] | ||
=Timezone= | |||
<pre> | |||
from datetime import tzinfo, timedelta, datetime | |||
ZERO = timedelta(0) | |||
HOUR = timedelta(hours=1) | |||
# A UTC class. | |||
class UTC(tzinfo): | |||
"""UTC""" | |||
def utcoffset(self, dt): | |||
return ZERO | |||
def tzname(self, dt): | |||
return "UTC" | |||
def dst(self, dt): | |||
return ZERO | |||
utc = UTC() | |||
# A class building tzinfo objects for fixed-offset time zones. | |||
# Note that FixedOffset(0, "UTC") is a different way to build a | |||
# UTC tzinfo object. | |||
class FixedOffset(tzinfo): | |||
"""Fixed offset in minutes east from UTC.""" | |||
def __init__(self, offset, name): | |||
self.__offset = timedelta(minutes = offset) | |||
self.__name = name | |||
def utcoffset(self, dt): | |||
return self.__offset | |||
def tzname(self, dt): | |||
return self.__name | |||
def dst(self, dt): | |||
return ZERO | |||
# A class capturing the platform's idea of local time. | |||
import time as _time | |||
STDOFFSET = timedelta(seconds = -_time.timezone) | |||
if _time.daylight: | |||
DSTOFFSET = timedelta(seconds = -_time.altzone) | |||
else: | |||
DSTOFFSET = STDOFFSET | |||
DSTDIFF = DSTOFFSET - STDOFFSET | |||
class LocalTimezone(tzinfo): | |||
def utcoffset(self, dt): | |||
if self._isdst(dt): | |||
return DSTOFFSET | |||
else: | |||
return STDOFFSET | |||
def dst(self, dt): | |||
if self._isdst(dt): | |||
return DSTDIFF | |||
else: | |||
return ZERO | |||
def tzname(self, dt): | |||
return _time.tzname[self._isdst(dt)] | |||
def _isdst(self, dt): | |||
tt = (dt.year, dt.month, dt.day, | |||
dt.hour, dt.minute, dt.second, | |||
dt.weekday(), 0, -1) | |||
stamp = _time.mktime(tt) | |||
tt = _time.localtime(stamp) | |||
return tt.tm_isdst > 0 | |||
Local = LocalTimezone() | |||
# A complete implementation of current DST rules for major US time zones. | |||
def first_sunday_on_or_after(dt): | |||
days_to_go = 6 - dt.weekday() | |||
if days_to_go: | |||
dt += timedelta(days_to_go) | |||
return dt | |||
# In the US, DST starts at 2am (standard time) on the first Sunday in April. | |||
DSTSTART = datetime(1, 4, 1, 2) | |||
# and ends at 2am (DST time; 1am standard time) on the last Sunday of Oct. | |||
# which is the first Sunday on or after Oct 25. | |||
DSTEND = datetime(1, 10, 25, 1) | |||
class USTimeZone(tzinfo): | |||
def __init__(self, hours, reprname, stdname, dstname): | |||
self.stdoffset = timedelta(hours=hours) | |||
self.reprname = reprname | |||
self.stdname = stdname | |||
self.dstname = dstname | |||
def __repr__(self): | |||
return self.reprname | |||
def tzname(self, dt): | |||
if self.dst(dt): | |||
return self.dstname | |||
else: | |||
return self.stdname | |||
def utcoffset(self, dt): | |||
return self.stdoffset + self.dst(dt) | |||
def dst(self, dt): | |||
if dt is None or dt.tzinfo is None: | |||
# An exception may be sensible here, in one or both cases. | |||
# It depends on how you want to treat them. The default | |||
# fromutc() implementation (called by the default astimezone() | |||
# implementation) passes a datetime with dt.tzinfo is self. | |||
return ZERO | |||
assert dt.tzinfo is self | |||
# Find first Sunday in April & the last in October. | |||
start = first_sunday_on_or_after(DSTSTART.replace(year=dt.year)) | |||
end = first_sunday_on_or_after(DSTEND.replace(year=dt.year)) | |||
# Can't compare naive to aware objects, so strip the timezone from | |||
# dt first. | |||
if start <= dt.replace(tzinfo=None) < end: | |||
return HOUR | |||
else: | |||
return ZERO | |||
Eastern = USTimeZone(-5, "Eastern", "EST", "EDT") | |||
Central = USTimeZone(-6, "Central", "CST", "CDT") | |||
Mountain = USTimeZone(-7, "Mountain", "MST", "MDT") | |||
Pacific = USTimeZone(-8, "Pacific", "PST", "PDT") | |||
</pre> | |||
=Datetime Woes= | |||
See: http://blog.mfabrik.com/2008/06/30/relativity-of-time-shortcomings-in-python-datetime-and-workaround/ | |||
<pre> | |||
# Copyright (c) 2008, Red Innovation Ltd., Finland | |||
# All rights reserved. | |||
# | |||
# Redistribution and use in source and binary forms, with or without | |||
# modification, are permitted provided that the following conditions are met: | |||
# * Redistributions of source code must retain the above copyright | |||
# notice, this list of conditions and the following disclaimer. | |||
# * Redistributions in binary form must reproduce the above copyright | |||
# notice, this list of conditions and the following disclaimer in the | |||
# documentation and/or other materials provided with the distribution. | |||
# * Neither the name of Red Innovation nor the names of its contributors | |||
# may be used to endorse or promote products derived from this software | |||
# without specific prior written permission. | |||
# | |||
# THIS SOFTWARE IS PROVIDED BY RED INNOVATION ``AS IS'' AND ANY | |||
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
# DISCLAIMED. IN NO EVENT SHALL RED INNOVATION BE LIABLE FOR ANY | |||
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
__doc__ = """ | |||
This module provides monkey-patched Python datetime class | |||
that fully supports different time zones and conversions | |||
between them. | |||
See the source for licensing terms. | |||
""" | |||
__author__ = 'Antti Haapala <antti@redinnovation.com>' | |||
__date__ = '24 Jun 2008' | |||
__version__ = '$Revision$' | |||
__copyright__ = '2008 Red Innovation Ltd.' | |||
__license__ = '3-clause BSD' | |||
from datetime import datetime as _datetime, tzinfo as _tzinfo | |||
from pytz import timezone as _timezone | |||
import time as _time | |||
import pytz as _pytz | |||
import math as _math | |||
import re as _re | |||
from pytz import utc, UTC, HOUR, ZERO | |||
_utc = _pytz.utc | |||
_default_tz = _utc | |||
def set_default_timezone(new_tz): | |||
"""Sets the default time zone used by the objects | |||
contained in this module. new_tz may be either | |||
a pytz-compatible tzinfo (requires normalize | |||
and localize methods), or a time zone name known | |||
to pytz. | |||
""" | |||
global _default_tz | |||
if type(new_tz) is str or type(new_tz) is unicode: | |||
new_tz = _pytz.timezone(new_tz) | |||
_default_tz = new_tz | |||
class FixedOffset(_tzinfo): | |||
"""Fixed offset in minutes east from UTC. Based on | |||
the python tutorial and pytz test code.""" | |||
def __init__(self, offset, name): | |||
"""Constructor. Create a new tzinfo object | |||
with given offset in minutes and name.""" | |||
self.__offset = timedelta(minutes = offset) | |||
self.__name = name | |||
def utcoffset(self, dt): | |||
return self.__offset | |||
def tzname(self, dt): | |||
return self.__name | |||
def dst(self, dt): | |||
return ZERO | |||
def localize(self, dt, is_dst=False): | |||
"""Convert naive time to local time. Copied | |||
from pytz tzinfo classes""" | |||
if dt.tzinfo is not None: | |||
raise ValueError, 'Not naive datetime (tzinfo is already set)' | |||
return dt.replace(tzinfo=self) | |||
def normalize(self, dt, is_dst=False): | |||
"""Correct the timezone information on the | |||
given datetime. Copied from pytz tzinfo classes.""" | |||
if dt.tzinfo is None: | |||
raise ValueError, 'Naive time - no tzinfo set' | |||
return dt.replace(tzinfo=self) | |||
def __str__(self): | |||
return self.__name | |||
def __repr__(self): | |||
return '<%s>' % self.__name | |||
_fixed_offset_tzs = { } | |||
def _get_fixed_offset_tz(offsetmins): | |||
"""For internal use only: Returns a tzinfo with | |||
the given fixed offset. This creates only one instance | |||
for each offset; the zones are kept in a dictionary""" | |||
if offsetmins == 0: | |||
return _utc | |||
if not _fixed_offset_tzs.has_key(offsetmins): | |||
if offsetmins < 0: | |||
sign = '-' | |||
absoff = -offsetmins | |||
else: | |||
sign = '+' | |||
absoff = offsetmins | |||
name = "UTC%s%02d:%02d" % (sign, int(absoff / 60), absoff % 60) | |||
inst = FixedOffset(offsetmins, name) | |||
_fixed_offset_tzs[offsetmins] = inst | |||
return _fixed_offset_tzs[offsetmins] | |||
_iso8601_parser = _re.compile(""" | |||
^ | |||
(?P<year> [0-9]{4})(?P<ymdsep>-?) | |||
(?P<month>[0-9]{2})(?P=ymdsep) | |||
(?P<day> [0-9]{2}) | |||
(?: # time part... optional... at least hour must be specified | |||
(?:T|\s+) | |||
(?P<hour>[0-9]{2}) | |||
(?: | |||
# minutes, separated with :, or none, from hours | |||
(?P<hmssep>[:]?) | |||
(?P<minute>[0-9]{2}) | |||
(?: | |||
# same for seconds, separated with :, or none, from hours | |||
(?P=hmssep) | |||
(?P<second>[0-9]{2}) | |||
)? | |||
)? | |||
# fractions | |||
(?: [,.] (?P<frac>[0-9]{1,10}))? | |||
# timezone, Z, +-hh or +-hh:?mm. MUST BE, but complain if not there. | |||
( | |||
(?P<tzempty>Z) | |||
| | |||
(?P<tzh>[+-][0-9]{2}) | |||
(?: :? # optional separator | |||
(?P<tzm>[0-9]{2}) | |||
)? | |||
)? | |||
)? | |||
$ | |||
""", _re.X) # """ | |||
def _parse_iso(timestamp): | |||
"""Internal function for parsing a timestamp in | |||
ISO 8601 format""" | |||
timestamp = timestamp.strip() | |||
m = _iso8601_parser.match(timestamp) | |||
if not m: | |||
raise ValueError("Not a proper ISO 8601 timestamp!") | |||
year = int(m.group('year')) | |||
month = int(m.group('month')) | |||
day = int(m.group('day')) | |||
h, min, s, us = None, None, None, 0 | |||
frac = 0 | |||
if m.group('tzempty') == None and m.group('tzh') == None: | |||
raise ValueError("Not a proper ISO 8601 timestamp: " + | |||
"missing timezone (Z or +hh[:mm])!") | |||
if m.group('frac'): | |||
frac = m.group('frac') | |||
power = len(frac) | |||
frac = long(frac) / 10.0 ** power | |||
if m.group('hour'): | |||
h = int(m.group('hour')) | |||
if m.group('minute'): | |||
min = int(m.group('minute')) | |||
if m.group('second'): | |||
s = int(m.group('second')) | |||
if frac != None: | |||
# ok, fractions of hour? | |||
if min == None: | |||
frac, min = _math.modf(frac * 60.0) | |||
min = int(min) | |||
# fractions of second? | |||
if s == None: | |||
frac, s = _math.modf(frac * 60.0) | |||
s = int(s) | |||
# and extract microseconds... | |||
us = int(frac * 1000000) | |||
if m.group('tzempty') == 'Z': | |||
offsetmins = 0 | |||
else: | |||
# timezone: hour diff with sign | |||
offsetmins = int(m.group('tzh')) * 60 | |||
tzm = m.group('tzm') | |||
# add optional minutes | |||
if tzm != None: | |||
tzm = long(tzm) | |||
offsetmins += tzm if offsetmins > 0 else -tzm | |||
tz = _get_fixed_offset_tz(offsetmins) | |||
return datetime(year, month, day, h, min, s, us, tz) | |||
class datetime(_datetime): | |||
"""Time zone aware subclass of Python datetime.datetime""" | |||
__name__ = 'fixed_datetime.datetime' | |||
def __new__(cls, year, month, day, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, is_dst=False): | |||
"""Creates a localized timestamp with the given parameters. | |||
If tzinfo is omitted, the default time zone will be used.""" | |||
if tzinfo == None: | |||
tzinfo = _default_tz | |||
dt = _datetime(year, month, day, hour, minute, second, microsecond) | |||
dt = tzinfo.localize(dt, is_dst=is_dst) | |||
return _datetime.__new__( | |||
cls, dt.year, dt.month, dt.day, | |||
dt.hour, dt.minute, dt.second, | |||
dt.microsecond, dt.tzinfo) | |||
def __radd__(self, addend): | |||
"""Autonormalized addition of datetimes and timedeltas.""" | |||
added = _datetime.__radd__(self, addend) | |||
added = self.tzinfo.normalize(added) | |||
return datetime.__from_datetime_with_tz(added) | |||
def __add__(self, addend): | |||
"""Autonormalized addition of datetimes and timedeltas.""" | |||
added = _datetime.__add__(self, addend) | |||
added = self.tzinfo.normalize(added) | |||
return datetime.__from_datetime_with_tz(added) | |||
def utctimetuple(self): | |||
"""Return UTC time tuple, compatible with time.gmtime(). | |||
Notice: the original datetime documentation is misleading: | |||
Calling utctimetuple() on a timezone-aware datetime will | |||
return the tuple in UTC, not in local time.""" | |||
return _datetime.utctimetuple(self) | |||
def astimezone(self, tzinfo): | |||
"""Convert to local time in new timezone tz. | |||
The result is normalized across DST boundaries.""" | |||
dt = _datetime.astimezone(self, tzinfo) | |||
dt = tzinfo.normalize(dt) | |||
return datetime.__from_datetime_with_tz(dt) | |||
@staticmethod | |||
def __from_datetime_with_tz(dt): | |||
"""Internal: create a datetime instance from | |||
a timezone-aware instance of the builtin datetime type.""" | |||
if dt.tzinfo == None: | |||
raise ValueError("The given datetime.datetime is not timezone-aware!") | |||
return datetime(dt.year, dt.month, dt.day, | |||
dt.hour, dt.minute, dt.second, dt.microsecond, | |||
dt.tzinfo) | |||
@staticmethod | |||
def fromtimestamp(timestamp, tz=None): | |||
"""Tz's local time from POSIX timestamp.""" | |||
bd = _time.gmtime(long(timestamp)) | |||
us = 0 | |||
if isinstance(timestamp, float): | |||
us = timestamp % 1.0 | |||
us *= 1000000 | |||
args = list(bd[:6]) | |||
args += [ int(us), _utc ] | |||
_tmp = datetime(*args) | |||
if tz == None: | |||
tz = _default_tz | |||
rv = _tmp.astimezone(tz) | |||
return datetime.__from_datetime_with_tz(rv) | |||
@staticmethod | |||
def today(tz=None): | |||
"""New datetime with tz's local day and time | |||
If tz is not specified, use the default timezone""" | |||
return datetime.fromtimestamp(long(_time.time()), tz) | |||
@staticmethod | |||
def now(tz=None): | |||
"""New datetime with tz's local day and time | |||
If tz is not specified, use the default timezone""" | |||
return datetime.fromtimestamp(_time.time(), tz) | |||
@staticmethod | |||
def utcnow(): | |||
"""Return a new datetime representing UTC day and time.""" | |||
return datetime.now(tz=_utc) | |||
@staticmethod | |||
def utcfromtimestamp(): | |||
"""Return a new UTC datetime from a POSIX timestamp (like time.time()).""" | |||
return datetime.utcfromtimestamp(tz=_utc) | |||
@staticmethod | |||
def parseisoformat(timestamp): | |||
"""Parses the given ISO 8601 compatible timestamp string | |||
and converts it to fixed_datetime.datetime. The timestamp | |||
must conform to following formats: | |||
- the format is DATE SEP TIME TIMEZONE without | |||
any intervening spaces. | |||
- the date must be in format YYYY-MM-DD | |||
- the time may be either | |||
* HH:MM:SS,FFFF | |||
* HH:MM,FFFF | |||
* HH,FFFF | |||
FFFF is the fractional part. Decimal point can be | |||
used too. | |||
- the time zone must be either Z, -HH:MM or +HH:MM | |||
- the date and time must be separated either by | |||
whitespace or single T letter | |||
- the separators - and : may all be omitted, or | |||
must all be present. | |||
Examples (Unix Epoch): | |||
1970-01-01T00:00:00Z | |||
1970-01-01T00Z | |||
1969-12-31 19,5-04:30 | |||
19700101T030000+0300 | |||
""" | |||
return _parse_iso(timestamp) | |||
def isoformat(self, sep='T', short=False): | |||
"""Returns the date represented by this instance | |||
in ISO 8601 conforming format. The separator | |||
is used to separate the date and time, and defaults | |||
to 'T'. This method supports both long and short | |||
formats. The long format is | |||
YYYY-MM-DD HH:MM:SS[.FFFFFF]=HH:MM | |||
and short is | |||
YYYYMMDDTHHMMSS[.FFFFFF]=HHMM | |||
The fractional part is separated with decimal point and | |||
is omitted if microseconds stored in this datetime are | |||
0. | |||
""" | |||
if not short: | |||
return _datetime.isoformat(self, sep) | |||
args = [ self.year, self.month, self.day, self.hour, self.minute, self.second ] | |||
fmt = "%04d%02d%02dT%02d%02d%02d" | |||
tz = "%s%02d%02d" | |||
if self.microsecond != 0: | |||
fmt += ".%06d" | |||
args += [ self.microsecond ] | |||
offset = self.tzinfo.utcoffset(self) | |||
tzseconds = offset.seconds + offset.days * 24 * 60 * 60 | |||
sign = '+' if tzseconds >= 0 else '-' | |||
tzseconds = abs(tzseconds) | |||
tzout = tz % (sign, int(tzseconds / 3600), int((tzseconds / 60) % 60)) | |||
dtout = fmt % tuple(args) | |||
return dtout + tzout | |||
from datetime import date, timedelta, time, tzinfo, MAXYEAR, MINYEAR | |||
</pre> | |||
[[Category:Python]] | [[Category:Python]] | ||
[[Category: | [[Category:Python datetime]] |
Latest revision as of 15:01, 1 August 2015
References
- http://seehuhn.de/pages/pdate#sec:1.6.0
- http://www.tutorialspoint.com/python/time_strptime.htm - A good summary of codes/directives...
Precision
Here's a simple two-liner to calculate roughly how many YEARS you can squeeze into what's left of the 53 bits of precsion in an IEEE754 64-bit float:
>>> import math >>> 10 ** (math.log10(2 ** 53) - math.log10(60 * 60 * 24) - 6) / 365.25 285.42092094268787 >>>
Watch out for round-off; add the smallest non-zero numbers first:
return timedelta.seconds + timedelta.microseconds / 1E6 + timedelta.days * 86400
Examples
Simple Example
#!/usr/bin/env python import datetime start_date = datetime.datetime(2007,01,01) end_date = datetime.datetime(2008,03,11) print start_date print end_date date = start_date print 'Date' while date < end_date: print date.strftime('%Y-%m-%d') date += datetime.timedelta(days=1)
Examples of Range of Functions
#!/usr/bin/env python # # $Id:$ # #--------------------------------------------------------------------- import sys import getopt from datetime import datetime, timedelta #--------------------------------------------------------------------- """ From datetime documentation... def astimezone(self, tz): if self.tzinfo is tz: return self # Convert self to UTC, and attach the new time zone object. utc = (self - self.utcoffset()).replace(tzinfo=tz) # Convert from UTC to tz's local time. return tz.fromutc(utc) """ #--------------------------------------------------------------------- def display(dt): print " timetuple() -> %s" % dt.timetuple() print " strftime() -> %s" % dt.strftime("%Y-%m-%d %H:%M:%S") print "isocalendar() -> %s" % str(dt.isocalendar()) print " weekday() -> %d" % dt.weekday() print " isoweekday() -> %d" % dt.isoweekday() print " isoformat() -> %s" % dt.isoformat() print " __str__() -> %s" % dt.__str__() print " ctime() -> %s" % dt.ctime() print " tzname() -> %s" % dt.tzname() print " dst() -> %s" % dt.dst() print " timetz() -> %s" % dt.timetz() #--------------------------------------------------------------------- def test(): now = datetime.now() print "now():" display(now) utcnow = datetime.utcnow() print "utcnow():" display(utcnow) plus_1_day = now + timedelta(days=1) print "plus_1_day():" display(plus_1_day) plus_2_day = now + timedelta(days=2) print "plus_2_day():" display(plus_2_day) #--------------------------------------------------------------------- def usage(): USAGE = """ Usage: $ dt.py """ sys.stderr.write(USAGE) #--------------------------------------------------------------------- def main(argv): global logfile, verbose_flg #----- Process command line arguments ---------------------------- try: opts, args = getopt.getopt(argv, "hl:u:t", ["help", "logfile=", "verbose"]) except getopt.GetoptError: usage() sys.exit(2) else: for opt, arg in opts: if opt in ("-h", "--help"): usage() sys.exit(0) elif opt in ("-l", "--logfile"): logfile = arg elif opt in ("-v", "--verbose"): verbose_flg = True test() #--------------------------------------------------------------------- if __name__ == "__main__": main(sys.argv[1:]) #---------------------------------------------------------------------
Exploring datetime and time Modules
#!/usr/bin/env python import time import datetime import pprint print datetime.datetime.now() print datetime.datetime.now().date() print datetime.datetime.now().date().isoformat() print datetime.datetime.now().time() print datetime.__doc__ print print print "time.time() -> ", time.time() print pp = pprint pp.pprint(time.__dict__) print time.__doc__
Timezone Examples
>>> import datetime >>> from dateutil import tz # python dateutil offers loads of convenience: http://labix.org/python-dateutil >>> dt = datetime.datetime(2008, 8, 21, 12, 51, 0, 0, tz.tzlocal()) >>> print repr(dt), ":", dt datetime.datetime(2008, 8, 21, 12, 51, tzinfo=tzlocal()) : 2008-08-21 12:51:00+02:00 >>> dt_utc = dt.astimezone(tz.tzutc()) >>> print repr(dt_utc), ":", dt datetime.datetime(2008, 8, 21, 10, 51, tzinfo=tzutc()) : 2008-08-21 12:51:00+02:00 >>> dt == dt_utc
Using strptime() and strftime()
from datetime import datetime dt = datetime.strptime('10:13:15 2006-03-07', '%H:%M:%S %Y-%m-%d') ts = datetime.now().strftime('%Y%m%d%H%M%S')
rdt = task.fields.ReminderDateTime if rdt: ctx.locals.ReminderDate = rdt.strftime('%Y-%m-%d') ctx.locals.ReminderTime = rdt.hour * 60 + rdt.minute else: ctx.locals.ReminderDate = ctx.locals.Today ctx.locals.ReminderTime = 630
from time import strptime ... 'ReminderDateTime' : datetime(*strptime(ctx.locals.ReminderDateTime, '%Y-%m-%d')[0:6]) + timedelta(minutes=int(ctx.locals.ReminderTime)),
Python Documentation
Timezone
from datetime import tzinfo, timedelta, datetime ZERO = timedelta(0) HOUR = timedelta(hours=1) # A UTC class. class UTC(tzinfo): """UTC""" def utcoffset(self, dt): return ZERO def tzname(self, dt): return "UTC" def dst(self, dt): return ZERO utc = UTC() # A class building tzinfo objects for fixed-offset time zones. # Note that FixedOffset(0, "UTC") is a different way to build a # UTC tzinfo object. class FixedOffset(tzinfo): """Fixed offset in minutes east from UTC.""" def __init__(self, offset, name): self.__offset = timedelta(minutes = offset) self.__name = name def utcoffset(self, dt): return self.__offset def tzname(self, dt): return self.__name def dst(self, dt): return ZERO # A class capturing the platform's idea of local time. import time as _time STDOFFSET = timedelta(seconds = -_time.timezone) if _time.daylight: DSTOFFSET = timedelta(seconds = -_time.altzone) else: DSTOFFSET = STDOFFSET DSTDIFF = DSTOFFSET - STDOFFSET class LocalTimezone(tzinfo): def utcoffset(self, dt): if self._isdst(dt): return DSTOFFSET else: return STDOFFSET def dst(self, dt): if self._isdst(dt): return DSTDIFF else: return ZERO def tzname(self, dt): return _time.tzname[self._isdst(dt)] def _isdst(self, dt): tt = (dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.weekday(), 0, -1) stamp = _time.mktime(tt) tt = _time.localtime(stamp) return tt.tm_isdst > 0 Local = LocalTimezone() # A complete implementation of current DST rules for major US time zones. def first_sunday_on_or_after(dt): days_to_go = 6 - dt.weekday() if days_to_go: dt += timedelta(days_to_go) return dt # In the US, DST starts at 2am (standard time) on the first Sunday in April. DSTSTART = datetime(1, 4, 1, 2) # and ends at 2am (DST time; 1am standard time) on the last Sunday of Oct. # which is the first Sunday on or after Oct 25. DSTEND = datetime(1, 10, 25, 1) class USTimeZone(tzinfo): def __init__(self, hours, reprname, stdname, dstname): self.stdoffset = timedelta(hours=hours) self.reprname = reprname self.stdname = stdname self.dstname = dstname def __repr__(self): return self.reprname def tzname(self, dt): if self.dst(dt): return self.dstname else: return self.stdname def utcoffset(self, dt): return self.stdoffset + self.dst(dt) def dst(self, dt): if dt is None or dt.tzinfo is None: # An exception may be sensible here, in one or both cases. # It depends on how you want to treat them. The default # fromutc() implementation (called by the default astimezone() # implementation) passes a datetime with dt.tzinfo is self. return ZERO assert dt.tzinfo is self # Find first Sunday in April & the last in October. start = first_sunday_on_or_after(DSTSTART.replace(year=dt.year)) end = first_sunday_on_or_after(DSTEND.replace(year=dt.year)) # Can't compare naive to aware objects, so strip the timezone from # dt first. if start <= dt.replace(tzinfo=None) < end: return HOUR else: return ZERO Eastern = USTimeZone(-5, "Eastern", "EST", "EDT") Central = USTimeZone(-6, "Central", "CST", "CDT") Mountain = USTimeZone(-7, "Mountain", "MST", "MDT") Pacific = USTimeZone(-8, "Pacific", "PST", "PDT")
Datetime Woes
# Copyright (c) 2008, Red Innovation Ltd., Finland # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # * Neither the name of Red Innovation nor the names of its contributors # may be used to endorse or promote products derived from this software # without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY RED INNOVATION ``AS IS'' AND ANY # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL RED INNOVATION BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. __doc__ = """ This module provides monkey-patched Python datetime class that fully supports different time zones and conversions between them. See the source for licensing terms. """ __author__ = 'Antti Haapala <antti@redinnovation.com>' __date__ = '24 Jun 2008' __version__ = '$Revision$' __copyright__ = '2008 Red Innovation Ltd.' __license__ = '3-clause BSD' from datetime import datetime as _datetime, tzinfo as _tzinfo from pytz import timezone as _timezone import time as _time import pytz as _pytz import math as _math import re as _re from pytz import utc, UTC, HOUR, ZERO _utc = _pytz.utc _default_tz = _utc def set_default_timezone(new_tz): """Sets the default time zone used by the objects contained in this module. new_tz may be either a pytz-compatible tzinfo (requires normalize and localize methods), or a time zone name known to pytz. """ global _default_tz if type(new_tz) is str or type(new_tz) is unicode: new_tz = _pytz.timezone(new_tz) _default_tz = new_tz class FixedOffset(_tzinfo): """Fixed offset in minutes east from UTC. Based on the python tutorial and pytz test code.""" def __init__(self, offset, name): """Constructor. Create a new tzinfo object with given offset in minutes and name.""" self.__offset = timedelta(minutes = offset) self.__name = name def utcoffset(self, dt): return self.__offset def tzname(self, dt): return self.__name def dst(self, dt): return ZERO def localize(self, dt, is_dst=False): """Convert naive time to local time. Copied from pytz tzinfo classes""" if dt.tzinfo is not None: raise ValueError, 'Not naive datetime (tzinfo is already set)' return dt.replace(tzinfo=self) def normalize(self, dt, is_dst=False): """Correct the timezone information on the given datetime. Copied from pytz tzinfo classes.""" if dt.tzinfo is None: raise ValueError, 'Naive time - no tzinfo set' return dt.replace(tzinfo=self) def __str__(self): return self.__name def __repr__(self): return '<%s>' % self.__name _fixed_offset_tzs = { } def _get_fixed_offset_tz(offsetmins): """For internal use only: Returns a tzinfo with the given fixed offset. This creates only one instance for each offset; the zones are kept in a dictionary""" if offsetmins == 0: return _utc if not _fixed_offset_tzs.has_key(offsetmins): if offsetmins < 0: sign = '-' absoff = -offsetmins else: sign = '+' absoff = offsetmins name = "UTC%s%02d:%02d" % (sign, int(absoff / 60), absoff % 60) inst = FixedOffset(offsetmins, name) _fixed_offset_tzs[offsetmins] = inst return _fixed_offset_tzs[offsetmins] _iso8601_parser = _re.compile(""" ^ (?P<year> [0-9]{4})(?P<ymdsep>-?) (?P<month>[0-9]{2})(?P=ymdsep) (?P<day> [0-9]{2}) (?: # time part... optional... at least hour must be specified (?:T|\s+) (?P<hour>[0-9]{2}) (?: # minutes, separated with :, or none, from hours (?P<hmssep>[:]?) (?P<minute>[0-9]{2}) (?: # same for seconds, separated with :, or none, from hours (?P=hmssep) (?P<second>[0-9]{2}) )? )? # fractions (?: [,.] (?P<frac>[0-9]{1,10}))? # timezone, Z, +-hh or +-hh:?mm. MUST BE, but complain if not there. ( (?P<tzempty>Z) | (?P<tzh>[+-][0-9]{2}) (?: :? # optional separator (?P<tzm>[0-9]{2}) )? )? )? $ """, _re.X) # """ def _parse_iso(timestamp): """Internal function for parsing a timestamp in ISO 8601 format""" timestamp = timestamp.strip() m = _iso8601_parser.match(timestamp) if not m: raise ValueError("Not a proper ISO 8601 timestamp!") year = int(m.group('year')) month = int(m.group('month')) day = int(m.group('day')) h, min, s, us = None, None, None, 0 frac = 0 if m.group('tzempty') == None and m.group('tzh') == None: raise ValueError("Not a proper ISO 8601 timestamp: " + "missing timezone (Z or +hh[:mm])!") if m.group('frac'): frac = m.group('frac') power = len(frac) frac = long(frac) / 10.0 ** power if m.group('hour'): h = int(m.group('hour')) if m.group('minute'): min = int(m.group('minute')) if m.group('second'): s = int(m.group('second')) if frac != None: # ok, fractions of hour? if min == None: frac, min = _math.modf(frac * 60.0) min = int(min) # fractions of second? if s == None: frac, s = _math.modf(frac * 60.0) s = int(s) # and extract microseconds... us = int(frac * 1000000) if m.group('tzempty') == 'Z': offsetmins = 0 else: # timezone: hour diff with sign offsetmins = int(m.group('tzh')) * 60 tzm = m.group('tzm') # add optional minutes if tzm != None: tzm = long(tzm) offsetmins += tzm if offsetmins > 0 else -tzm tz = _get_fixed_offset_tz(offsetmins) return datetime(year, month, day, h, min, s, us, tz) class datetime(_datetime): """Time zone aware subclass of Python datetime.datetime""" __name__ = 'fixed_datetime.datetime' def __new__(cls, year, month, day, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, is_dst=False): """Creates a localized timestamp with the given parameters. If tzinfo is omitted, the default time zone will be used.""" if tzinfo == None: tzinfo = _default_tz dt = _datetime(year, month, day, hour, minute, second, microsecond) dt = tzinfo.localize(dt, is_dst=is_dst) return _datetime.__new__( cls, dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond, dt.tzinfo) def __radd__(self, addend): """Autonormalized addition of datetimes and timedeltas.""" added = _datetime.__radd__(self, addend) added = self.tzinfo.normalize(added) return datetime.__from_datetime_with_tz(added) def __add__(self, addend): """Autonormalized addition of datetimes and timedeltas.""" added = _datetime.__add__(self, addend) added = self.tzinfo.normalize(added) return datetime.__from_datetime_with_tz(added) def utctimetuple(self): """Return UTC time tuple, compatible with time.gmtime(). Notice: the original datetime documentation is misleading: Calling utctimetuple() on a timezone-aware datetime will return the tuple in UTC, not in local time.""" return _datetime.utctimetuple(self) def astimezone(self, tzinfo): """Convert to local time in new timezone tz. The result is normalized across DST boundaries.""" dt = _datetime.astimezone(self, tzinfo) dt = tzinfo.normalize(dt) return datetime.__from_datetime_with_tz(dt) @staticmethod def __from_datetime_with_tz(dt): """Internal: create a datetime instance from a timezone-aware instance of the builtin datetime type.""" if dt.tzinfo == None: raise ValueError("The given datetime.datetime is not timezone-aware!") return datetime(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond, dt.tzinfo) @staticmethod def fromtimestamp(timestamp, tz=None): """Tz's local time from POSIX timestamp.""" bd = _time.gmtime(long(timestamp)) us = 0 if isinstance(timestamp, float): us = timestamp % 1.0 us *= 1000000 args = list(bd[:6]) args += [ int(us), _utc ] _tmp = datetime(*args) if tz == None: tz = _default_tz rv = _tmp.astimezone(tz) return datetime.__from_datetime_with_tz(rv) @staticmethod def today(tz=None): """New datetime with tz's local day and time If tz is not specified, use the default timezone""" return datetime.fromtimestamp(long(_time.time()), tz) @staticmethod def now(tz=None): """New datetime with tz's local day and time If tz is not specified, use the default timezone""" return datetime.fromtimestamp(_time.time(), tz) @staticmethod def utcnow(): """Return a new datetime representing UTC day and time.""" return datetime.now(tz=_utc) @staticmethod def utcfromtimestamp(): """Return a new UTC datetime from a POSIX timestamp (like time.time()).""" return datetime.utcfromtimestamp(tz=_utc) @staticmethod def parseisoformat(timestamp): """Parses the given ISO 8601 compatible timestamp string and converts it to fixed_datetime.datetime. The timestamp must conform to following formats: - the format is DATE SEP TIME TIMEZONE without any intervening spaces. - the date must be in format YYYY-MM-DD - the time may be either * HH:MM:SS,FFFF * HH:MM,FFFF * HH,FFFF FFFF is the fractional part. Decimal point can be used too. - the time zone must be either Z, -HH:MM or +HH:MM - the date and time must be separated either by whitespace or single T letter - the separators - and : may all be omitted, or must all be present. Examples (Unix Epoch): 1970-01-01T00:00:00Z 1970-01-01T00Z 1969-12-31 19,5-04:30 19700101T030000+0300 """ return _parse_iso(timestamp) def isoformat(self, sep='T', short=False): """Returns the date represented by this instance in ISO 8601 conforming format. The separator is used to separate the date and time, and defaults to 'T'. This method supports both long and short formats. The long format is YYYY-MM-DD HH:MM:SS[.FFFFFF]=HH:MM and short is YYYYMMDDTHHMMSS[.FFFFFF]=HHMM The fractional part is separated with decimal point and is omitted if microseconds stored in this datetime are 0. """ if not short: return _datetime.isoformat(self, sep) args = [ self.year, self.month, self.day, self.hour, self.minute, self.second ] fmt = "%04d%02d%02dT%02d%02d%02d" tz = "%s%02d%02d" if self.microsecond != 0: fmt += ".%06d" args += [ self.microsecond ] offset = self.tzinfo.utcoffset(self) tzseconds = offset.seconds + offset.days * 24 * 60 * 60 sign = '+' if tzseconds >= 0 else '-' tzseconds = abs(tzseconds) tzout = tz % (sign, int(tzseconds / 3600), int((tzseconds / 60) % 60)) dtout = fmt % tuple(args) return dtout + tzout from datetime import date, timedelta, time, tzinfo, MAXYEAR, MINYEAR