Interface ( DateTime : DateTimeDelta : RelativeDateTime ) : Arithmetic : Submodules ( ISO : ARPA : Feasts ) : Examples : C API : Structure : Download & Installation : Support : Copyright : History : Home | Version 1.0.1 |
These types were created to provide a consistent way of transfering date and time data between Python and databases. Apart from handling date before the Unix epoch (1.1.1970) they also correctly work with dates beyond the Unix time limit (currently with Unix time value being encoded using 32bit integers, the limit is reached in 2038) and thus is Year 2000 and Year 2038 safe.
After some discussions on the db-sig list about what the date type DateTime should be capable of doing and what not, we decided to use the following internal format:
The epoch used by the module is January 1st of the year 1 at midnight (0:00:00.00). This date corresponds to absolute day 1 and absolute time 0. Dates before 01.01.0001 are not supported (this is a little difficult to handle, since the year 0 was omitted by the Romans).
For the purpose of storing absolute time values and time spans, the package provides a second type called DateTimeDelta. The internal representation for this type is seconds and stored in a signed C double.
As of version 0.9.1, a third object type is available: RelativeDateTime. This object is currently implemented in Python and may be used to store relative time deltas (see below for an exact description). It's main purpose is providing an intuitive way to calculate e.g. the "first of next month".
Designing the types wasn't as easy as expected, since many criteria had to be taken into account. Here are some of them and their implementation:
Time zones are among the most difficult to handle issues when it comes to implementing and using types for date and time. We chose to move the time zone handling functionality out of the C implementation and into Python. This means that the types know nothing about the time zones of the values they store and calculations are done using the raw values.
If you need to store and use these informations in calculations, you can "subclass" the types to implement your ideas rather than having to stick to what the C implementation defines. The included ODMG submodule is an example of how this can be done.
Leap seconds are not supported either. You can implement classes respecting these by "subclassing" DateTime and DateTimeDelta and then overriding the calculation methods with methods that work on Unix ticks values (if the underlying C lib knows about leap seconds).
For the purpose of converting the stored values to Unix ticks (number of seconds since the Unix epoch; the C lib also uses this representation) we assume that the values are given in local time. This assumption had to be made because the C lib provides no standard way to convert a broken down date/time value in any other way into a ticks value. Conversion from stored UTC values to ticks only works if your C lib provides the necessary mechanisms (see the notes for gmticks() below). Fortunately many C libs have a working mktime() or timegm() API, so the situation is not all that bad.
Conversions to COM dates and tuples are done without any assumption on the time zone. The raw values are used.
Conversion from other formats to DateTime instances is always done by first calculating the corresponding absolute time and date values (which are also used as basis for calculations).
The internal representation of date/times behaves much like
floats do in Python, i.e. rounding errors can occur when
doing calculations. There is a special compare function included
(cmp()
) in the package that allows you to compare
two date/time values using a given accuracy,
e.g. cmp(date1,date2,0.5)
will allow 12:00:00.5 and
12:00:01.0 to compare equal.
Special care has been taken to prevent these rounding errors from occurring for COM dates. If you create a DateTime instance using a COM date, then the value returned by the .COMDate() method is guaranteed to be exactly the same as the one used for creation. The same is true for creation using absolute time and absolute date and broken down values.
One other thing to keep in mind when working with DateTime and DateTimeDelta instances is that they are immutable (like tuples). Once an instance is created you can not change its value. Instead, you will have to create a new instance with modified values. The advantage of having immutable objects is that they can be used as dictionary keys.
DateTime and DateTimeDelta instances can be compared and hashed, making them compatible to the dictionary implementation Python uses (they can be used as keys). The copy protocol, simple arithmetic and pickleing are also supported (ee below for details).
DateTime and DateTimeDelta instances know how to output
themselves as ISO8601-strings. The format is very simple:
YYYY-MM-DD HH:MM:SS.ss for DateTime instances and
[-][DD:]HH:MM:SS.ss for DateTimeDelta instances (the DD-part
(days) is only given if the absolute delta value is greater than
24 hours). Customized conversion to strings can be done using
the strftime
-methods or the included submodules.
String parsing is supported through the strptime()
constructor which implements a very strict parsing scheme and
the included submodules (e.g. ISO and ARPA), which allow a little more freedom.
Comparing the types to time-module based routines is not really possible, since the used strategies differ. You can compare them to tuple-based date/time classes though: DateTime[Delta] are much faster on creation, use less storage and are faster to convert to the supported other formats than any equivalent tuple-based implementation written in Python.
Creation of time-module values using time.mktime() is much slower than doing the same thing with DateTime(). The same holds for the reverse conversion (using time.localtime()).
The storage size of ticks (floats, which the time module uses) is about 1/3 of the size a DateTime instance uses. This is mainly due to the fact that DateTime instances cache the broken down values for fast access.
To summarize: DateTime[Delta] are faster, but also use more memory than traditional time-module based techniques.
The package provides three data structures for working with date and time values. These are:
Several constructors are available in the module DateTime:
DateTimeFromAbsDateTime(absdate,abstime)
DateTime(year,month=1,day=1,hour=0,minute=0,second=0.0)
day
can be negative to indicate days
counted in reverse order, that is the last day becomes -1,
the day before that -2, and so on,
e.g. DateTime(1997,12,-2)
gives the
30.12.1997 (this is useful especially for months). Note
that although the above makes it look like this function
can handle keywords, it currently cannot.
Timestamp(year,month,day,hour=0,minute=0,second=0.0)
Date(year,month,day)
mktime(year,month,day,hour,minute,second,dow,doy,dst)
localtime(ticks=time.time())
now()
gmtime(ticks=time.time())
gmticks()
is
the inverse of this function.
utctime(ticks=time.time())
gmtime()
.
today(hour=0,minute=0,second=0.0)
DateTimeFromAbsDays(days)
DateTimeFromCOMDate(comdate)
COMDate()
returns exactly
the same value as the one used for constructing it -- even
though the internal representation is more
accurate.
strptime(string,format_string[,default])
Error
is raised if the
underlying C parsing function strptime()
fails. Note: This function is relatively new, you may not
have access to this constructor on your platform. For
further information on the format, please refer to the
Unix manpage (it is very similar to that of
strftime() which is documented in the Python
library reference for the time module).
A DateTime instance has the following methods:
tuple()
absvalues()
(absdate,
abstime)
.
ticks(offset=0.0,dst=-1)
OverflowError
exception if the objects value
does not fit into the system's ticks range.
Note: On some platforms the C lib's mktime()
function that this method uses does not allow setting DST
to an arbitrary value. The module checks for this and
raises a SystemError
in case setting DST to 0
or 1 does not result in valid results.
gmticks(offset=0.0)
OverflowError
exception if the objects
value does not fit into the system's ticks range.
Note: This method is not available on all
platforms. Use the helper function
gmticks(datetime)
for a more portable way of
handling conversion from UTC to ticks.
COMDate()
strftime(format_string="%c")
tz
instead.
Format(format_string="%c")
To make life easier, the instances also provide a more direct interface to their stored values:
hour, minute, second
year, month, day
dst
tz
day_of_week
day_of_year
days_in_month
iso_week
is_leapyear
yearoffset
absdays
absdate
abstime
Several constructors are available:
DateTimeDelta(delta_days,delta_seconds=0.0)
86400.0*days + seconds
. Keep this in mind
when passing negative values to the constructor.
TimeDelta(hour=0.0,minute=0.0,second=0.0)
hours * 3600 + minutes * 60 + seconds
. Keep
this in mind when passing negative values to the
constructor. The constructor allows usage of keywords,
e.g. Time(seconds=1.5) works.
Time(hour,minute=0.0,second=0.0)
DateTimeDeltaFromSeconds(seconds)
DateTimeDeltaFromDays(days)
A DateTimeDelta instance has the following methods:
absvalues()
(absdays, absseconds)
tuple. The
absseconds part is normalized in such way that it is
always smaller than 86400.0. The values can be used do
date/time calculations. Both values are signed.
tuple()
strftime(format_string)
%d %H %M %S %I %p %X
work as expected). Negative values show up positive --
you'll have to provide your own way of showing the sign
(the seconds
instance variable is signed).
To make life easier, the instances also provide a more direct interface to their stored values:
day, hour, minute, second
days, hours, minutes, seconds
TimeDelta(12,00,00).days ==
0.5
.
These constructors are avaiable:
RelativeDateTime(years=0,months=0,days=0,
year=0,month=0,day=0,
hours=0,minutes=0,seconds=0,
hour=None,minute=None,second=None)
RelativeDate(years=0,months=0,days=0,year=0,month=0,day=0)
RelativeDateTime objects store the given settings (plural nouns meaning deltas, singular nouns absolute values) and apply them when used in calculations. Delta values will have the effect of changing the corresponding attribute of the involved absolute DateTime object accordingly, while absolute values overwrite the DateTime objects attribute value with a new one. The effective value of the object is thus determined at calculation time and depends on the context it is used in.
Adding and subtracting RelativeDateTime instances is supported with the following rules: deltas will be added together and right side absolute values override left side ones.
Adding RelativeDateTime instances to and subtracting
RelativeDateTime instances from DateTime instances will
return DateTime instances with the appropriate calculations
applied, e.g. to get a DateTime instance for the first of
next month, you'd call now() +
RelativeDateTime(months=+1,day=01)
.
A few examples will probably make the intended usage clearer:
>>> from DateTime import * >>> print now() 1998-08-11 16:46:02.20 # add one month >>> print now() + RelativeDateTime(months=+1) 1998-09-11 16:46:24.59 # add ten months >>> print now() + RelativeDateTime(months=+10) 1999-06-11 16:47:03.07 # ten days from now >>> print now() + RelativeDateTime(days=+10) 1998-08-21 16:47:10.58 # first of next month >>> print now() + RelativeDateTime(months=+1,day=1) 1998-09-01 16:47:25.15 # first of this month, same time >>> print now() + RelativeDateTime(day=1) 1998-08-01 16:47:35.48 # first of this month at midnight >>> print now() + RelativeDateTime(day=1,hour=0,minute=0,second=0) 1998-08-01 00:00:00.00 # next year, first of previous month, same time >>> print now() + RelativeDateTime(years=+1,months=-1,day=1) 1999-07-01 16:48:31.87
RelativeDateTime instances currently don't have any instance methods.
The following attributes are exposed, but should not be written to directly (the objects are currently implemented in Python, but that could change in future releases).
year, month, day, hour, minute, second
years, months, days, hours, minutes, seconds
The given values are only defined in case they were set at instance creation time.
The package defines these constants:
oneWeek, oneDay, oneHour, oneMinute, oneSecond
Error, RangeError
DateTimeType, DateTimeDelta
mxDateTimeAPI
The package defines these additional functions:
cmp(obj1,obj2,accuracy=0.0)
gmticks(datetime)
datetime.gmticks()
if
it is available. If not, the module will revert to using
datetime.ticks(time.timezone,0)
. See the
notes on the datetime.ticks()
method for
further information on how this works.
In any case, you should check the correctness of the results on your target platforms to avoid wrong results or malfunctioning programs.
utcticks(datetime)
gmticks()
.
tz_offset(datetime)
datetime.ticks()
method, so the same comments
as for gmtime()
apply.
gm2local(datetime)
gmticks()
, so the same comments
apply.
utc2local(datetime)
gm2local()
.
local2gm(datetime)
local2utc(datetime)
local2gm()
.
If you find any bugs, please report them to me so that I can fix them for the next release.
The three objects DateTime, DateTimeDelta and
RelativeDateTime can be used to do simple date/time
arithmetic. Addition and subtraction are supported and result
in the expected results. In addition to handling arithmetic
using only the two types, mixed arithmetic with numbers is
also understood to a certain extent:
No operations defined.
Note: Operation and argument order are important
because of the different ways arguments are coerced. Use
parenthesis to make your intent clear or you will get unwanted
results.
Due to a flaw in the C interface for coercion in the
interpreter, it is not possible to do proper handling of mixed
type arithmetic for types which don't coerce to a common type
(without creating temporary objets all the time). The module
uses a workaround, but unfortunately the order of the operands
is lost along the way. Under normal circumstances you won't
notice this defect, but be warned since e.g.
The package provides additional features in form of the
following submodules. All submodules are imported on request
only.
The ISO submodule is intended to provide interfacing
functions to ISO
8601 date and time representations . The most common format
is:
YYYY-MM-DD HH:MM:SS[+-HH:MM]
Note that timezone information (in square brackets)
is only interpreted by the
You can access the functions and symbols defined in the
submodule through
The module defines these constructors and functions:
The parsing routines strip surrounding whitespace from the
strings, but are strict in what they want to see. Additional
characters are not allowed and will cause a
Timezone information may be included, but will not be
interpreted unless explicitly stated.
The parsing routines also understand the ISO 8601 date/time
formats without seperating dashes and colons,
e.g. '19980102T142020', and mixtures of both notations.
DateTime and DateTimeDelta instances use a slightly enhanced ISO
format for string represenation:
DateTime instances are converted to
DateTimeDelta instances use
The ARPA submodule is intended to provide interfacing
functions to ARPA date representations. These are used throughout
the Internet for passing around mails, postings, etc. The
format is very simple:
[Day, ]DD Mon YYYY HH:MM[:SS] ZONE
where ZONE can be one of these: MDT, O, EDT, X, Y,
CDT, UT, AST, GMT, PST, Z, V, CST, ADT, I, W, T, U, R, S, P,
Q, N, EST, L, M, MST, K, H, E, F, G, D, PDT, B, C, UTC, A
(the single letter ones being military
time zones). Use of explicit time zone names other than
UTC and GMT is depreciated, though. The better alternative
is providing the offset from UTC being in effect at the
given local time: +-HHMM (this is the offset you
have to subtract from the given time in order to get UTC).
You can access the functions and symbols defined in the
submodule through
The module defines these constructors and functions:
The parsing routines strip surrounding whitespace from the
strings. Additional characters are allowed (because some
mail apps add extra information to the date header).
The Feasts submodule is intended to provide easy-to-use
constructors for common moveable christian feasts that can
be deduced from the date of Easter Sunday.
The algorithm used to calculate Easter Sunday is based on
the one presented in the Calendar
FAQ by Claus Tondering, which in return is based on the
algorithm of Oudin (1940) as quoted in "Explanatory
Supplement to the Astronomical Almanac", P. Kenneth
Seidelmann, editor.
The module defines these constructors and functions:
The other feasts are deduced from this date and all use the
same interface. The module defines these sets of
constructors the return the corresponding DateTime instance
for midnight of the implied day:
For an example of how to use the two types to develop other
date/time classes (e.g. ones that support time zones or
different calendars), see the included ODMG
module. It defines types similar to those of the ODMG
standard.
Here is a little countdown script:
This snippet demonstrates some of the possible string
representations for DateTime instances:
More examples will eventually appear in the Examples
subdirectory of the package.
Names with trailing / are plain directories, ones with
[]-brackets are Python packages, ones with ".py" extension
are Python submodules.
The package imports all symbols from the extension module
and also registers the types so that they become compatible
to the pickle and copy mechanisms in Python.
Windows:
Florent Heyworth (radbit.com) has kindly provided a
compiled version of the C extension for Windows 95 which is
included in the archive (version 1.0.1) -- no further steps
or compilation are necessary.
If you intend to recompile the module yourself, he has
also provided a batch file (win32mk.bat) and a make file
(mxDateTime.mak) for VC50 which you can use. All you have to
do is run 'win32mk c:\programs\python' from the mxDateTime
subdirectory.
Unix:
Please post any bug reports, questions etc. directly to me.
I am currently planning to provide commercial support for
this package through Python Professional
Services Inc.. If you are interested in receiving
information about this service or have suggestions regarding
the form of support you would like to receive, please
contact me.
© 1997,1998, Copyright by Marc-André Lemburg; All
Rights Reserved. mailto: mal@lemburg.com
Permission to use, copy, modify, and distribute this
software and its documentation for any purpose and without fee
or royalty is hereby granted, provided that the above
copyright notice appear in all copies and that both the
copyright notice and this permission notice appear in
supporting documentation or portions thereof, including
modifications, that you make.
THE AUTHOR MARC-ANDRE LEMBURG DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE AUTHOR BE
LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
OR PERFORMANCE OF THIS SOFTWARE !
Things that still need to be done:
Things that changed from 1.0.0 to 1.0.1:
Things that changed from 0.9.2 to 1.0.0:
This change was needed since there is no way in Python
to make sure that C extensions are really only imported
once: importing mxDateTime directly and indirectly through
the DateTime package lead to two versions of the
extensions being loaded. While this is not too serious at
first sight (it may even be useful in some cases) it turns
out to be a significant problem because the objects
declared by the two versions are seen as being of
different type (type checks in Python are done via
comparing the address of type objects).
As a result, you no longer have to run 'make install'
to install the C extension.
Things that changed from 0.9.1 to 0.9.2:
Things that changed from 0.9.0 to 0.9.1:
Older history entries can be found in a seperate list.
Date/Time Arithmetic
Argument 1
Argument 2
Result
DateTime object v
DateTime object w
v - w
v + w
DateTime object v
A number w
v - w
w
days (floats can be used to indicate day
fractions);
v + w
Note: you can use the object oneDay to get similar
effects in a more intuitive way.
v cmp w
v
to Unix ticks and returns the result of comparing the
ticks value to the number w
. Note: the
ticks conversion assumes that the stored value is
given in local time. Also note that the comparison will
only yield correct results if the DateTime instance is
placed on the left of the comparison operator
(this is because of the coercion quirks mentioned
above).
DateTime object v
DateTimeDelta object w
v - w
w
's value;
v + w
DateTime object v
RelativeDateTime object w
v + w
w
's settings;
v - w
DateTimeDelta object v
DateTime object w
DateTimeDelta object v
A number w
v - w
w
seconds (can be
given as float to indicate fractions of a second);
v + w
Note: you can use the object oneSecond to get similar
effects in a more intuitive way;
v * w
w
;
v / w
w
;
v cmp w
v
to a signed float representing the delta in seconds
and returns the result of comparing the seconds value
to the number w
.Note that the comparison
will only yield correct results if the DateTimeDelta
instance is placed on the left of the comparison
operator (this is because of the coercion quirks
mentioned above).
DateTimeDelta object v
DateTimeDelta object w
v + w
(v+w).seconds == v.seconds +
w.seconds
);
v - w
v / w
v.seconds / w.seconds
.
oneDay - 1
== 1 - oneDay
, yet oneDay - oneSecond !=
oneSecond - oneDay
.
Submodules
ISO Submodule
ParseDateTimeUTC()
constructor. All others ignore the given offset and store
the time value as-is.
DateTime.ISO
-- it is
imported on demand.
WeekTime(year,isoweek=1,isoday=1,hour=0,minute=0,second=0.0)
iso_week
provides
an inverse to this function.
Week(year,isoweek,isoday=1)
WeekTime()
.
DateTime(), Time(), TimeDelta()
ParseDateTime(isostring)
ParseDateTimeGMT(isostring)
ParseDateTimeUTC(isostring)
ParseDate(isostring)
ParseWeek(isostring)
ParseWeekTime(isostring)
ParseTime(isostring)
ParseTimeDelta(isostring)
ParseAny(isostring)
str(datetime)
strGMT(datetime)
strUTC(datetime)
ValueError
to be raised.
ISO 8601 string formats and DateTime[Delta] instances
'YYYY-MM-DD
HH:MM:SS.ss'
where the last ss indicate hundredths of a
second (ISO doesn't define how to display these).
'[-][DD:]HH:MM:SS.ss'
as format, where DD: is only shown for deltas spanning more than
one day (24 hours). The ss part has the same meaning as for
DateTime instances: hundredths of a second. A minus is shown for
negative deltas. ISO does not define relative time deltas, but
the time representation is allowed to be 'HH:MM:SS'.
ARPA Submodule
DateTime.ARPA
-- it is
imported on demand.
ParseDateTime(arpastring)
ParseDateTimeGMT(arpastring)
ParseDateTimeUTC(arpastring)
str(datetime,tz=DateTime.tz_offset(datetime))
strGMT(datetime)
strUTC(datetime)
Feasts Submodule
EasterSunday(year),
Ostersonntag(year), DimanchePaques(year)
CarnivalMonday(year),
Rosenmontag(year)
MardiGras(year)
AshWednesday(year),
Aschermittwoch(year), MercrediCendres(year)
PalmSunday(year),
Palmsonntag(year), DimancheRameaux(year)
EasterFriday(year),
Karfreitag(year), LundiPaques(year)
EasterMonday(year),
Ostermontag(year), LundiPaques(year)
Ascension(year),
Himmelfahrt(year)
WhitSunday(year),
Pfingstsonntag(year), DimanchePentecote(year)
WhitMonday(year),
Pfingstmontag(year), LundiPentecote(year)
CorpusChristi(year),
Frohnleichnam(year), FeteDieu(year)
Examples of Use
#!/usr/local/bin/python -u
""" Y2000.py - The year 2000 countdown.
"""
from DateTime import *
from time import sleep
while 1:
d = Date(2000,1,1) - now()
print 'Y2000... time left: %2i days %2i hours '
'%2i minutes %2i seconds\r' % \
(d.day,d.hour,d.minute,d.second),
sleep(1)
>>> from DateTime import *
>>> ISO.str(now())
'1998-06-14 11:08:27+0200'
>>> ARPA.str(now())
'Sun, 14 Jun 1998 11:08:33 +0200'
>>> now().strftime()
'Sun Jun 14 11:08:51 1998'
>>> str(now())
'1998-06-14 11:09:17.82'
Supported Data Types in the C-API
Please have look at the file mxDateTime.h for details.
Interfacing is provided through a Python C object for ticks, struct
tm, COM doubles, Python tuples and direct input either by giving
absolute date/time or a broken down tuple.
To access the module, do the following (note the similarities with
Python's way of accessing functions from a module):
#include "mxDateTime.h"
...
PyObject *v;
/* Import the mxDateTime module */
if (mxDateTime_ImportModuleAndAPI())
goto onError;
/* Access functions from the exported C API through mxDateTime */
v = mxDateTime.DateTime_FromAbsDateAndTime(729376, 49272.0);
if (!v)
goto onError;
/* Type checking */
if (mxDateTime_Check(v))
printf("Works.\n");
Py_DECREF(v);
...
Package Structure
[DateTime]
Doc/
Examples/
[mxDateTime]
ARPA.py
DateTime.py
Feasts.py
ISO.py
ODMG.py
Installation
First, download the archive, unzip it to a
directory on your Python path and then follow these
steps (assuming you have already installed Python):
timegm
symbol. The next Python release (1.5.2) will do the
needed checking for you, until then you'll have to edit
the file manually...
Support
What I'd like to hear from you...
Copyright & Disclaimer
History & Future