[Mailman-Developers] clobber_date bug

Barry A. Warsaw barry@zope.com
Fri, 9 Nov 2001 11:56:16 -0500


>>>>> "ES" == Eric Seppanen <eds@reric.net> writes:

    ES> I just noticed a small bug.  On an active list, I turned on
    ES> the clobber_date setting (to apply the "resent" time to
    ES> messages stored in the archives), and I noticed that it messed
    ES> up the order of a bunch of messages in the archive.

    ES> The reason is that clobber_date doesn't put the timezone
    ES> information in the Date: field.  So it looks as though the
    ES> messages are dated GMT instead of GMT-6, and the messages from
    ES> this morning appear after those from the afternoon.

You're right that in Mailman 2.0.x, time.ctime() is used and that
simply doesn't produce a proper RFC 2822 date.

In Mailman 2.1 however, we use email.Utils.formatdate() which is
supposed to produce a valid RFC 2822 date, homed at GMT.  However, I
realized that with email-0.94, email.Utils.formatdate() is simply an
alias for rfc822.formatdate(), and the latter has not been updated to
RFC 2822.  Although legal, rfc822.formatdate() produces dates with
obs-zone (obsolete zone designations, e.g. GMT) instead of the now
preferred numeric offsets from -0000.

So while MM2.1's clobber_date code should be technically correct, I
think it would be better to update email.Utils.formatdate().  Below is
what I plan on checking into CVS.

Note that this adds an optional argument `localtime' which formats the
date based on the local timezone's daylight savings time information.
For backwards compatibility, we use -0000 by default.  Also, in MM2.1
I plan on leaving clobber_date to use -0000.

-Barry

-------------------- snip snip --------------------
def formatdate(timeval=None, localtime=0):
    """Returns a formatted time as specified by RFC 2822, e.g.:

    Fri, 09 Nov 2001 01:08:47 -0000

    Optional timeval if given is a float time as accepted by localtime() or
    gmtime().  Optional localtime is a flag that when true, interprets and
    returns a time relative to the local timezone instead of UTC.
    """
    # Note: we cannot use strftime() because that honors the locale and RFC
    # 2822 requires that day and month names be the English abbreviations.
    if timeval is None:
        timeval = time.time()
    if localtime:
        now = time.localtime(timeval)
        # Calculate timezone offset, based on whether the local zone has
        # daylight savings time, and whether DST is in effect.
        if time.daylight and now[-1]:
            offset = time.altzone
        else:
            offset = time.timezone
        zone = '%+03d%02d' % (offset / -3600, offset % 60)
    else:
        now = time.gmtime(timeval)
        # Timezone offset is always -0000
        zone = '-0000'
    return '%s, %02d %s %04d %02d:%02d:%02d %s' % (
        ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'][now[6]],
        now[2],
        ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
         'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][now[1] - 1],
        now[0], now[3], now[4], now[5],
        zone)