Skip to content

Commit b759308

Browse files
committed
dates: Add iso8601 pattern timezone Format
#325
1 parent 949e4cb commit b759308

2 files changed

Lines changed: 167 additions & 15 deletions

File tree

babel/dates.py

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,7 +1194,7 @@ def __getitem__(self, name):
11941194
return self.format_frac_seconds(num)
11951195
elif char == 'A':
11961196
return self.format_milliseconds_in_day(num)
1197-
elif char in ('z', 'Z', 'v', 'V'):
1197+
elif char in ('z', 'Z', 'v', 'V', 'x', 'X', 'O'):
11981198
return self.format_timezone(char, num)
11991199
else:
12001200
raise KeyError('Unsupported date/time field %r' % char)
@@ -1296,19 +1296,47 @@ def format_milliseconds_in_day(self, num):
12961296
return self.format(msecs, num)
12971297

12981298
def format_timezone(self, char, num):
1299-
width = {3: 'short', 4: 'long'}[max(3, num)]
1299+
width = {3: 'short', 4: 'long', 5: 'iso8601'}[max(3, num)]
13001300
if char == 'z':
13011301
return get_timezone_name(self.value, width, locale=self.locale)
13021302
elif char == 'Z':
1303+
if num == 5:
1304+
return get_timezone_gmt(self.value, width, locale=self.locale, return_z=True)
13031305
return get_timezone_gmt(self.value, width, locale=self.locale)
1306+
elif char == 'O':
1307+
if num == 4:
1308+
return get_timezone_gmt(self.value, width, locale=self.locale)
1309+
# TODO: To add support for O:1
13041310
elif char == 'v':
13051311
return get_timezone_name(self.value.tzinfo, width,
13061312
locale=self.locale)
13071313
elif char == 'V':
13081314
if num == 1:
13091315
return get_timezone_name(self.value.tzinfo, width,
13101316
uncommon=True, locale=self.locale)
1317+
elif num == 2:
1318+
return get_timezone_name(self.value.tzinfo, locale=self.locale, return_zone=True)
1319+
elif num == 3:
1320+
return get_timezone_location(self.value.tzinfo, locale=self.locale, return_city=True)
13111321
return get_timezone_location(self.value.tzinfo, locale=self.locale)
1322+
# Included additional elif condition to add support for 'Xx' in timezone format
1323+
elif char == 'X':
1324+
if num == 1:
1325+
return get_timezone_gmt(self.value, width='iso8601_short', locale=self.locale,
1326+
return_z=True)
1327+
elif num in (2, 4):
1328+
return get_timezone_gmt(self.value, width='short', locale=self.locale,
1329+
return_z=True)
1330+
elif num in (3, 5):
1331+
return get_timezone_gmt(self.value, width='iso8601', locale=self.locale,
1332+
return_z=True)
1333+
elif char == 'x':
1334+
if num == 1:
1335+
return get_timezone_gmt(self.value, width='iso8601_short', locale=self.locale)
1336+
elif num in (2, 4):
1337+
return get_timezone_gmt(self.value, width='short', locale=self.locale)
1338+
elif num in (3, 5):
1339+
return get_timezone_gmt(self.value, width='iso8601', locale=self.locale)
13121340

13131341
def format(self, value, length):
13141342
return ('%%0%dd' % length) % value
@@ -1352,24 +1380,25 @@ def get_week_number(self, day_of_period, day_of_week=None):
13521380

13531381

13541382
PATTERN_CHARS = {
1355-
'G': [1, 2, 3, 4, 5], # era
1356-
'y': None, 'Y': None, 'u': None, # year
1357-
'Q': [1, 2, 3, 4], 'q': [1, 2, 3, 4], # quarter
1358-
'M': [1, 2, 3, 4, 5], 'L': [1, 2, 3, 4, 5], # month
1359-
'w': [1, 2], 'W': [1], # week
1360-
'd': [1, 2], 'D': [1, 2, 3], 'F': [1], 'g': None, # day
1361-
'E': [1, 2, 3, 4, 5], 'e': [1, 2, 3, 4, 5], 'c': [1, 3, 4, 5], # week day
1362-
'a': [1], # period
1363-
'h': [1, 2], 'H': [1, 2], 'K': [1, 2], 'k': [1, 2], # hour
1364-
'm': [1, 2], # minute
1365-
's': [1, 2], 'S': None, 'A': None, # second
1366-
'z': [1, 2, 3, 4], 'Z': [1, 2, 3, 4], 'v': [1, 4], 'V': [1, 4] # zone
1383+
'G': [1, 2, 3, 4, 5], # era
1384+
'y': None, 'Y': None, 'u': None, # year
1385+
'Q': [1, 2, 3, 4], 'q': [1, 2, 3, 4], # quarter
1386+
'M': [1, 2, 3, 4, 5], 'L': [1, 2, 3, 4, 5], # month
1387+
'w': [1, 2], 'W': [1], # week
1388+
'd': [1, 2], 'D': [1, 2, 3], 'F': [1], 'g': None, # day
1389+
'E': [1, 2, 3, 4, 5], 'e': [1, 2, 3, 4, 5], 'c': [1, 3, 4, 5], # week day
1390+
'a': [1], # period
1391+
'h': [1, 2], 'H': [1, 2], 'K': [1, 2], 'k': [1, 2], # hour
1392+
'm': [1, 2], # minute
1393+
's': [1, 2], 'S': None, 'A': None, # second
1394+
'z': [1, 2, 3, 4], 'Z': [1, 2, 3, 4, 5], 'O': [1, 4], 'v': [1, 4], # zone
1395+
'V': [1, 2, 3, 4], 'x': [1, 2, 3, 4, 5], 'X': [1, 2, 3, 4, 5] # zone
13671396
}
13681397

13691398
#: The pattern characters declared in the Date Field Symbol Table
13701399
#: (http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table)
13711400
#: in order of decreasing magnitude.
1372-
PATTERN_CHAR_ORDER = "GyYuUQqMLlwWdDFgEecabBChHKkjJmsSAzZvV"
1401+
PATTERN_CHAR_ORDER = "GyYuUQqMLlwWdDFgEecabBChHKkjJmsSAzZOvVXx"
13731402

13741403
_pattern_cache = {}
13751404

tests/test_dates.py

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,129 @@ def test_with_float(self):
250250
formatted_string = dates.format_datetime(epoch, format='long', locale='en_US')
251251
self.assertEqual(u'April 1, 2012 at 3:30:29 PM +0000', formatted_string)
252252

253+
def test_timezone_formats(self):
254+
dt = datetime(2016, 1, 13, 7, 8, 35)
255+
tz = dates.get_timezone('America/Los_Angeles')
256+
dt = tz.localize(dt)
257+
formatted_string = dates.format_datetime(dt, 'z', locale='en')
258+
self.assertEqual(u'PST', formatted_string)
259+
formatted_string = dates.format_datetime(dt, 'zz', locale='en')
260+
self.assertEqual(u'PST', formatted_string)
261+
formatted_string = dates.format_datetime(dt, 'zzz', locale='en')
262+
self.assertEqual(u'PST', formatted_string)
263+
formatted_string = dates.format_datetime(dt, 'zzzz', locale='en')
264+
self.assertEqual(u'Pacific Standard Time', formatted_string)
265+
formatted_string = dates.format_datetime(dt, 'Z', locale='en')
266+
self.assertEqual(u'-0800', formatted_string)
267+
formatted_string = dates.format_datetime(dt, 'ZZ', locale='en')
268+
self.assertEqual(u'-0800', formatted_string)
269+
formatted_string = dates.format_datetime(dt, 'ZZZ', locale='en')
270+
self.assertEqual(u'-0800', formatted_string)
271+
formatted_string = dates.format_datetime(dt, 'ZZZZ', locale='en')
272+
self.assertEqual(u'GMT-08:00', formatted_string)
273+
formatted_string = dates.format_datetime(dt, 'ZZZZZ', locale='en')
274+
self.assertEqual(u'-08:00', formatted_string)
275+
formatted_string = dates.format_datetime(dt, 'OOOO', locale='en')
276+
self.assertEqual(u'GMT-08:00', formatted_string)
277+
formatted_string = dates.format_datetime(dt, 'VV', locale='en')
278+
self.assertEqual(u'America/Los_Angeles', formatted_string)
279+
formatted_string = dates.format_datetime(dt, 'VVV', locale='en')
280+
self.assertEqual(u'Los Angeles', formatted_string)
281+
formatted_string = dates.format_datetime(dt, 'X', locale='en')
282+
self.assertEqual(u'-08', formatted_string)
283+
formatted_string = dates.format_datetime(dt, 'XX', locale='en')
284+
self.assertEqual(u'-0800', formatted_string)
285+
formatted_string = dates.format_datetime(dt, 'XXX', locale='en')
286+
self.assertEqual(u'-08:00', formatted_string)
287+
formatted_string = dates.format_datetime(dt, 'XXXX', locale='en')
288+
self.assertEqual(u'-0800', formatted_string)
289+
formatted_string = dates.format_datetime(dt, 'XXXXX', locale='en')
290+
self.assertEqual(u'-08:00', formatted_string)
291+
formatted_string = dates.format_datetime(dt, 'x', locale='en')
292+
self.assertEqual(u'-08', formatted_string)
293+
formatted_string = dates.format_datetime(dt, 'xx', locale='en')
294+
self.assertEqual(u'-0800', formatted_string)
295+
formatted_string = dates.format_datetime(dt, 'xxx', locale='en')
296+
self.assertEqual(u'-08:00', formatted_string)
297+
formatted_string = dates.format_datetime(dt, 'xxxx', locale='en')
298+
self.assertEqual(u'-0800', formatted_string)
299+
formatted_string = dates.format_datetime(dt, 'xxxxx', locale='en')
300+
self.assertEqual(u'-08:00', formatted_string)
301+
dt = datetime(2016, 1, 13, 7, 8, 35)
302+
tz = dates.get_timezone('UTC')
303+
dt = tz.localize(dt)
304+
formatted_string = dates.format_datetime(dt, 'Z', locale='en')
305+
self.assertEqual(u'+0000', formatted_string)
306+
formatted_string = dates.format_datetime(dt, 'ZZ', locale='en')
307+
self.assertEqual(u'+0000', formatted_string)
308+
formatted_string = dates.format_datetime(dt, 'ZZZ', locale='en')
309+
self.assertEqual(u'+0000', formatted_string)
310+
formatted_string = dates.format_datetime(dt, 'ZZZZ', locale='en')
311+
self.assertEqual(u'GMT+00:00', formatted_string)
312+
formatted_string = dates.format_datetime(dt, 'ZZZZZ', locale='en')
313+
self.assertEqual(u'Z', formatted_string)
314+
formatted_string = dates.format_datetime(dt, 'OOOO', locale='en')
315+
self.assertEqual(u'GMT+00:00', formatted_string)
316+
formatted_string = dates.format_datetime(dt, 'VV', locale='en')
317+
self.assertEqual(u'Etc/GMT', formatted_string)
318+
formatted_string = dates.format_datetime(dt, 'VVV', locale='en')
319+
self.assertEqual(u'GMT', formatted_string)
320+
formatted_string = dates.format_datetime(dt, 'X', locale='en')
321+
self.assertEqual(u'Z', formatted_string)
322+
formatted_string = dates.format_datetime(dt, 'XX', locale='en')
323+
self.assertEqual(u'Z', formatted_string)
324+
formatted_string = dates.format_datetime(dt, 'XXX', locale='en')
325+
self.assertEqual(u'Z', formatted_string)
326+
formatted_string = dates.format_datetime(dt, 'XXXX', locale='en')
327+
self.assertEqual(u'Z', formatted_string)
328+
formatted_string = dates.format_datetime(dt, 'XXXXX', locale='en')
329+
self.assertEqual(u'Z', formatted_string)
330+
formatted_string = dates.format_datetime(dt, 'x', locale='en')
331+
self.assertEqual(u'+00', formatted_string)
332+
formatted_string = dates.format_datetime(dt, 'xx', locale='en')
333+
self.assertEqual(u'+0000', formatted_string)
334+
formatted_string = dates.format_datetime(dt, 'xxx', locale='en')
335+
self.assertEqual(u'+00:00', formatted_string)
336+
formatted_string = dates.format_datetime(dt, 'xxxx', locale='en')
337+
self.assertEqual(u'+0000', formatted_string)
338+
formatted_string = dates.format_datetime(dt, 'xxxxx', locale='en')
339+
self.assertEqual(u'+00:00', formatted_string)
340+
dt = datetime(2016, 1, 13, 7, 8, 35)
341+
tz = dates.get_timezone('Asia/Kolkata')
342+
dt = tz.localize(dt)
343+
formatted_string = dates.format_datetime(dt, 'zzzz', locale='en')
344+
self.assertEqual(u'India Standard Time', formatted_string)
345+
formatted_string = dates.format_datetime(dt, 'ZZZZ', locale='en')
346+
self.assertEqual(u'GMT+05:30', formatted_string)
347+
formatted_string = dates.format_datetime(dt, 'ZZZZZ', locale='en')
348+
self.assertEqual(u'+05:30', formatted_string)
349+
formatted_string = dates.format_datetime(dt, 'OOOO', locale='en')
350+
self.assertEqual(u'GMT+05:30', formatted_string)
351+
formatted_string = dates.format_datetime(dt, 'VV', locale='en')
352+
self.assertEqual(u'Asia/Calcutta', formatted_string)
353+
formatted_string = dates.format_datetime(dt, 'VVV', locale='en')
354+
self.assertEqual(u'Kolkata', formatted_string)
355+
formatted_string = dates.format_datetime(dt, 'X', locale='en')
356+
self.assertEqual(u'+0530', formatted_string)
357+
formatted_string = dates.format_datetime(dt, 'XX', locale='en')
358+
self.assertEqual(u'+0530', formatted_string)
359+
formatted_string = dates.format_datetime(dt, 'XXX', locale='en')
360+
self.assertEqual(u'+05:30', formatted_string)
361+
formatted_string = dates.format_datetime(dt, 'XXXX', locale='en')
362+
self.assertEqual(u'+0530', formatted_string)
363+
formatted_string = dates.format_datetime(dt, 'XXXXX', locale='en')
364+
self.assertEqual(u'+05:30', formatted_string)
365+
formatted_string = dates.format_datetime(dt, 'x', locale='en')
366+
self.assertEqual(u'+0530', formatted_string)
367+
formatted_string = dates.format_datetime(dt, 'xx', locale='en')
368+
self.assertEqual(u'+0530', formatted_string)
369+
formatted_string = dates.format_datetime(dt, 'xxx', locale='en')
370+
self.assertEqual(u'+05:30', formatted_string)
371+
formatted_string = dates.format_datetime(dt, 'xxxx', locale='en')
372+
self.assertEqual(u'+0530', formatted_string)
373+
formatted_string = dates.format_datetime(dt, 'xxxxx', locale='en')
374+
self.assertEqual(u'+05:30', formatted_string)
375+
253376

254377
class FormatTimeTestCase(unittest.TestCase):
255378

0 commit comments

Comments
 (0)