Fixed #479 -- Implemented time-zone formats in dateformat. Thanks, Sune

git-svn-id: http://code.djangoproject.com/svn/django/trunk@992 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Adrian Holovaty 2005-10-22 21:37:59 +00:00
parent f82e64c6b2
commit 17f62269c2
5 changed files with 175 additions and 18 deletions

View File

@ -12,8 +12,9 @@ Usage:
""" """
from django.utils.dates import MONTHS, MONTHS_AP, WEEKDAYS from django.utils.dates import MONTHS, MONTHS_AP, WEEKDAYS
from django.utils.tzinfo import LocalTimezone
from calendar import isleap from calendar import isleap
import re import re, time
re_formatchars = re.compile(r'(?<!\\)([aABdDfFgGhHiIjlLmMnNOPrsStTUwWyYzZ])') re_formatchars = re.compile(r'(?<!\\)([aABdDfFgGhHiIjlLmMnNOPrsStTUwWyYzZ])')
re_escaped = re.compile(r'\\(.)') re_escaped = re.compile(r'\\(.)')
@ -40,7 +41,9 @@ class TimeFormat(Formatter):
def A(self): def A(self):
"'AM' or 'PM'" "'AM' or 'PM'"
return self.a().upper() if self.data.hour > 11:
return 'PM'
return 'AM'
def B(self): def B(self):
"Swatch Internet time" "Swatch Internet time"
@ -100,8 +103,12 @@ class TimeFormat(Formatter):
class DateFormat(TimeFormat): class DateFormat(TimeFormat):
year_days = [None, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334] year_days = [None, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]
def __init__(self, d): def __init__(self, dt):
self.data = d # Accepts either a datetime or date object.
self.data = dt
self.timezone = getattr(dt, 'tzinfo', None)
if hasattr(self.data, 'hour') and not self.timezone:
self.timezone = LocalTimezone(dt)
def d(self): def d(self):
"Day of the month, 2 digits with leading zeros; i.e. '01' to '31'" "Day of the month, 2 digits with leading zeros; i.e. '01' to '31'"
@ -119,6 +126,13 @@ class DateFormat(TimeFormat):
"'1' if Daylight Savings Time, '0' otherwise." "'1' if Daylight Savings Time, '0' otherwise."
raise NotImplementedError raise NotImplementedError
def I(self):
"'1' if Daylight Savings Time, '0' otherwise."
if self.timezone.dst(self.data):
return '1'
else:
return '0'
def j(self): def j(self):
"Day of the month without leading zeros; i.e. '1' to '31'" "Day of the month without leading zeros; i.e. '1' to '31'"
return self.data.day return self.data.day
@ -149,11 +163,12 @@ class DateFormat(TimeFormat):
def O(self): def O(self):
"Difference to Greenwich time in hours; e.g. '+0200'" "Difference to Greenwich time in hours; e.g. '+0200'"
raise NotImplementedError tz = self.timezone.utcoffset(self.data)
return "%+03d%02d" % (tz.seconds // 3600, (tz.seconds // 60) % 60)
def r(self): def r(self):
"RFC 822 formatted date; e.g. 'Thu, 21 Dec 2000 16:01:07 +0200'" "RFC 822 formatted date; e.g. 'Thu, 21 Dec 2000 16:01:07 +0200'"
raise NotImplementedError return self.format('D, j M Y H:i:s O')
def S(self): def S(self):
"English ordinal suffix for the day of the month, 2 characters; i.e. 'st', 'nd', 'rd' or 'th'" "English ordinal suffix for the day of the month, 2 characters; i.e. 'st', 'nd', 'rd' or 'th'"
@ -174,11 +189,15 @@ class DateFormat(TimeFormat):
def T(self): def T(self):
"Time zone of this machine; e.g. 'EST' or 'MDT'" "Time zone of this machine; e.g. 'EST' or 'MDT'"
raise NotImplementedError name = self.timezone.tzname(self.data)
if name is None:
name = self.format('O')
return name
def U(self): def U(self):
"Seconds since the Unix epoch (January 1 1970 00:00:00 GMT)" "Seconds since the Unix epoch (January 1 1970 00:00:00 GMT)"
raise NotImplementedError off = self.timezone.utcoffset(self.data)
return int(time.mktime(self.data.timetuple())) + off.seconds * 60
def w(self): def w(self):
"Day of the week, numeric, i.e. '0' (Sunday) to '6' (Saturday)" "Day of the week, numeric, i.e. '0' (Sunday) to '6' (Saturday)"
@ -229,7 +248,7 @@ class DateFormat(TimeFormat):
"""Time zone offset in seconds (i.e. '-43200' to '43200'). The offset """Time zone offset in seconds (i.e. '-43200' to '43200'). The offset
for timezones west of UTC is always negative, and for those east of UTC for timezones west of UTC is always negative, and for those east of UTC
is always positive.""" is always positive."""
raise NotImplementedError return self.timezone.utcoffset(self.data).seconds
def format(value, format_string): def format(value, format_string):
"Convenience function" "Convenience function"

View File

@ -1,4 +1,5 @@
import time, math, datetime import datetime, math, time
from django.utils.tzinfo import LocalTimezone
def timesince(d, now=None): def timesince(d, now=None):
""" """
@ -6,7 +7,6 @@ def timesince(d, now=None):
as a nicely formatted string, e.g "10 minutes" as a nicely formatted string, e.g "10 minutes"
Adapted from http://blog.natbat.co.uk/archive/2003/Jun/14/time_since Adapted from http://blog.natbat.co.uk/archive/2003/Jun/14/time_since
""" """
original = time.mktime(d.timetuple())
chunks = ( chunks = (
(60 * 60 * 24 * 365, 'year'), (60 * 60 * 24 * 365, 'year'),
(60 * 60 * 24 * 30, 'month'), (60 * 60 * 24 * 30, 'month'),
@ -14,9 +14,17 @@ def timesince(d, now=None):
(60 * 60, 'hour'), (60 * 60, 'hour'),
(60, 'minute') (60, 'minute')
) )
if not now: if now:
now = time.time() t = time.mktime(now)
since = now - original else:
t = time.localtime()
if d.tzinfo:
tz = LocalTimezone()
else:
tz = None
now = datetime.datetime(t[0], t[1], t[2], t[3], t[4], t[5], tzinfo=tz)
delta = now - d
since = delta.days * 24 * 60 * 60 + delta.seconds
# Crazy iteration syntax because we need i to be current index # Crazy iteration syntax because we need i to be current index
for i, (seconds, name) in zip(range(len(chunks)), chunks): for i, (seconds, name) in zip(range(len(chunks)), chunks):
count = math.floor(since / seconds) count = math.floor(since / seconds)

52
django/utils/tzinfo.py Normal file
View File

@ -0,0 +1,52 @@
"Implementation of tzinfo classes for use with datetime.datetime."
import time
from datetime import timedelta, tzinfo
class FixedOffset(tzinfo):
"Fixed offset in minutes east from UTC."
def __init__(self, offset):
self.__offset = timedelta(minutes=offset)
self.__name = "%+03d%02d" % (offset // 60, offset % 60)
def __repr__(self):
return self.__name
def utcoffset(self, dt):
return self.__offset
def tzname(self, dt):
return self.__name
def dst(self, dt):
return timedelta(0)
class LocalTimezone(tzinfo):
"Proxy timezone information from time module."
def __init__(self, dt):
tzinfo.__init__(self, dt)
self._tzname = time.tzname[self._isdst(dt)]
def __repr__(self):
return self._tzname
def utcoffset(self, dt):
if self._isdst(dt):
return timedelta(seconds=-time.altzone)
else:
return timedelta(seconds=-time.timezone)
def dst(self, dt):
if self._isdst(dt):
return timedelta(seconds=-time.altzone) - timedelta(seconds=-time.timezone)
else:
return timedelta(0)
def tzname(self, dt):
return time.tzname[self._isdst(dt)]
def _isdst(self, dt):
tt = (dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.weekday(), 0, -1)
stamp = time.mktime(tt)
tt = time.localtime(stamp)
return tt.tm_isdst > 0

View File

@ -517,18 +517,18 @@ Built-in tag reference
n Month without leading zeros. ``'1'`` to ``'12'`` n Month without leading zeros. ``'1'`` to ``'12'``
N Month abbreviation in Associated Press ``'Jan.'``, ``'Feb.'``, ``'March'``, ``'May'`` N Month abbreviation in Associated Press ``'Jan.'``, ``'Feb.'``, ``'March'``, ``'May'``
style. Proprietary extension. style. Proprietary extension.
O Not implemented. O Difference to Greenwich time in hours. ``'+0200'``
P Time, in 12-hour hours, minutes and ``'1 a.m.'``, ``'1:30 p.m.'``, ``'midnight'``, ``'noon'``, ``'12:30 p.m.'`` P Time, in 12-hour hours, minutes and ``'1 a.m.'``, ``'1:30 p.m.'``, ``'midnight'``, ``'noon'``, ``'12:30 p.m.'``
'a.m.'/'p.m.', with minutes left off 'a.m.'/'p.m.', with minutes left off
if they're zero and the special-case if they're zero and the special-case
strings 'midnight' and 'noon' if strings 'midnight' and 'noon' if
appropriate. Proprietary extension. appropriate. Proprietary extension.
r Not implemented. r RFC 822 formatted date. ``'Thu, 21 Dec 2000 16:01:07 +0200'``
s Seconds, 2 digits with leading zeros. ``'00'`` to ``'59'`` s Seconds, 2 digits with leading zeros. ``'00'`` to ``'59'``
S English ordinal suffix for day of the ``'st'``, ``'nd'``, ``'rd'`` or ``'th'`` S English ordinal suffix for day of the ``'st'``, ``'nd'``, ``'rd'`` or ``'th'``
month, 2 characters. month, 2 characters.
t Not implemented. t Not implemented.
T Not implemented. T Time zone of this machine. ``'EST'``, ``'MDT'``
U Not implemented. U Not implemented.
w Day of the week, digits without ``'0'`` (Sunday) to ``'6'`` (Saturday) w Day of the week, digits without ``'0'`` (Sunday) to ``'6'`` (Saturday)
leading zeros. leading zeros.
@ -537,7 +537,10 @@ Built-in tag reference
y Year, 2 digits. ``'99'`` y Year, 2 digits. ``'99'``
Y Year, 4 digits. ``'1999'`` Y Year, 4 digits. ``'1999'``
z Day of the year. ``0`` to ``365`` z Day of the year. ``0`` to ``365``
Z Not implemented. Z Time zone offset in seconds. The ``-43200`` to ``43200``
offset for timezones west of UTC is
always negative, and for those east of
UTC is always positive.
================ ====================================== ===================== ================ ====================================== =====================
Example:: Example::

View File

@ -0,0 +1,75 @@
"""
>>> format(my_birthday, '')
''
>>> format(my_birthday, 'a')
'p.m.'
>>> format(my_birthday, 'A')
'PM'
>>> format(my_birthday, 'j')
'7'
>>> format(my_birthday, 'l')
'Saturday'
>>> format(my_birthday, 'L')
'False'
>>> format(my_birthday, 'm')
'07'
>>> format(my_birthday, 'M')
'Jul'
>>> format(my_birthday, 'n')
'7'
>>> format(my_birthday, 'N')
'July'
>>> format(my_birthday, 'O')
'+0100'
>>> format(my_birthday, 'P')
'10 p.m.'
>>> format(my_birthday, 'r')
'Sat, 7 Jul 1979 22:00:00 +0100'
>>> format(my_birthday, 's')
'00'
>>> format(my_birthday, 'S')
'th'
>>> format(my_birthday, 't')
Traceback (most recent call last):
...
NotImplementedError
>>> format(my_birthday, 'T')
'CET'
>>> format(my_birthday, 'U')
'300445200'
>>> format(my_birthday, 'w')
'6'
>>> format(my_birthday, 'W')
'27'
>>> format(my_birthday, 'y')
'79'
>>> format(my_birthday, 'Y')
'1979'
>>> format(my_birthday, 'z')
'188'
>>> format(my_birthday, 'Z')
'3600'
>>> format(summertime, 'I')
'1'
>>> format(summertime, 'O')
'+0200'
>>> format(wintertime, 'I')
'0'
>>> format(wintertime, 'O')
'+0100'
>>> format(my_birthday, 'Y z \\C\\E\\T')
'1979 188 CET'
"""
from django.utils import dateformat
format = dateformat.format
import datetime, os, time
os.environ['TZ'] = 'Europe/Copenhagen'
time.tzset()
my_birthday = datetime.datetime(1979, 7, 7, 22, 00)
summertime = datetime.datetime(2005, 10, 30, 1, 00)
wintertime = datetime.datetime(2005, 10, 30, 4, 00)