Am I asking too much from datetime?

Robert Brewer fumanchu at amor.org
Tue Jun 1 17:34:41 CEST 2004


thehaas at binary.net wrote:
> I'm trying to use the datetime module.  The following seems to work
> any day except the first day of the month:
> 
> >>> import datetime
> >>> today = datetime.date.today()
> >>> print today
> 2004-06-01
> >>> yesterday = datetime.date(today.year, today.month, today.day-1)
> Traceback (most recent call last):
>   File "<stdin>", line 1, in ?
> ValueError: day is out of range for month
> 
> In other languages (specifically Java, but I'm sure these are others),
> this would come out as "2004-05-31".
> 
> Is this is a bug, or outside of the functionality of datetime?

As Yermat pointed out, it's "outside the functionality". But you can
easily write your own wrapper for that behavior. This is an excerpt from
my "recur" module at: http://www.aminus.org/rbre/python


def sane_date(year, month, day, fixMonth=False):
    """Return a valid datetime.date even if parameters are out of
bounds.
    
    If the month param is out of bounds, both it and the year will
    be modified. If negative, the year will be decremented.
    
    If fixMonth is False, and the day param is out of bounds, both the
    day param and the month will be modified.
    
    If fixMonth is True, and the day param is out of bounds, the month
    will not change, and the day will be set to the appropriate
boundary.
    The month may still, however, modify the year.
    
    Examples:
        sane_date(2003, 2, 1) = datetime.date(2003, 2, 1)
        sane_date(2003, -10, 13) = datetime.date(2002, 2, 13)
        sane_date(2003, 12, -5) = datetime.date(2003, 11, 25)
        sane_date(2003, 1, 35, True) = datetime.date(2003, 1, 31)
    """
    while month > 12:
        month -= 12
        year += 1
    while month < 1:
        month += 12
        year -= 1
    if fixMonth:
        if day < 1:
            newDate = datetime.date(year, month, 1)
        else:
            while True:
                try:
                    newDate = datetime.date(year, month, day)
                except ValueError:
                    day -= 1
                    if day < 1:
                        raise ValueError("A valid day for month: %s in "
                                         "year: %s could not be found",
                                         (month, year))
                else:
                    break
    else:
        if day < 1:
            # Count backward from the end of the current month.
            firstOfMonth = sane_date(year, month + 1, 1)
        else:
            # Count forward from the first of the current month.
            firstOfMonth = datetime.date(year, month, 1)
        newDate = (firstOfMonth + datetime.timedelta(day - 1))
    return newDate

def sane_time(day, hour, minute, second):
    """Return a valid (day, datetime.time) even if parameters are out of
bounds.
    
    If the hour param is out of bounds, both it and the day will
    be modified. If negative, the day will be decremented.
    
    If the minute param is out of bounds, both it and the hour will
    be modified. If negative, the hour will be decremented.
    
    If the second param is out of bounds, both it and the minute will
    be modified. If negative, the minute will be decremented.
    
    Examples:
        sane_time(0, 4, 2, 1) = (0, datetime.time(4, 2, 1)
        sane_time(0, 25, 2, 1) = (1, datetime.time(1, 2, 1)
        sane_time(0, 4, 1440, 1) = (1, datetime.time(4, 2, 1)
        sane_time(0, 0, 0, -1) = (-1, datetime.time(23, 59, 59)
    """
    while second > 59:
        second -= 60
        minute += 1
    while second < 0:
        second += 60
        minute -= 1
    while minute > 59:
        minute -= 60
        hour += 1
    while minute < 0:
        minute += 60
        hour -= 1
    while hour > 23:
        hour -= 24
        day += 1
    while hour < 0:
        hour += 24
        day -= 1
    newTime = (day, datetime.time(hour, minute, second))
    return newTime


Hope that helps,

Robert Brewer
MIS
Amor Ministries
fumanchu at amor.org




More information about the Python-list mailing list