pep proposal : A date object for the standard library

sebastien s.keim at laposte.net
Thu Dec 6 06:46:44 EST 2001


hello,

This is the first draft of a PEP to introduce a high level date class
in python standard
library. 
I have highlighted by [???] the points that I'm not sure. Of course
that doesn't mean that the
other sentences are true ;-) .

Since I am not a brilliant English speaker, grammar would probably
need a little refactoring too.


PEP: XXX
Title: Improving date time support in Python
Version: 
Last-Modified: 
Author: s.keim at laposte.net (Sébastien Keim)
Status: Active
Type: Informational
Created: 29-Nov-2001
Post-History:


Abstract

Date and Time computation is a bit of mess in almost every programming
languages. This is mainly because calendars are a very irregular kind
of data.

In standard python, dates are defined with two formats:
 * os module use the POSIX format (elapsed time in seconds since the
1970-01-01)
 * a tupple is defined in the time module
They are low level format, not really user-friendly.
This PEP try to define an high level date protocol intended to ease
date manipulation in Python.
   
Rationale

Fundamentally, a date is the coordinates of a point on the time axis.
Calendars are just tools to express this notion with units more
suitable for people.
    
During the years people have tried to find a calendar representation
that fit their feeling of naturals events. That mean that exist today
dozens of calendars, even if the most  used is the Gregorian one.

This facts mandate several objectives for a python date module:
     - date arithmetic should be independent of the calendar
presentation chosen.
     - since it's the most widely used, the standard date module
should support the Gregorian calendar.
     - but because some specific applications could need another
calendar convention, we shouldmake the creation of new calendar
libraries as easy as possible.


    
What exist today for Python
		
A powerful mxDateTime tools already exist but this package is probably
to complex to go on the standard distribution[3].
				

NormalDate define also a light date class[2].


AbstractDate class

Many operations on dates, don't bother with the calendar used to
process this date.
So we can create an AbstractDate class that will define this
operations. That mean that they  will be allowed for any date objects
that would inherit from this class.

The first thing that we need is a way to share a date information
between dates classes. It's important to define a common lingua for
dealing with dates. This will allow the Python users to create several
calendar related class without having to boring (to much) with
conversions problems.

This intermediate format could be defined as a floating point
representing the modified juian day numbers[5].
This will be called MJD (Modified Julian Day) in the next part of the
document.

In this format, the integer part correspond to the number of elapsed
days since the start of the day 1858-11-17 CE. Negatives numbers are
allowed for date before 1858-11-17. The decimal component is the
fraction of the day corresponding to hour minutes and seconds,
expressed in GMT.

This format has the following advantages:
  - date arithmetic is easy (number of days between two dates is
trivial, the  day of week need only to compute a modulo 7 ..)
  - floating representation allow to compute dates arbitrary far in
the past, even if we lose precision.
  - we keep the better precision for current dates.
  - algorithms for conversion to Gregorian or Julian dates are well
known.
  - it's a quite standard format.

I feel this solution better than the POSIX convention to count the
elapsed time in seconds because not all the days have the same length.
About once every year or two there is an extra second, called a "leap
second" added as the last second of the December 31 or June 30. For
example, the last minute of the year 1995 was 61 seconds long, thanks
to an added leap second. In MJD format, this seconds won't accumulate
for years to years.

Each calendar classes should define:
   - MJD() : method that return the Modified Julian Day from the given
date
   - from_MJD(n) : class method that return a date object from the
Modified  Julian Day n
For converting the MJD in their own calendar protocol.

AbstractDate class definition of the operations:       
       - date1 < date2  (and <=, ==,  >=, >, <>)    
       - hash value
       - date + duration ==> date
       - date - duration ==> date
       - date - date ==> duration
would only depend to from_MJD() and MJD() methods
That mean that we will be able to do arithmetic between almost any
date objects that would define this two methods.

[???]since we deal with real numbers maybe we should define a minimal
range where two dates are equals.
    
 I don't feel the need to introduce a new type for duration. Duration
can be expressed as a floating point number of seconds. This give us
all the arithmetic needed and this format is backward compatible with:
    * timeouts in the thread module
    * duration computed from dates of files expressed in epoch
format(in the os module )
    
We can define a few numbers of constants:
    seconds =      1.0
    minutes =     60.0
    hours   =   3600.0
    days    =  86400.0
    weeks   = 604800.0
  
We can't introduce higher constants because we deal here with absolute
duration. Length of month or year isn't absolute but relative to the
starting date. So relative duration is dependant of the calendar
chosen.
    
    
Default calendar classes

AbstractDate class is intended to make the creation of calendar
related  classes as easy as possible. Netherless I don't think Python
user would be happy to have to redefine their own calendar classes for
common work on dates.
According to the 80-20 rule, this PEP suggest to define for in the
standard library a default date class intended to solve the most
common date time  problems.
    
Default date classe should work with local time. User will have to
create subclass for handling non-local times. It would be great if he
had only twomethods to redefine, one to convert from GMT to local
times, and one for the opposite operation. Because of daylight saving
hours, this methods will have to know the empty date to compute, not
only the time part.

The default methods could use the built-in time module for computing
time zone offset.
 [???] I don't know well the behavior of this module but I don't think
it's clever enough to know when daylight saving was introduced in a
given time  zone. This could introduce errors when we compute dates in
the past.

 [???] The high majority of platforms support the time module but what
to do  with the one which doesn't?

   Constructor:    
If no args current time is used to create the object
If one arg ==> the object given in arg must define a MJD() method
For more args, the following rule apply:
    date(year, month, day, hour=0, minute=0, seconds=0)
    
Note that, you could have something like:
    >>> date(1858,11,17).MJD()
      -0.25
Where you was probably waiting for 0.0
This is because we use local time, and with your time zone offset, the
1858-11-17 0h00 can actually be something like 1858-11-16  18h00 GMT.
[???] Any better way to handle both pure date (without specifying
time) and local time zone without ambiguity?

A factory function: time(hour, minute, seconds) will create a date
object by using current year, month and day.
    
 Properties:     
    day(*)
    month(*)
    year
    hour
    minute
    second
    week_day(*)

Properties are new in python 2.2, they allow us to assign assessors
methods to an attribute.
That mean that: 
    - x.day = value will call something like  x.set_day(value)
    - value = x.day will call value = x.get_day()
    
All of this properties return always a valid number, but can accept
and process values that are not in the good range. This will allow
powerful constructs like x.day += 10

(*) Theses properties use int as input but return a subtype of int
that provide the following methods:
        -name()    for sample 'monday' or 'january' 
        -short_name() for sample 'mon' or 'jan'
    

[???] What must be the behavior of x.week_day = Monday :
          - fix the day to the Monday of the current week
          - fix the day to the nearest Monday
          - or to the next (or previous) Monday

[???] The returned value could maybe provide more functions for
sample:
          x.month.length() could return the length of the month
          x.year.leap_year()
          x.day.year_count() n° of the day in the year
      But I think we can live without this for the moment.
    
[???] Should we append a week property for dealing with num of weeks ?

  String formating:
str(format=None) : return the date as string, format is a string like
in the time.strptime function. (note: __str__ will call self.str())
    
from_str(value, format=None) : parse a string to create a date object
[???] it would me more Pythonic to use the standard constructor to
create a date object from  string. But on the over hand class
constructor is already  rather complex.

[???] It seems that the time.strptime function doesn't work well on
all platforms. Maybe that in theses case we should provide an
alternate function like in [4] And what should we do: always use the
python function or only when the C one is broken? (then how to detect
this?)

[???] should we provide a set of predefined format strings (and which
ones?)?
At least me must define the format string used when format=None (the
ISO notation?)


  localization:
Date and time format are heavily related to localization for:
        (1) daylight saving and time zone
        (2) date formatting conventions
        (3) nouns of months and days
   	
        (1) is currently handled by the time module (almost on my
computer).
        (2) is probably related to locals module but I haven't seen
something about it.
        (3) is dependant of a translation utility for python. I don't
know if they  are projects for this.

For now we could probably just handle (1). But we should be careful to
allow us to adopt (2) and (3) later without breaking user code.


Backward compatibility issues:

All of this can be written in pure python in a standalone module. So I
don't note any compatibility problems directly related to this PEP.
Since the date  class use properties, class methods and built-in types
inheritance, it will need Python 2.2.

There is probably some changes to do in standard library to really fit
the date classes. For sample the date objects currently returned by
python modules could support the MJD() method. But this is out of the
scope of this PEP.


References

    [1] Calendar FAQ   
        http://www.tondering.dk/claus/calendar.html

    [2] NormalDate module for Python
        http://starship.python.net/crew/jbauer/normaldate/

    [3] mxDateTime module for Python
        http://www.lemburg.com/files/python/mxDateTime.html

    [4] strptime implementation in Python
        http://www.fukt.hk-r.se/~flognat/hacks/strptime.py

    [5] The julian day number
        http://serendipity.magnet.ch/hermetic/cal_stud/jdn.htm


Copyright

    This document has been placed in the public domain.


Local Variables:
mode: indented-text
indent-tabs-mode: nil
fill-column: 70
End:



More information about the Python-list mailing list