Mailing List Archive

rfc822 date header
Is there a reasonably bulletproof way to generate an
rfc822-compliant date header using the time module?

The reason I ask is I recall a number of subtle
errors in this regard, reported by Chris Lawrence,
among others.

-Jeff Bauer
rfc822 date header [ In reply to ]
Jeff Bauer wrote:
>
> Is there a reasonably bulletproof way to generate an
> rfc822-compliant date header using the time module?
>
> The reason I ask is I recall a number of subtle
> errors in this regard, reported by Chris Lawrence,
> among others.

According to the RFC, time.ctime() should do the trick...
but it's probably locale aware which the RFC doesn't account
for.

A better way is to use the ARPA submodule in mxDateTime:

http://starship.skyport.net/~lemburg/mxDateTime.html

...even if it's just for looking up the string format ;-)

--
Marc-Andre Lemburg Y2000: 262 days left
---------------------------------------------------------------------
: Python Pages >>> http://starship.skyport.net/~lemburg/ :
---------------------------------------------------------
rfc822 date header [ In reply to ]
On Tue, 13 Apr 1999 07:39:45 GMT, M.-A. Lemburg <mal@lemburg.com> wrote:
>Jeff Bauer wrote:
>>
>> Is there a reasonably bulletproof way to generate an
>> rfc822-compliant date header using the time module?
>>
>> The reason I ask is I recall a number of subtle
>> errors in this regard, reported by Chris Lawrence,
>> among others.

[Eeek! I'm famous!]

>According to the RFC, time.ctime() should do the trick...
>but it's probably locale aware which the RFC doesn't account
>for.

time.ctime() will throw you off (it will generate Unix timestamps, which are
decidedly non-RFC-compliant in any number of ways). Try:

time.strftime('%a, %d %b %Y %H:%M:%S GMT', time.gmtime(timeval))

where timeval is a time.time() result. If you already have the tuple form,
you may need to coax it into gmt-relative tuple form first (see the tz-aware
functions in rfc822). Actually, here you're getting a GMT RFC-compliant
header, which is a subset of the universe of allowed headers, but if you're
dumping HTTP output this is what you need.

Cheap hack for other timezones (untested, ugly, but probably right):

ttuple = time.localtime(timeval)
x = time.strftime('%a, %d %b %Y %H:%M:%S ', ttuple)
if ttuple[8] == 1:
x = x + ('%04d' % (-time.altzone))
else:
x = x + ('%04d' % (-time.timezone))

Note that locales will screw up the %a (weekday) and make it
non-RFC-compliant (though whether anything in the real world will CARE is
another question entirely). You may need to bracket this with some
locale.setlocale() calls if you're using locale != "C".

Incidentally, the locale issue even affects GNU date. Try 'LC_ALL=fr_FR
date --rfc --utc' sometime on Linux ;-) I made a patch but dunno if it ever
made it upstream...

The "subtle errors" were mainly in parsing the damn things, and in Linux's
implementation of the time functions in libc6 (which drove me crazy until I
finally figured out what was going on a few weeks ago ;-).


Chris, exploring the minutae of the topic (as per clp tradition)
--
=============================================================================
| Chris Lawrence | Get your Debian 2.1 CD-ROMs |
| <quango@watervalley.net> | http://www.lordsutch.com/ |
| | |
| Grad Student, Pol. Sci. | Do you want your bank to snoop? |
| University of Mississippi | http://www.defendyourprivacy.com/ |
=============================================================================
rfc822 date header [ In reply to ]
"M.-A. Lemburg" wrote:
>
> Jeff Bauer wrote:
> >
> > Is there a reasonably bulletproof way to generate an
> > rfc822-compliant date header using the time module?
> >
> > The reason I ask is I recall a number of subtle
> > errors in this regard, reported by Chris Lawrence,
> > among others.
>
> According to the RFC, time.ctime() should do the trick...
> but it's probably locale aware which the RFC doesn't account
> for.

Which RFC are you referring to? time.ctime() output is definitely *not*
compatible with RFC822. But it should be easy enough to come up with a
time.strftime() format that does the right thing...
--
Jack Jansen | ++++ stop the execution of Mumia Abu-Jamal ++++
Jack.Jansen@oratrix.com | ++++ if you agree copy these lines to your sig ++++
www.oratrix.nl/~jack | see http://www.xs4all.nl/~tank/spg-l/sigaction.htm
rfc822 date header [ In reply to ]
>>> Is there a reasonably bulletproof way to generate an
>>> rfc822-compliant date header using the time module?

Chris,

Thanks for your response. (Also, thanks to Jack Jansen and
M.A. Lemburg for responding too.)

I'd like to lobby for a strdate() convenience method to be
added to rfc822.py, provided it's sufficiently controversial. <g>

-Jeff Bauer
rfc822 date header [ In reply to ]
Jeremy Hylton wrote:
> If you write it, I'll lobby :-).

As a first pass, we could do lots worse than Chris Lawrence's
GMT version (untested).

def strdate(self, timeval=None):
from time import gmtime, strftime, time
if timeval is None:
timeval = time()
return "Date: %s" % strftime('%a, %d %b %Y %H:%M:%S GMT',
gmtime(timeval))

-Jeff
rfc822 date header [ In reply to ]
Jack Jansen wrote:
>
> "M.-A. Lemburg" wrote:
> >
> > Jeff Bauer wrote:
> > >
> > > Is there a reasonably bulletproof way to generate an
> > > rfc822-compliant date header using the time module?
> > >
> > > The reason I ask is I recall a number of subtle
> > > errors in this regard, reported by Chris Lawrence,
> > > among others.
> >
> > According to the RFC, time.ctime() should do the trick...
> > but it's probably locale aware which the RFC doesn't account
> > for.
>
> Which RFC are you referring to? time.ctime() output is definitely *not*
> compatible with RFC822. But it should be easy enough to come up with a
> time.strftime() format that does the right thing...

Ah, sorry, I mixed up HTTP and RFC822. According to RFC 2068 (HTTP 1.1)
the result of time.asctime() is a valid date header.

Since time.ctime() is short for time.asctime(time.localtime(ticks))
it would not result in the correct value for HTTP either (:-/ second
Ooops). You'd have to use time.asctime(time.gmtime(ticks)).

Oh well. Anyway, mxDateTime does the right thing (and also allows
parsing those beasts).

Cheers,
--
Marc-Andre Lemburg Y2000: 262 days left
---------------------------------------------------------------------
: Python Pages >>> http://starship.skyport.net/~lemburg/ :
---------------------------------------------------------
rfc822 date header [ In reply to ]
jeffbauer@bigfoot.com:
> def strdate(self, timeval=None):
> from time import gmtime, strftime, time
> if timeval is None:
> timeval = time()
> return "Date: %s" % strftime('%a, %d %b %Y %H:%M:%S GMT',
> gmtime(timeval))

Here's what I wrote for Slime (thhe mailer I'm writing):

def _date_header(self):
"""Return Date header reflecting current time."""
# XXX this should probably communicate the local time zone
# somehow
t = time.gmtime(time.time())
return "Date: %s, %02d %s %04d %02d:%02d:%02d GMT\n" % \
(rfc822._daynames[t[6]],
t[2],
rfc822._monthnames[t[1]],
t[0],
t[3],
t[4],
t[5])

Note that it isn't locale dependent.

(I apologize for the bad indentation of a whole tab, I haven't got around
to implementing proper indentation support in my editor.)
rfc822 date header [ In reply to ]
Lars Wirzenius <liw@iki.fi>:
> Here's what I wrote for Slime (thhe mailer I'm writing):

How embarrassing, the code I posted doesn't work. I'm pretty sure it
did work, at some point in time, but either I misremember, or I broke
it, or the stuff within rfc822 I use changed. Never mind, here is the
new version:

def _date_header(self):
"""Return Date header reflecting current time."""
# XXX this should probably communicate the local time zone
# somehow
t = time.gmtime(time.time())
return "Date: %s, %02d %s %04d %02d:%02d:%02d GMT\n" % \
(string.capitalize(rfc822._daynames[t[6]]),
t[2],
string.capitalize(rfc822._monthnames[t[1] - 1]),
t[0],
t[3],
t[4],
t[5])