views:

1940

answers:

4

Is there a fairly easy way to convert a datetime object into an RFC 1123 (HTTP/1.1) date/time string, i.e. a string with the format

Sun, 06 Nov 1994 08:49:37 GMT

Using strftime does not work, since the strings are locale-dependant. Do I have to build the string by hand?

+1  A: 

You can set LC_TIME to force stftime() to use a specific locale:

>>> locale.setlocale(locale.LC_TIME, 'en_US')
'en_US'
>>> datetime.datetime.now().strftime(locale.nl_langinfo(locale.D_T_FMT))
'Wed 22 Oct 2008 06:05:39 AM '
Ignacio Vazquez-Abrams
Well, setting (and resetting) locale.LC_TIME works, of course, but this has disadvantages, like most likely not being thread-safe, and depending on the catalog of string translations. Also, locale.D_T_FMT does not return the right format with LC_TIME set to en_US.
Sebastian Rittau
locale.D_T_FMT was merely an example. You can pass any format you like to strftime().
Ignacio Vazquez-Abrams
+13  A: 

You can use wsgiref.handlers.format_date_time from the stdlib which does not rely on locale settings

from wsgiref.handlers import format_date_time
from datetime import datetime
from time import mktime

now = datetime.now()
stamp = mktime(now.timetuple())
print format_date_time(stamp) #--> Wed, 22 Oct 2008 10:52:40 GMT

You can use email.utils.formatdate from the stdlib which does not rely on locale settings

from email.utils import formatdate
from datetime import datetime
from time import mktime

now = datetime.now()
stamp = mktime(now.timetuple())
print formatdate(
    timeval     = stamp,
    localtime   = False,
    usegmt      = True
) #--> Wed, 22 Oct 2008 10:55:46 GMT

If you can set the locale process wide then you can do:

import locale, datetime

locale.setlocale(locale.LC_TIME, 'en_US')
datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')

If you don't want to set the locale process wide you could use Babel date formating

from datetime import datetime
from babel.dates import format_datetime

now = datetime.utcnow()
format = 'EEE, dd LLL yyyy hh:mm:ss'
print format_datetime(now, format, locale='en') + ' GMT'

A manual way to format it which is identical with wsgiref.handlers.format_date_time is:

def httpdate(dt):
    """Return a string representation of a date according to RFC 1123
    (HTTP/1.1).

    The supplied date must be in UTC.

    """
    weekday = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"][dt.weekday()]
    month = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
             "Oct", "Nov", "Dec"][dt.month - 1]
    return "%s, %02d %s %04d %02d:%02d:%02d GMT" % (weekday, dt.day, month,
        dt.year, dt.hour, dt.minute, dt.second)
Florian Bösch
This solution won't work for the reason outlined in the question: stftime is locale-dependant.
Sebastian Rittau
that's why you ocale.setlocale(locale.LC_TIME, 'en_US')
Florian Bösch
And that's why SO needs an indicator of when answers were edited.
Ignacio Vazquez-Abrams
that'd be a good idea
Florian Bösch
@Sebastian: which of the many good solutions did you select as "best"?
Ber
They are all good solutions, depending on what you want to achieve. For example, the outside dependecies can be used when you are already using that dependency. wsgiref can be used with Python 2.5+, and the manual solution is the fall-back case.
Sebastian Rittau
+3  A: 

You can use the formatdate() function from the Python standard email module:

from email.utils import formatdate
print formatdate(timeval=None, localtime=False, usegmt=True)

Gives the current time in the desired format:

Wed, 22 Oct 2008 10:32:33 GMT

In fact, this function does it "by hand" without using strftime()

Ber
A: 

Well, here is a manual function to format it:

def httpdate(dt):
    """Return a string representation of a date according to RFC 1123
    (HTTP/1.1).

    The supplied date must be in UTC.

    """
    weekday = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"][dt.weekday()]
    month = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
             "Oct", "Nov", "Dec"][dt.month - 1]
    return "%s, %02d %s %04d %02d:%02d:%02d GMT" % (weekday, dt.day, month,
        dt.year, dt.hour, dt.minute, dt.second)
Sebastian Rittau