date = date_.today()
elif isinstance(date, datetime):
date = date.date()
+
locale = Locale.parse(locale)
if format in ('full', 'long', 'medium', 'short'):
format = get_date_format(format, locale=locale)
pattern = parse_pattern(format)
return parse_pattern(format).apply(date, locale)
-def format_datetime(datetime=None, format='medium', tzinfo=UTC, locale=LC_TIME):
+def format_datetime(datetime=None, format='medium', tzinfo=None,
+ locale=LC_TIME):
"""Returns a date formatted according to the given pattern.
>>> dt = datetime(2007, 04, 01, 15, 30)
>>> format_datetime(dt, locale='en_US')
u'Apr 1, 2007 3:30:00 PM'
+ For any pattern requiring the display of the time-zone, the third-party
+ ``pytz`` package is needed to explicitly specify the time-zone:
+
+ >>> from pytz import timezone
+ >>> format_datetime(dt, 'full', tzinfo=timezone('Europe/Berlin'),
+ ... locale='de_DE')
+ u'Sonntag, 1. April 2007 17:30 Uhr MESZ'
+ >>> format_datetime(dt, "yyyy.MM.dd G 'at' HH:mm:ss zzz",
+ ... tzinfo=timezone('US/Eastern'), locale='en')
+ u'2007.04.01 AD at 11:30:00 EDT'
+
:param datetime: the `datetime` object; if `None`, the current date and
time is used
:param format: one of "full", "long", "medium", or "short", or a custom
"""
if datetime is None:
datetime = datetime_.now()
+ elif isinstance(datetime, (int, long)):
+ datetime = datetime.fromtimestamp(datetime)
+ elif isinstance(datetime, time):
+ datetime = datetime_.combine(date.today(), datetime)
+ if datetime.tzinfo is None:
+ datetime = datetime.replace(tzinfo=UTC)
+ if tzinfo is not None:
+ datetime = datetime.astimezone(tzinfo)
+ if hasattr(tzinfo, 'normalize'):
+ datetime = tzinfo.normalize(datetime)
+
locale = Locale.parse(locale)
if format in ('full', 'long', 'medium', 'short'):
return get_datetime_format(format, locale=locale) \
- .replace('{0}', format_time(datetime, format, tzinfo=tzinfo,
+ .replace('{0}', format_time(datetime, format, tzinfo=None,
locale=locale)) \
.replace('{1}', format_date(datetime, format, locale=locale))
else:
return parse_pattern(format).apply(datetime, locale)
-def format_time(time=None, format='medium', tzinfo=UTC, locale=LC_TIME):
+def format_time(time=None, format='medium', tzinfo=None, locale=LC_TIME):
"""Returns a time formatted according to the given pattern.
>>> t = time(15, 30)
For any pattern requiring the display of the time-zone, the third-party
``pytz`` package is needed to explicitly specify the time-zone:
- >>> from pytz import timezone
- >>> cet = timezone('Europe/Berlin')
- >>> format_time(t, format='full', tzinfo=cet, locale='de_DE')
- u'15:30 Uhr MEZ'
+ >>> from pytz import timezone, utc
+ >>> t = time(15, 30, tzinfo=utc)
+ >>> format_time(t, format='full', tzinfo=timezone('Europe/Berlin'),
+ ... locale='de_DE')
+ u'17:30 Uhr MESZ'
+ >>> format_time(t, "hh 'o''clock' a, zzzz", tzinfo=timezone('US/Eastern'),
+ ... locale='en')
+ u"11 o'clock AM, Eastern Daylight Time"
:param time: the ``time`` or ``datetime`` object; if `None`, the current
time is used
elif isinstance(time, (int, long)):
time = datetime.fromtimestamp(time).time()
elif isinstance(time, datetime):
- time = time.time()
+ time = time.timetz()
if time.tzinfo is None:
- time = time.replace(tzinfo=tzinfo)
+ time = time.replace(tzinfo=UTC)
+ if tzinfo is not None:
+ dt = datetime.combine(date.today(), time).astimezone(tzinfo)
+ if hasattr(tzinfo, 'normalize'):
+ dt = tzinfo.normalize(dt)
+ time = dt.timetz()
+
locale = Locale.parse(locale)
if format in ('full', 'long', 'medium', 'short'):
format = get_time_format(format, locale=locale)
def format_timezone(self, char, num):
if char == 'z':
- zone = self.value.tzinfo.zone
- if num < 4:
- return self.locale.time_zones[zone]['short'][
- self.value.dst() and 'daylight' or 'standard'
- ]
+ if hasattr(self.value.tzinfo, 'zone'):
+ zone = self.value.tzinfo.zone
+ else:
+ zone = self.value.tzinfo.tzname(self.value)
+
+ # Get the canonical time-zone code
+ zone = self.locale.zone_aliases.get(zone, zone)
+
+ # Try explicitly translated zone names first
+ display = self.locale.time_zones.get(zone)
+ if display:
+ if 'long' in display:
+ width = {3: 'short', 4: 'long'}[max(3, num)]
+ dst = self.value.dst() and 'daylight' or 'standard'
+ return display[width][dst]
+ elif 'city' in display:
+ return display['city']
+
else:
- return self.locale.time_zones[zone]['long'][
- self.value.dst() and 'daylight' or 'standard'
- ]
+ return zone.split('/', 1)[1]
elif char == 'Z':
offset = self.value.utcoffset()
- hours, seconds = divmod(offset.seconds, 3600)
- minutes = seconds // 60
- sign = '+'
- if offset.seconds < 0:
- sign = '-'
- pattern = {3: '%s%02d%02d', 4: 'GMT %s%02d:%02d'}[max(3, num)]
- return pattern % (sign, hours, minutes)
+ seconds = offset.days * 24 * 60 * 60 + offset.seconds
+ hours, seconds = divmod(seconds, 3600)
+ pattern = {3: '%+03d%02d', 4: 'GMT %+03d:%02d'}[max(3, num)]
+ return pattern % (hours, seconds // 60)
elif char == 'v':
raise NotImplementedError
reliably converting from UTC to local time, and vice versa::
>>> from datetime import time
- >>> t = time(15, 30)
-
- >>> from pytz import timezone
- >>> cet = timezone('Europe/Berlin')
- >>> format_time(t, 'H:mm Z', tzinfo=cet, locale='de_DE')
- u'15:30 +0100'
+ >>> from pytz import timezone, utc
+ >>> dt = datetime(2007, 04, 01, 15, 30, tzinfo=utc)
+ >>> eastern = timezone('US/Eastern')
+ >>> format_datetime(dt, 'H:mm Z', tzinfo=eastern, locale='en_US')
+ u'11:30 -0400'
The recommended approach to deal with different time-zones in a Python
application is to always use UTC internally, and only convert from/to the users
time-zone when accepting user input and displaying date/time data, respectively.
+You can use Babel together with ``pytz`` to apply a time-zone to any
+``datetime`` or ``time`` object for display, leaving the original information
+unchanged::
- .. _`pytz`: http://pytz.sourceforge.net/
+ >>> british = timezone('Europe/London')
+ >>> format_datetime(dt, 'H:mm zzzz', tzinfo=british, locale='en_US')
+ u'16:30 British Summer Time'
+ .. _`pytz`: http://pytz.sourceforge.net/
Parsing Dates
Babel can also parse numeric data in a locale-sensitive manner::
- >>> from babel.dates import parse_decimal, parse_number
+ >>> from babel.numbers import parse_decimal, parse_number
Examples::