summaryrefslogtreecommitdiff
path: root/django/utils/dateformat.py
diff options
context:
space:
mode:
authorWarren Smith <warren@wandrsmith.net>2013-07-02 17:19:56 -0500
committerWarren Smith <warren@wandrsmith.net>2013-08-26 16:15:53 -0500
commitdd3a883894a219bc6c69e556c694734ab82b33e9 (patch)
tree3d78ae088cc8b4f7a848d4a1f03b6e1b4a9c08fd /django/utils/dateformat.py
parentfa572666998bf5dc70d15ec9386d5d3692b264f2 (diff)
Fixed #20693 -- Add timezone support to built-in time filter.
Modified django.utils.dateformat module, moving __init__() method and timezone-related format methods from DateFormat class to TimeFormat base class. Modified timezone-related format methods to return an empty string when timezone is inappropriate for input value.
Diffstat (limited to 'django/utils/dateformat.py')
-rw-r--r--django/utils/dateformat.py133
1 files changed, 82 insertions, 51 deletions
diff --git a/django/utils/dateformat.py b/django/utils/dateformat.py
index 6d0a7b63f7..fbf299631b 100644
--- a/django/utils/dateformat.py
+++ b/django/utils/dateformat.py
@@ -38,8 +38,19 @@ class Formatter(object):
return ''.join(pieces)
class TimeFormat(Formatter):
- def __init__(self, t):
- self.data = t
+
+ def __init__(self, obj):
+ self.data = obj
+ self.timezone = None
+
+ # We only support timezone when formatting datetime objects,
+ # not date objects (timezone information not appropriate),
+ # or time objects (against established django policy).
+ if isinstance(obj, datetime.datetime):
+ if is_naive(obj):
+ self.timezone = LocalTimezone(obj)
+ else:
+ self.timezone = obj.tzinfo
def a(self):
"'a.m.' or 'p.m.'"
@@ -57,6 +68,25 @@ class TimeFormat(Formatter):
"Swatch Internet time"
raise NotImplementedError
+ def e(self):
+ """
+ Timezone name.
+
+ If timezone information is not available, this method returns
+ an empty string.
+ """
+ if not self.timezone:
+ return ""
+
+ try:
+ if hasattr(self.data, 'tzinfo') and self.data.tzinfo:
+ # Have to use tzinfo.tzname and not datetime.tzname
+ # because datatime.tzname does not expect Unicode
+ return self.data.tzinfo.tzname(self.data) or ""
+ except NotImplementedError:
+ pass
+ return ""
+
def f(self):
"""
Time, in 12-hour hours and minutes, with minutes left off if they're
@@ -92,6 +122,21 @@ class TimeFormat(Formatter):
"Minutes; i.e. '00' to '59'"
return '%02d' % self.data.minute
+ def O(self):
+ """
+ Difference to Greenwich time in hours; e.g. '+0200', '-0430'.
+
+ If timezone information is not available, this method returns
+ an empty string.
+ """
+ if not self.timezone:
+ return ""
+
+ seconds = self.Z()
+ sign = '-' if seconds < 0 else '+'
+ seconds = abs(seconds)
+ return "%s%02d%02d" % (sign, seconds // 3600, (seconds // 60) % 60)
+
def P(self):
"""
Time, in 12-hour hours, minutes and 'a.m.'/'p.m.', with minutes left off
@@ -109,24 +154,48 @@ class TimeFormat(Formatter):
"Seconds; i.e. '00' to '59'"
return '%02d' % self.data.second
+ def T(self):
+ """
+ Time zone of this machine; e.g. 'EST' or 'MDT'.
+
+ If timezone information is not available, this method returns
+ an empty string.
+ """
+ if not self.timezone:
+ return ""
+
+ name = self.timezone.tzname(self.data) if self.timezone else None
+ if name is None:
+ name = self.format('O')
+ return six.text_type(name)
+
def u(self):
"Microseconds; i.e. '000000' to '999999'"
return '%06d' %self.data.microsecond
+ def Z(self):
+ """
+ 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 is
+ always positive.
+
+ If timezone information is not available, this method returns
+ an empty string.
+ """
+ if not self.timezone:
+ return ""
+
+ offset = self.timezone.utcoffset(self.data)
+ # `offset` is a datetime.timedelta. For negative values (to the west of
+ # UTC) only days can be negative (days=-1) and seconds are always
+ # positive. e.g. UTC-1 -> timedelta(days=-1, seconds=82800, microseconds=0)
+ # Positive offsets have days=0
+ return offset.days * 86400 + offset.seconds
+
class DateFormat(TimeFormat):
year_days = [None, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]
- def __init__(self, dt):
- # Accepts either a datetime or date object.
- self.data = dt
- self.timezone = None
- if isinstance(dt, datetime.datetime):
- if is_naive(dt):
- self.timezone = LocalTimezone(dt)
- else:
- self.timezone = dt.tzinfo
-
def b(self):
"Month, textual, 3 letters, lowercase; e.g. 'jan'"
return MONTHS_3[self.data.month]
@@ -146,17 +215,6 @@ class DateFormat(TimeFormat):
"Day of the week, textual, 3 letters; e.g. 'Fri'"
return WEEKDAYS_ABBR[self.data.weekday()]
- def e(self):
- "Timezone name if available"
- try:
- if hasattr(self.data, 'tzinfo') and self.data.tzinfo:
- # Have to use tzinfo.tzname and not datetime.tzname
- # because datatime.tzname does not expect Unicode
- return self.data.tzinfo.tzname(self.data) or ""
- except NotImplementedError:
- pass
- return ""
-
def E(self):
"Alternative month names as required by some locales. Proprietary extension."
return MONTHS_ALT[self.data.month]
@@ -204,13 +262,6 @@ class DateFormat(TimeFormat):
"ISO 8601 year number matching the ISO week number (W)"
return self.data.isocalendar()[0]
- def O(self):
- "Difference to Greenwich time in hours; e.g. '+0200', '-0430'"
- seconds = self.Z()
- sign = '-' if seconds < 0 else '+'
- seconds = abs(seconds)
- return "%s%02d%02d" % (sign, seconds // 3600, (seconds // 60) % 60)
-
def r(self):
"RFC 2822 formatted date; e.g. 'Thu, 21 Dec 2000 16:01:07 +0200'"
return self.format('D, j M Y H:i:s O')
@@ -232,13 +283,6 @@ class DateFormat(TimeFormat):
"Number of days in the given month; i.e. '28' to '31'"
return '%02d' % calendar.monthrange(self.data.year, self.data.month)[1]
- def T(self):
- "Time zone of this machine; e.g. 'EST' or 'MDT'"
- name = self.timezone.tzname(self.data) if self.timezone else None
- if name is None:
- name = self.format('O')
- return six.text_type(name)
-
def U(self):
"Seconds since the Unix epoch (January 1 1970 00:00:00 GMT)"
if isinstance(self.data, datetime.datetime) and is_aware(self.data):
@@ -291,26 +335,13 @@ class DateFormat(TimeFormat):
doy += 1
return doy
- def Z(self):
- """
- 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 is
- always positive.
- """
- if not self.timezone:
- return 0
- offset = self.timezone.utcoffset(self.data)
- # `offset` is a datetime.timedelta. For negative values (to the west of
- # UTC) only days can be negative (days=-1) and seconds are always
- # positive. e.g. UTC-1 -> timedelta(days=-1, seconds=82800, microseconds=0)
- # Positive offsets have days=0
- return offset.days * 86400 + offset.seconds
def format(value, format_string):
"Convenience function"
df = DateFormat(value)
return df.format(format_string)
+
def time_format(value, format_string):
"Convenience function"
tf = TimeFormat(value)