20
20
from django.utils.dates import MONTHS, MONTHS_3, MONTHS_ALT, MONTHS_AP, WEEKDAYS, WEEKDAYS_ABBR
21
from django.utils.tzinfo import LocalTimezone
22
21
from django.utils.translation import ugettext as _
23
22
from django.utils.encoding import force_text
24
23
from django.utils import six
25
from django.utils.timezone import is_aware, is_naive
24
from django.utils.timezone import get_default_timezone, is_aware, is_naive
27
26
re_formatchars = re.compile(r'(?<!\\)([aAbBcdDeEfFgGhHiIjlLmMnNoOPrsStTUuwWyYzZ])')
28
27
re_escaped = re.compile(r'\\(.)')
30
30
class Formatter(object):
31
31
def format(self, formatstr):
37
37
pieces.append(re_escaped.sub(r'\1', piece))
38
38
return ''.join(pieces)
40
41
class TimeFormat(Formatter):
41
def __init__(self, t):
43
def __init__(self, obj):
47
# We only support timezone when formatting datetime objects,
48
# not date objects (timezone information not appropriate),
49
# or time objects (against established django policy).
50
if isinstance(obj, datetime.datetime):
52
self.timezone = get_default_timezone()
54
self.timezone = obj.tzinfo
57
69
"Swatch Internet time"
58
raise NotImplementedError
70
raise NotImplementedError('may be implemented in a future release')
76
If timezone information is not available, this method returns
83
if hasattr(self.data, 'tzinfo') and self.data.tzinfo:
84
# Have to use tzinfo.tzname and not datetime.tzname
85
# because datatime.tzname does not expect Unicode
86
return self.data.tzinfo.tzname(self.data) or ""
87
except NotImplementedError:
92
123
"Minutes; i.e. '00' to '59'"
93
124
return '%02d' % self.data.minute
128
Difference to Greenwich time in hours; e.g. '+0200', '-0430'.
130
If timezone information is not available, this method returns
133
if not self.timezone:
137
sign = '-' if seconds < 0 else '+'
138
seconds = abs(seconds)
139
return "%s%02d%02d" % (sign, seconds // 3600, (seconds // 60) % 60)
97
143
Time, in 12-hour hours, minutes and 'a.m.'/'p.m.', with minutes left off
109
155
"Seconds; i.e. '00' to '59'"
110
156
return '%02d' % self.data.second
160
Time zone of this machine; e.g. 'EST' or 'MDT'.
162
If timezone information is not available, this method returns
165
if not self.timezone:
168
name = self.timezone.tzname(self.data) if self.timezone else None
170
name = self.format('O')
171
return six.text_type(name)
113
174
"Microseconds; i.e. '000000' to '999999'"
114
return '%06d' %self.data.microsecond
175
return '%06d' % self.data.microsecond
179
Time zone offset in seconds (i.e. '-43200' to '43200'). The offset for
180
timezones west of UTC is always negative, and for those east of UTC is
183
If timezone information is not available, this method returns
186
if not self.timezone:
189
offset = self.timezone.utcoffset(self.data)
190
# `offset` is a datetime.timedelta. For negative values (to the west of
191
# UTC) only days can be negative (days=-1) and seconds are always
192
# positive. e.g. UTC-1 -> timedelta(days=-1, seconds=82800, microseconds=0)
193
# Positive offsets have days=0
194
return offset.days * 86400 + offset.seconds
117
197
class DateFormat(TimeFormat):
118
198
year_days = [None, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]
120
def __init__(self, dt):
121
# Accepts either a datetime or date object.
124
if isinstance(dt, datetime.datetime):
126
self.timezone = LocalTimezone(dt)
128
self.timezone = dt.tzinfo
131
201
"Month, textual, 3 letters, lowercase; e.g. 'jan'"
132
202
return MONTHS_3[self.data.month]
146
216
"Day of the week, textual, 3 letters; e.g. 'Fri'"
147
217
return WEEKDAYS_ABBR[self.data.weekday()]
150
"Timezone name if available"
152
if hasattr(self.data, 'tzinfo') and self.data.tzinfo:
153
# Have to use tzinfo.tzname and not datetime.tzname
154
# because datatime.tzname does not expect Unicode
155
return self.data.tzinfo.tzname(self.data) or ""
156
except NotImplementedError:
161
220
"Alternative month names as required by some locales. Proprietary extension."
162
221
return MONTHS_ALT[self.data.month]
204
263
"ISO 8601 year number matching the ISO week number (W)"
205
264
return self.data.isocalendar()[0]
208
"Difference to Greenwich time in hours; e.g. '+0200', '-0430'"
210
sign = '-' if seconds < 0 else '+'
211
seconds = abs(seconds)
212
return "%s%02d%02d" % (sign, seconds // 3600, (seconds // 60) % 60)
215
267
"RFC 2822 formatted date; e.g. 'Thu, 21 Dec 2000 16:01:07 +0200'"
216
268
return self.format('D, j M Y H:i:s O')
219
271
"English ordinal suffix for the day of the month, 2 characters; i.e. 'st', 'nd', 'rd' or 'th'"
220
if self.data.day in (11, 12, 13): # Special case
272
if self.data.day in (11, 12, 13): # Special case
222
274
last = self.data.day % 10
232
284
"Number of days in the given month; i.e. '28' to '31'"
233
285
return '%02d' % calendar.monthrange(self.data.year, self.data.month)[1]
236
"Time zone of this machine; e.g. 'EST' or 'MDT'"
237
name = self.timezone.tzname(self.data) if self.timezone else None
239
name = self.format('O')
240
return six.text_type(name)
243
288
"Seconds since the Unix epoch (January 1 1970 00:00:00 GMT)"
244
289
if isinstance(self.data, datetime.datetime) and is_aware(self.data):
258
303
weekday = self.data.weekday() + 1
259
304
day_of_year = self.z()
260
305
if day_of_year <= (8 - jan1_weekday) and jan1_weekday > 4:
261
if jan1_weekday == 5 or (jan1_weekday == 6 and calendar.isleap(self.data.year-1)):
306
if jan1_weekday == 5 or (jan1_weekday == 6 and calendar.isleap(self.data.year - 1)):
296
Time zone offset in seconds (i.e. '-43200' to '43200'). The offset for
297
timezones west of UTC is always negative, and for those east of UTC is
300
if not self.timezone:
302
offset = self.timezone.utcoffset(self.data)
303
# `offset` is a datetime.timedelta. For negative values (to the west of
304
# UTC) only days can be negative (days=-1) and seconds are always
305
# positive. e.g. UTC-1 -> timedelta(days=-1, seconds=82800, microseconds=0)
306
# Positive offsets have days=0
307
return offset.days * 86400 + offset.seconds
309
340
def format(value, format_string):
310
341
"Convenience function"
311
342
df = DateFormat(value)
312
343
return df.format(format_string)
314
346
def time_format(value, format_string):
315
347
"Convenience function"
316
348
tf = TimeFormat(value)