Mercurial > babel > mirror
annotate babel/dates.py @ 242:910a6fe4471d trunk
Finish implementation of day-of-year and day-of-month for now, and fix implementation of year-of-week-of-year field. Closes #46. I suspect there are still cases not entirely covered by this implementation, but those can be filed as separate tickets.
author | cmlenz |
---|---|
date | Tue, 07 Aug 2007 21:41:35 +0000 |
parents | 15acce6db1da |
children | 319cfe6cdc0c |
rev | line source |
---|---|
1 | 1 # -*- coding: utf-8 -*- |
2 # | |
3 # Copyright (C) 2007 Edgewall Software | |
4 # All rights reserved. | |
5 # | |
6 # This software is licensed as described in the file COPYING, which | |
7 # you should have received as part of this distribution. The terms | |
8 # are also available at http://babel.edgewall.org/wiki/License. | |
9 # | |
10 # This software consists of voluntary contributions made by many | |
11 # individuals. For the exact contribution history, see the revision | |
12 # history and logs, available at http://babel.edgewall.org/log/. | |
13 | |
14 """Locale dependent formatting and parsing of dates and times. | |
15 | |
16 The default locale for the functions in this module is determined by the | |
17 following environment variables, in that order: | |
18 | |
19 * ``LC_TIME``, | |
20 * ``LC_ALL``, and | |
21 * ``LANG`` | |
22 """ | |
23 | |
29 | 24 from datetime import date, datetime, time, timedelta, tzinfo |
38
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
25 import re |
1 | 26 |
233
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
27 from babel.core import default_locale, get_global, Locale |
39
008de2f257a6
Move function for determining the system default locale to `babel.core`, and make it available as a class method on `Locale`.
cmlenz
parents:
38
diff
changeset
|
28 from babel.util import UTC |
1 | 29 |
233
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
30 __all__ = ['format_date', 'format_datetime', 'format_time', |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
31 'get_timezone_name', 'parse_date', 'parse_datetime', 'parse_time'] |
1 | 32 __docformat__ = 'restructuredtext en' |
33 | |
72
e0bb7dce49ea
More explicit module-level function names in `babel.core`. Added `Locale.negotiate` class method.
cmlenz
parents:
46
diff
changeset
|
34 LC_TIME = default_locale('LC_TIME') |
1 | 35 |
33 | 36 # Aliases for use in scopes where the modules are shadowed by local variables |
37 date_ = date | |
38 datetime_ = datetime | |
39 time_ = time | |
40 | |
1 | 41 def get_period_names(locale=LC_TIME): |
42 """Return the names for day periods (AM/PM) used by the locale. | |
43 | |
44 >>> get_period_names(locale='en_US')['am'] | |
45 u'AM' | |
46 | |
47 :param locale: the `Locale` object, or a locale string | |
48 :return: the dictionary of period names | |
49 :rtype: `dict` | |
50 """ | |
51 return Locale.parse(locale).periods | |
52 | |
53 def get_day_names(width='wide', context='format', locale=LC_TIME): | |
54 """Return the day names used by the locale for the specified format. | |
55 | |
56 >>> get_day_names('wide', locale='en_US')[1] | |
15 | 57 u'Tuesday' |
1 | 58 >>> get_day_names('abbreviated', locale='es')[1] |
15 | 59 u'mar' |
1 | 60 >>> get_day_names('narrow', context='stand-alone', locale='de_DE')[1] |
15 | 61 u'D' |
1 | 62 |
63 :param width: the width to use, one of "wide", "abbreviated", or "narrow" | |
64 :param context: the context, either "format" or "stand-alone" | |
65 :param locale: the `Locale` object, or a locale string | |
66 :return: the dictionary of day names | |
67 :rtype: `dict` | |
68 """ | |
69 return Locale.parse(locale).days[context][width] | |
70 | |
71 def get_month_names(width='wide', context='format', locale=LC_TIME): | |
72 """Return the month names used by the locale for the specified format. | |
73 | |
74 >>> get_month_names('wide', locale='en_US')[1] | |
75 u'January' | |
76 >>> get_month_names('abbreviated', locale='es')[1] | |
77 u'ene' | |
78 >>> get_month_names('narrow', context='stand-alone', locale='de_DE')[1] | |
79 u'J' | |
80 | |
81 :param width: the width to use, one of "wide", "abbreviated", or "narrow" | |
82 :param context: the context, either "format" or "stand-alone" | |
83 :param locale: the `Locale` object, or a locale string | |
84 :return: the dictionary of month names | |
85 :rtype: `dict` | |
86 """ | |
87 return Locale.parse(locale).months[context][width] | |
88 | |
89 def get_quarter_names(width='wide', context='format', locale=LC_TIME): | |
90 """Return the quarter names used by the locale for the specified format. | |
91 | |
92 >>> get_quarter_names('wide', locale='en_US')[1] | |
93 u'1st quarter' | |
94 >>> get_quarter_names('abbreviated', locale='de_DE')[1] | |
95 u'Q1' | |
96 | |
97 :param width: the width to use, one of "wide", "abbreviated", or "narrow" | |
98 :param context: the context, either "format" or "stand-alone" | |
99 :param locale: the `Locale` object, or a locale string | |
100 :return: the dictionary of quarter names | |
101 :rtype: `dict` | |
102 """ | |
103 return Locale.parse(locale).quarters[context][width] | |
104 | |
105 def get_era_names(width='wide', locale=LC_TIME): | |
106 """Return the era names used by the locale for the specified format. | |
107 | |
108 >>> get_era_names('wide', locale='en_US')[1] | |
109 u'Anno Domini' | |
110 >>> get_era_names('abbreviated', locale='de_DE')[1] | |
111 u'n. Chr.' | |
112 | |
233
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
113 :param width: the width to use, either "wide", "abbreviated", or "narrow" |
1 | 114 :param locale: the `Locale` object, or a locale string |
115 :return: the dictionary of era names | |
116 :rtype: `dict` | |
117 """ | |
118 return Locale.parse(locale).eras[width] | |
119 | |
120 def get_date_format(format='medium', locale=LC_TIME): | |
121 """Return the date formatting patterns used by the locale for the specified | |
122 format. | |
123 | |
124 >>> get_date_format(locale='en_US') | |
12
e6ba3e878b10
* Removed pkg_resources/setuptools requirement from various places.
cmlenz
parents:
8
diff
changeset
|
125 <DateTimePattern u'MMM d, yyyy'> |
1 | 126 >>> get_date_format('full', locale='de_DE') |
12
e6ba3e878b10
* Removed pkg_resources/setuptools requirement from various places.
cmlenz
parents:
8
diff
changeset
|
127 <DateTimePattern u'EEEE, d. MMMM yyyy'> |
1 | 128 |
129 :param format: the format to use, one of "full", "long", "medium", or | |
130 "short" | |
131 :param locale: the `Locale` object, or a locale string | |
132 :return: the date format pattern | |
33 | 133 :rtype: `DateTimePattern` |
1 | 134 """ |
135 return Locale.parse(locale).date_formats[format] | |
136 | |
33 | 137 def get_datetime_format(format='medium', locale=LC_TIME): |
138 """Return the datetime formatting patterns used by the locale for the | |
139 specified format. | |
140 | |
141 >>> get_datetime_format(locale='en_US') | |
142 u'{1} {0}' | |
143 | |
144 :param format: the format to use, one of "full", "long", "medium", or | |
145 "short" | |
146 :param locale: the `Locale` object, or a locale string | |
147 :return: the datetime format pattern | |
148 :rtype: `unicode` | |
149 """ | |
150 patterns = Locale.parse(locale).datetime_formats | |
151 if format not in patterns: | |
152 format = None | |
153 return patterns[format] | |
154 | |
1 | 155 def get_time_format(format='medium', locale=LC_TIME): |
156 """Return the time formatting patterns used by the locale for the specified | |
157 format. | |
158 | |
159 >>> get_time_format(locale='en_US') | |
12
e6ba3e878b10
* Removed pkg_resources/setuptools requirement from various places.
cmlenz
parents:
8
diff
changeset
|
160 <DateTimePattern u'h:mm:ss a'> |
1 | 161 >>> get_time_format('full', locale='de_DE') |
233
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
162 <DateTimePattern u'HH:mm:ss v'> |
1 | 163 |
164 :param format: the format to use, one of "full", "long", "medium", or | |
165 "short" | |
166 :param locale: the `Locale` object, or a locale string | |
167 :return: the time format pattern | |
33 | 168 :rtype: `DateTimePattern` |
1 | 169 """ |
170 return Locale.parse(locale).time_formats[format] | |
171 | |
233
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
172 def get_timezone_gmt(datetime=None, width='long', locale=LC_TIME): |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
173 """Return the timezone associated with the given `datetime` object formatted |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
174 as string indicating the offset from GMT. |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
175 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
176 >>> dt = datetime(2007, 4, 1, 15, 30) |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
177 >>> get_timezone_gmt(dt) |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
178 u'GMT+00:00' |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
179 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
180 >>> from pytz import timezone |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
181 >>> tz = timezone('America/Los_Angeles') |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
182 >>> dt = datetime(2007, 4, 1, 15, 30, tzinfo=tz) |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
183 >>> get_timezone_gmt(dt) |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
184 u'GMT-08:00' |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
185 >>> get_timezone_gmt(dt, 'short') |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
186 u'-0800' |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
187 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
188 The long format depends on the locale, for example in France a different |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
189 string is used for GMT: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
190 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
191 >>> get_timezone_gmt(dt, 'long', locale='fr_FR') |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
192 u'HMG-08:00' |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
193 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
194 :param dt: the ``datetime`` object; if `None`, the current date and time are |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
195 used |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
196 :param width: either "long" or "short" |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
197 :param locale: the `Locale` object, or a locale string |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
198 :return: the GMT offset representation of the timezone |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
199 :rtype: `unicode` |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
200 :since: version 0.9 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
201 """ |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
202 if datetime is None: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
203 datetime = datetime_.now() |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
204 elif isinstance(datetime, (int, long)): |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
205 datetime = datetime_.fromtimestamp(datetime).time() |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
206 if datetime.tzinfo is None: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
207 datetime = datetime.replace(tzinfo=UTC) |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
208 locale = Locale.parse(locale) |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
209 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
210 offset = datetime.utcoffset() |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
211 seconds = offset.days * 24 * 60 * 60 + offset.seconds |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
212 hours, seconds = divmod(seconds, 3600) |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
213 if width == 'short': |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
214 pattern = u'%+03d%02d' |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
215 else: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
216 pattern = locale.zone_formats['gmt'] % '%+03d:%02d' |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
217 return pattern % (hours, seconds // 60) |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
218 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
219 def get_timezone_location(dt_or_tzinfo=None, locale=LC_TIME): |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
220 """Return a representation of the given timezone using "location format". |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
221 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
222 The result depends on both the local display name of the country and the |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
223 city assocaited with the time zone: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
224 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
225 >>> from pytz import timezone |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
226 >>> tz = timezone('America/St_Johns') |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
227 >>> get_timezone_location(tz, locale='de_DE') |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
228 u"Kanada (St. John's)" |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
229 >>> tz = timezone('America/Mexico_City') |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
230 >>> get_timezone_location(tz, locale='de_DE') |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
231 u'Mexiko (Mexiko-Stadt)' |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
232 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
233 If the timezone is associated with a country that uses only a single |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
234 timezone, just the localized country name is returned: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
235 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
236 >>> tz = timezone('Europe/Berlin') |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
237 >>> get_timezone_name(tz, locale='de_DE') |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
238 u'Deutschland' |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
239 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
240 :param dt_or_tzinfo: the ``datetime`` or ``tzinfo`` object that determines |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
241 the timezone; if `None`, the current date and time in |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
242 UTC is assumed |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
243 :param locale: the `Locale` object, or a locale string |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
244 :return: the localized timezone name using location format |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
245 :rtype: `unicode` |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
246 :since: version 0.9 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
247 """ |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
248 if dt_or_tzinfo is None or isinstance(dt_or_tzinfo, (int, long)): |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
249 dt = None |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
250 tzinfo = UTC |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
251 elif isinstance(dt_or_tzinfo, (datetime, time)): |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
252 dt = dt_or_tzinfo |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
253 if dt.tzinfo is not None: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
254 tzinfo = dt.tzinfo |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
255 else: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
256 tzinfo = UTC |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
257 else: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
258 dt = None |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
259 tzinfo = dt_or_tzinfo |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
260 locale = Locale.parse(locale) |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
261 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
262 if hasattr(tzinfo, 'zone'): |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
263 zone = tzinfo.zone |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
264 else: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
265 zone = tzinfo.tzname(dt or datetime.utcnow()) |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
266 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
267 # Get the canonical time-zone code |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
268 zone = get_global('zone_aliases').get(zone, zone) |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
269 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
270 metainfo = {} |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
271 info = locale.time_zones.get(zone, {}) |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
272 if 'use_metazone' in info: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
273 metainfo = locale.meta_zones.get(info['use_metazone'], {}) |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
274 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
275 # Otherwise, if there is only one timezone for the country, return the |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
276 # localized country name |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
277 region_format = locale.zone_formats['region'] |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
278 territory = get_global('zone_territories').get(zone) |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
279 territory_name = locale.territories[territory] |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
280 if territory and len(get_global('territory_zones')[territory]) == 1: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
281 return region_format % (territory_name) |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
282 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
283 # Otherwise, include the city in the output |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
284 fallback_format = locale.zone_formats['fallback'] |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
285 if 'city' in info: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
286 city_name = info['city'] |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
287 elif 'city' in metainfo: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
288 city_name = metainfo['city'] |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
289 elif '/' in zone: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
290 city_name = zone.split('/', 1)[1].replace('_', ' ') |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
291 else: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
292 city_name = zone.replace('_', ' ') |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
293 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
294 return region_format % (fallback_format % { |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
295 '0': city_name, |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
296 '1': territory_name |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
297 }) |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
298 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
299 def get_timezone_name(dt_or_tzinfo=None, width='long', uncommon=False, |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
300 locale=LC_TIME): |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
301 r"""Return the localized display name for the given timezone. The timezone |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
302 may be specified using a ``datetime`` or `tzinfo` object. |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
303 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
304 >>> from pytz import timezone |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
305 >>> dt = time(15, 30, tzinfo=timezone('America/Los_Angeles')) |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
306 >>> get_timezone_name(dt, locale='en_US') |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
307 u'Pacific Standard Time' |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
308 >>> get_timezone_name(dt, width='short', locale='en_US') |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
309 u'PST' |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
310 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
311 If this function gets passed only a `tzinfo` object and no concrete |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
312 `datetime`, the returned display name is indenpendent of daylight savings |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
313 time. This can be used for example for selecting timezones, or to set the |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
314 time of events that recur across DST changes: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
315 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
316 >>> tz = timezone('America/Los_Angeles') |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
317 >>> get_timezone_name(tz, locale='en_US') |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
318 u'Pacific Time' |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
319 >>> get_timezone_name(tz, 'short', locale='en_US') |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
320 u'PT' |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
321 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
322 If no localized display name for the timezone is available, and the timezone |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
323 is associated with a country that uses only a single timezone, the name of |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
324 that country is returned, formatted according to the locale: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
325 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
326 >>> tz = timezone('Europe/Berlin') |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
327 >>> get_timezone_name(tz, locale='de_DE') |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
328 u'Deutschland' |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
329 >>> get_timezone_name(tz, locale='pt_BR') |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
330 u'Hor\xe1rio Alemanha' |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
331 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
332 On the other hand, if the country uses multiple timezones, the city is also |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
333 included in the representation: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
334 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
335 >>> tz = timezone('America/St_Johns') |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
336 >>> get_timezone_name(tz, locale='de_DE') |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
337 u"Kanada (St. John's)" |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
338 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
339 The `uncommon` parameter can be set to `True` to enable the use of timezone |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
340 representations that are not commonly used by the requested locale. For |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
341 example, while in frensh the central europian timezone is usually |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
342 abbreviated as "HEC", in Canadian frensh, this abbreviation is not in common |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
343 use, so a generic name would be chosen by default: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
344 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
345 >>> tz = timezone('Europe/Paris') |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
346 >>> get_timezone_name(tz, 'short', locale='fr_CA') |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
347 u'France' |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
348 >>> get_timezone_name(tz, 'short', uncommon=True, locale='fr_CA') |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
349 u'HEC' |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
350 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
351 :param dt_or_tzinfo: the ``datetime`` or ``tzinfo`` object that determines |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
352 the timezone; if a ``tzinfo`` object is used, the |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
353 resulting display name will be generic, i.e. |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
354 independent of daylight savings time; if `None`, the |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
355 current date in UTC is assumed |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
356 :param width: either "long" or "short" |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
357 :param uncommon: whether even uncommon timezone abbreviations should be used |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
358 :param locale: the `Locale` object, or a locale string |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
359 :return: the timezone display name |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
360 :rtype: `unicode` |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
361 :since: version 0.9 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
362 :see: `LDML Appendix J: Time Zone Display Names |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
363 <http://www.unicode.org/reports/tr35/#Time_Zone_Fallback>`_ |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
364 """ |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
365 if dt_or_tzinfo is None or isinstance(dt_or_tzinfo, (int, long)): |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
366 dt = None |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
367 tzinfo = UTC |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
368 elif isinstance(dt_or_tzinfo, (datetime, time)): |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
369 dt = dt_or_tzinfo |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
370 if dt.tzinfo is not None: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
371 tzinfo = dt.tzinfo |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
372 else: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
373 tzinfo = UTC |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
374 else: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
375 dt = None |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
376 tzinfo = dt_or_tzinfo |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
377 locale = Locale.parse(locale) |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
378 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
379 if hasattr(tzinfo, 'zone'): |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
380 zone = tzinfo.zone |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
381 else: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
382 zone = tzinfo.tzname(dt or datetime.utcnow()) |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
383 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
384 # Get the canonical time-zone code |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
385 zone = get_global('zone_aliases').get(zone, zone) |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
386 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
387 metainfo = {} |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
388 info = locale.time_zones.get(zone, {}) |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
389 # Try explicitly translated zone names first |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
390 if width in info: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
391 if dt is None: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
392 field = 'generic' |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
393 else: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
394 field = tzinfo.dst(dt) and 'daylight' or 'standard' |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
395 if field in info[width]: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
396 return info[width][field] |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
397 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
398 if 'use_metazone' in info: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
399 metainfo = locale.meta_zones.get(info['use_metazone'], {}) |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
400 if width in metainfo and (uncommon or metainfo.get('common')): |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
401 if dt is None: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
402 field = 'generic' |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
403 else: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
404 field = tzinfo.dst(dt) and 'daylight' or 'standard' |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
405 if field in metainfo[width]: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
406 return metainfo[width][field] |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
407 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
408 # If we have a concrete datetime, we assume that the result can't be |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
409 # independent of daylight savings time, so we return the GMT offset |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
410 if dt is not None: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
411 return get_timezone_gmt(time, width=width, locale=locale) |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
412 |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
413 return get_timezone_location(dt_or_tzinfo, locale=locale) |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
414 |
33 | 415 def format_date(date=None, format='medium', locale=LC_TIME): |
101
0f641136aa6b
Add wrapper class bundling the various formatting functions bound to a specific locale and time-zone.
cmlenz
parents:
72
diff
changeset
|
416 """Return a date formatted according to the given pattern. |
1 | 417 |
418 >>> d = date(2007, 04, 01) | |
419 >>> format_date(d, locale='en_US') | |
420 u'Apr 1, 2007' | |
421 >>> format_date(d, format='full', locale='de_DE') | |
422 u'Sonntag, 1. April 2007' | |
423 | |
16 | 424 If you don't want to use the locale default formats, you can specify a |
425 custom date pattern: | |
426 | |
29 | 427 >>> format_date(d, "EEE, MMM d, ''yy", locale='en') |
16 | 428 u"Sun, Apr 1, '07" |
429 | |
33 | 430 :param date: the ``date`` or ``datetime`` object; if `None`, the current |
431 date is used | |
16 | 432 :param format: one of "full", "long", "medium", or "short", or a custom |
433 date/time pattern | |
19
d8352fbaca65
Moved some datetime tests from doctest to unittest, to avoid breaking docutils/epydoc doctest block detection.
cmlenz
parents:
18
diff
changeset
|
434 :param locale: a `Locale` object or a locale identifier |
1 | 435 :rtype: `unicode` |
19
d8352fbaca65
Moved some datetime tests from doctest to unittest, to avoid breaking docutils/epydoc doctest block detection.
cmlenz
parents:
18
diff
changeset
|
436 |
d8352fbaca65
Moved some datetime tests from doctest to unittest, to avoid breaking docutils/epydoc doctest block detection.
cmlenz
parents:
18
diff
changeset
|
437 :note: If the pattern contains time fields, an `AttributeError` will be |
d8352fbaca65
Moved some datetime tests from doctest to unittest, to avoid breaking docutils/epydoc doctest block detection.
cmlenz
parents:
18
diff
changeset
|
438 raised when trying to apply the formatting. This is also true if |
d8352fbaca65
Moved some datetime tests from doctest to unittest, to avoid breaking docutils/epydoc doctest block detection.
cmlenz
parents:
18
diff
changeset
|
439 the value of ``date`` parameter is actually a ``datetime`` object, |
d8352fbaca65
Moved some datetime tests from doctest to unittest, to avoid breaking docutils/epydoc doctest block detection.
cmlenz
parents:
18
diff
changeset
|
440 as this function automatically converts that to a ``date``. |
1 | 441 """ |
33 | 442 if date is None: |
443 date = date_.today() | |
444 elif isinstance(date, datetime): | |
18
990909fdf98b
Started documentation for date formatting, plus some code tweaks in that area.
cmlenz
parents:
16
diff
changeset
|
445 date = date.date() |
34 | 446 |
1 | 447 locale = Locale.parse(locale) |
448 if format in ('full', 'long', 'medium', 'short'): | |
449 format = get_date_format(format, locale=locale) | |
450 pattern = parse_pattern(format) | |
451 return parse_pattern(format).apply(date, locale) | |
452 | |
34 | 453 def format_datetime(datetime=None, format='medium', tzinfo=None, |
454 locale=LC_TIME): | |
101
0f641136aa6b
Add wrapper class bundling the various formatting functions bound to a specific locale and time-zone.
cmlenz
parents:
72
diff
changeset
|
455 """Return a date formatted according to the given pattern. |
1 | 456 |
33 | 457 >>> dt = datetime(2007, 04, 01, 15, 30) |
458 >>> format_datetime(dt, locale='en_US') | |
459 u'Apr 1, 2007 3:30:00 PM' | |
460 | |
34 | 461 For any pattern requiring the display of the time-zone, the third-party |
462 ``pytz`` package is needed to explicitly specify the time-zone: | |
463 | |
464 >>> from pytz import timezone | |
233
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
465 >>> format_datetime(dt, 'full', tzinfo=timezone('Europe/Paris'), |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
466 ... locale='fr_FR') |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
467 u'dimanche 1 avril 2007 17:30:00 HEC' |
34 | 468 >>> format_datetime(dt, "yyyy.MM.dd G 'at' HH:mm:ss zzz", |
469 ... tzinfo=timezone('US/Eastern'), locale='en') | |
470 u'2007.04.01 AD at 11:30:00 EDT' | |
471 | |
33 | 472 :param datetime: the `datetime` object; if `None`, the current date and |
473 time is used | |
16 | 474 :param format: one of "full", "long", "medium", or "short", or a custom |
475 date/time pattern | |
29 | 476 :param tzinfo: the timezone to apply to the time for display |
19
d8352fbaca65
Moved some datetime tests from doctest to unittest, to avoid breaking docutils/epydoc doctest block detection.
cmlenz
parents:
18
diff
changeset
|
477 :param locale: a `Locale` object or a locale identifier |
1 | 478 :rtype: `unicode` |
479 """ | |
33 | 480 if datetime is None: |
481 datetime = datetime_.now() | |
34 | 482 elif isinstance(datetime, (int, long)): |
483 datetime = datetime.fromtimestamp(datetime) | |
484 elif isinstance(datetime, time): | |
485 datetime = datetime_.combine(date.today(), datetime) | |
486 if datetime.tzinfo is None: | |
487 datetime = datetime.replace(tzinfo=UTC) | |
488 if tzinfo is not None: | |
489 datetime = datetime.astimezone(tzinfo) | |
101
0f641136aa6b
Add wrapper class bundling the various formatting functions bound to a specific locale and time-zone.
cmlenz
parents:
72
diff
changeset
|
490 if hasattr(tzinfo, 'normalize'): # pytz |
34 | 491 datetime = tzinfo.normalize(datetime) |
492 | |
18
990909fdf98b
Started documentation for date formatting, plus some code tweaks in that area.
cmlenz
parents:
16
diff
changeset
|
493 locale = Locale.parse(locale) |
990909fdf98b
Started documentation for date formatting, plus some code tweaks in that area.
cmlenz
parents:
16
diff
changeset
|
494 if format in ('full', 'long', 'medium', 'short'): |
33 | 495 return get_datetime_format(format, locale=locale) \ |
34 | 496 .replace('{0}', format_time(datetime, format, tzinfo=None, |
33 | 497 locale=locale)) \ |
498 .replace('{1}', format_date(datetime, format, locale=locale)) | |
499 else: | |
500 return parse_pattern(format).apply(datetime, locale) | |
1 | 501 |
34 | 502 def format_time(time=None, format='medium', tzinfo=None, locale=LC_TIME): |
101
0f641136aa6b
Add wrapper class bundling the various formatting functions bound to a specific locale and time-zone.
cmlenz
parents:
72
diff
changeset
|
503 """Return a time formatted according to the given pattern. |
1 | 504 |
505 >>> t = time(15, 30) | |
506 >>> format_time(t, locale='en_US') | |
507 u'3:30:00 PM' | |
508 >>> format_time(t, format='short', locale='de_DE') | |
509 u'15:30' | |
510 | |
16 | 511 If you don't want to use the locale default formats, you can specify a |
512 custom time pattern: | |
513 | |
514 >>> format_time(t, "hh 'o''clock' a", locale='en') | |
515 u"03 o'clock PM" | |
516 | |
29 | 517 For any pattern requiring the display of the time-zone, the third-party |
518 ``pytz`` package is needed to explicitly specify the time-zone: | |
519 | |
101
0f641136aa6b
Add wrapper class bundling the various formatting functions bound to a specific locale and time-zone.
cmlenz
parents:
72
diff
changeset
|
520 >>> from pytz import timezone |
0f641136aa6b
Add wrapper class bundling the various formatting functions bound to a specific locale and time-zone.
cmlenz
parents:
72
diff
changeset
|
521 >>> t = time(15, 30) |
233
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
522 >>> format_time(t, format='full', tzinfo=timezone('Europe/Paris'), |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
523 ... locale='fr_FR') |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
524 u'17:30:00 HEC' |
34 | 525 >>> format_time(t, "hh 'o''clock' a, zzzz", tzinfo=timezone('US/Eastern'), |
526 ... locale='en') | |
527 u"11 o'clock AM, Eastern Daylight Time" | |
29 | 528 |
33 | 529 :param time: the ``time`` or ``datetime`` object; if `None`, the current |
530 time is used | |
16 | 531 :param format: one of "full", "long", "medium", or "short", or a custom |
532 date/time pattern | |
29 | 533 :param tzinfo: the time-zone to apply to the time for display |
19
d8352fbaca65
Moved some datetime tests from doctest to unittest, to avoid breaking docutils/epydoc doctest block detection.
cmlenz
parents:
18
diff
changeset
|
534 :param locale: a `Locale` object or a locale identifier |
1 | 535 :rtype: `unicode` |
19
d8352fbaca65
Moved some datetime tests from doctest to unittest, to avoid breaking docutils/epydoc doctest block detection.
cmlenz
parents:
18
diff
changeset
|
536 |
d8352fbaca65
Moved some datetime tests from doctest to unittest, to avoid breaking docutils/epydoc doctest block detection.
cmlenz
parents:
18
diff
changeset
|
537 :note: If the pattern contains date fields, an `AttributeError` will be |
d8352fbaca65
Moved some datetime tests from doctest to unittest, to avoid breaking docutils/epydoc doctest block detection.
cmlenz
parents:
18
diff
changeset
|
538 raised when trying to apply the formatting. This is also true if |
d8352fbaca65
Moved some datetime tests from doctest to unittest, to avoid breaking docutils/epydoc doctest block detection.
cmlenz
parents:
18
diff
changeset
|
539 the value of ``time`` parameter is actually a ``datetime`` object, |
d8352fbaca65
Moved some datetime tests from doctest to unittest, to avoid breaking docutils/epydoc doctest block detection.
cmlenz
parents:
18
diff
changeset
|
540 as this function automatically converts that to a ``time``. |
1 | 541 """ |
33 | 542 if time is None: |
543 time = datetime.now().time() | |
544 elif isinstance(time, (int, long)): | |
18
990909fdf98b
Started documentation for date formatting, plus some code tweaks in that area.
cmlenz
parents:
16
diff
changeset
|
545 time = datetime.fromtimestamp(time).time() |
990909fdf98b
Started documentation for date formatting, plus some code tweaks in that area.
cmlenz
parents:
16
diff
changeset
|
546 elif isinstance(time, datetime): |
34 | 547 time = time.timetz() |
29 | 548 if time.tzinfo is None: |
34 | 549 time = time.replace(tzinfo=UTC) |
550 if tzinfo is not None: | |
551 dt = datetime.combine(date.today(), time).astimezone(tzinfo) | |
101
0f641136aa6b
Add wrapper class bundling the various formatting functions bound to a specific locale and time-zone.
cmlenz
parents:
72
diff
changeset
|
552 if hasattr(tzinfo, 'normalize'): # pytz |
34 | 553 dt = tzinfo.normalize(dt) |
554 time = dt.timetz() | |
555 | |
1 | 556 locale = Locale.parse(locale) |
557 if format in ('full', 'long', 'medium', 'short'): | |
558 format = get_time_format(format, locale=locale) | |
559 return parse_pattern(format).apply(time, locale) | |
560 | |
561 def parse_date(string, locale=LC_TIME): | |
38
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
562 """Parse a date from a string. |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
563 |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
564 This function uses the date format for the locale as a hint to determine |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
565 the order in which the date fields appear in the string. |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
566 |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
567 >>> parse_date('4/1/04', locale='en_US') |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
568 datetime.date(2004, 4, 1) |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
569 >>> parse_date('01.04.2004', locale='de_DE') |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
570 datetime.date(2004, 4, 1) |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
571 |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
572 :param string: the string containing the date |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
573 :param locale: a `Locale` object or a locale identifier |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
574 :return: the parsed date |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
575 :rtype: `date` |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
576 """ |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
577 # TODO: try ISO format first? |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
578 format = get_date_format(locale=locale).pattern.lower() |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
579 year_idx = format.index('y') |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
580 month_idx = format.index('m') |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
581 if month_idx < 0: |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
582 month_idx = format.index('l') |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
583 day_idx = format.index('d') |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
584 |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
585 indexes = [(year_idx, 'Y'), (month_idx, 'M'), (day_idx, 'D')] |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
586 indexes.sort() |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
587 indexes = dict([(item[1], idx) for idx, item in enumerate(indexes)]) |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
588 |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
589 # FIXME: this currently only supports numbers, but should also support month |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
590 # names, both in the requested locale, and english |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
591 |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
592 numbers = re.findall('(\d+)', string) |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
593 year = numbers[indexes['Y']] |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
594 if len(year) == 2: |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
595 year = 2000 + int(year) |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
596 else: |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
597 year = int(year) |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
598 month = int(numbers[indexes['M']]) |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
599 day = int(numbers[indexes['D']]) |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
600 if month > 12: |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
601 month, day = day, month |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
602 return date(year, month, day) |
1 | 603 |
604 def parse_datetime(string, locale=LC_TIME): | |
46 | 605 """Parse a date and time from a string. |
606 | |
607 This function uses the date and time formats for the locale as a hint to | |
608 determine the order in which the time fields appear in the string. | |
609 | |
610 :param string: the string containing the date and time | |
611 :param locale: a `Locale` object or a locale identifier | |
612 :return: the parsed date/time | |
613 :rtype: `datetime` | |
614 """ | |
1 | 615 raise NotImplementedError |
616 | |
617 def parse_time(string, locale=LC_TIME): | |
46 | 618 """Parse a time from a string. |
38
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
619 |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
620 This function uses the time format for the locale as a hint to determine |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
621 the order in which the time fields appear in the string. |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
622 |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
623 >>> parse_time('15:30:00', locale='en_US') |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
624 datetime.time(15, 30) |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
625 |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
626 :param string: the string containing the time |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
627 :param locale: a `Locale` object or a locale identifier |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
628 :return: the parsed time |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
629 :rtype: `time` |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
630 """ |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
631 # TODO: try ISO format first? |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
632 format = get_time_format(locale=locale).pattern.lower() |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
633 hour_idx = format.index('h') |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
634 if hour_idx < 0: |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
635 hour_idx = format.index('k') |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
636 min_idx = format.index('m') |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
637 sec_idx = format.index('s') |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
638 |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
639 indexes = [(hour_idx, 'H'), (min_idx, 'M'), (sec_idx, 'S')] |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
640 indexes.sort() |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
641 indexes = dict([(item[1], idx) for idx, item in enumerate(indexes)]) |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
642 |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
643 # FIXME: support 12 hour clock, and 0-based hour specification |
46 | 644 # and seconds should be optional, maybe minutes too |
645 # oh, and time-zones, of course | |
38
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
646 |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
647 numbers = re.findall('(\d+)', string) |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
648 hour = int(numbers[indexes['H']]) |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
649 minute = int(numbers[indexes['M']]) |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
650 second = int(numbers[indexes['S']]) |
7ae4722af473
Started implementation of datetime parsing, using a very basic approach for now.
cmlenz
parents:
34
diff
changeset
|
651 return time(hour, minute, second) |
1 | 652 |
653 | |
12
e6ba3e878b10
* Removed pkg_resources/setuptools requirement from various places.
cmlenz
parents:
8
diff
changeset
|
654 class DateTimePattern(object): |
1 | 655 |
656 def __init__(self, pattern, format): | |
657 self.pattern = pattern | |
658 self.format = format | |
659 | |
660 def __repr__(self): | |
661 return '<%s %r>' % (type(self).__name__, self.pattern) | |
662 | |
663 def __unicode__(self): | |
664 return self.pattern | |
665 | |
666 def __mod__(self, other): | |
667 assert type(other) is DateTimeFormat | |
668 return self.format % other | |
669 | |
670 def apply(self, datetime, locale): | |
671 return self % DateTimeFormat(datetime, locale) | |
672 | |
673 | |
674 class DateTimeFormat(object): | |
675 | |
676 def __init__(self, value, locale): | |
677 assert isinstance(value, (date, datetime, time)) | |
29 | 678 if isinstance(value, (datetime, time)) and value.tzinfo is None: |
679 value = value.replace(tzinfo=UTC) | |
1 | 680 self.value = value |
681 self.locale = Locale.parse(locale) | |
682 | |
683 def __getitem__(self, name): | |
15 | 684 char = name[0] |
685 num = len(name) | |
686 if char == 'G': | |
687 return self.format_era(char, num) | |
215
7fcdcdf8972d
Dummy/stub implementation for week-in-year and week-in-month date format fields. Also, treat extended year the same as the regular year field, not even ICU seems to handle it specially.
cmlenz
parents:
129
diff
changeset
|
688 elif char in ('y', 'Y', 'u'): |
15 | 689 return self.format_year(char, num) |
690 elif char in ('Q', 'q'): | |
691 return self.format_quarter(char, num) | |
692 elif char in ('M', 'L'): | |
693 return self.format_month(char, num) | |
215
7fcdcdf8972d
Dummy/stub implementation for week-in-year and week-in-month date format fields. Also, treat extended year the same as the regular year field, not even ICU seems to handle it specially.
cmlenz
parents:
129
diff
changeset
|
694 elif char in ('w', 'W'): |
7fcdcdf8972d
Dummy/stub implementation for week-in-year and week-in-month date format fields. Also, treat extended year the same as the regular year field, not even ICU seems to handle it specially.
cmlenz
parents:
129
diff
changeset
|
695 return self.format_week(char, num) |
15 | 696 elif char == 'd': |
697 return self.format(self.value.day, num) | |
221
2af0d1085dd4
Implement day-of-year date format field. Closes #49.
cmlenz
parents:
217
diff
changeset
|
698 elif char == 'D': |
2af0d1085dd4
Implement day-of-year date format field. Closes #49.
cmlenz
parents:
217
diff
changeset
|
699 return self.format_day_of_year(num) |
241
15acce6db1da
Implement day-of-week-in-month field in date formatting. Closes #50.
cmlenz
parents:
240
diff
changeset
|
700 elif char == 'F': |
15acce6db1da
Implement day-of-week-in-month field in date formatting. Closes #50.
cmlenz
parents:
240
diff
changeset
|
701 return self.format_day_of_week_in_month() |
15 | 702 elif char in ('E', 'e', 'c'): |
703 return self.format_weekday(char, num) | |
704 elif char == 'a': | |
705 return self.format_period(char) | |
706 elif char == 'h': | |
707 return self.format(self.value.hour % 12, num) | |
708 elif char == 'H': | |
709 return self.format(self.value.hour, num) | |
18
990909fdf98b
Started documentation for date formatting, plus some code tweaks in that area.
cmlenz
parents:
16
diff
changeset
|
710 elif char == 'K': |
990909fdf98b
Started documentation for date formatting, plus some code tweaks in that area.
cmlenz
parents:
16
diff
changeset
|
711 return self.format(self.value.hour % 12 - 1, num) |
990909fdf98b
Started documentation for date formatting, plus some code tweaks in that area.
cmlenz
parents:
16
diff
changeset
|
712 elif char == 'k': |
990909fdf98b
Started documentation for date formatting, plus some code tweaks in that area.
cmlenz
parents:
16
diff
changeset
|
713 return self.format(self.value.hour + 1, num) |
15 | 714 elif char == 'm': |
715 return self.format(self.value.minute, num) | |
716 elif char == 's': | |
717 return self.format(self.value.second, num) | |
216
72813ca69416
Support for fractional seconds field in date formatting. Closes #47.
cmlenz
parents:
215
diff
changeset
|
718 elif char == 'S': |
217 | 719 return self.format_frac_seconds(num) |
720 elif char == 'A': | |
721 return self.format_milliseconds_in_day(num) | |
233
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
722 elif char in ('z', 'Z', 'v', 'V'): |
29 | 723 return self.format_timezone(char, num) |
1 | 724 else: |
15 | 725 raise KeyError('Unsupported date/time field %r' % char) |
1 | 726 |
15 | 727 def format_era(self, char, num): |
1 | 728 width = {3: 'abbreviated', 4: 'wide', 5: 'narrow'}[max(3, num)] |
729 era = int(self.value.year >= 0) | |
730 return get_era_names(width, self.locale)[era] | |
731 | |
15 | 732 def format_year(self, char, num): |
242
910a6fe4471d
Finish implementation of day-of-year and day-of-month for now, and fix implementation of year-of-week-of-year field. Closes #46. I suspect there are still cases not entirely covered by this implementation, but those can be filed as separate tickets.
cmlenz
parents:
241
diff
changeset
|
733 value = self.value.year |
910a6fe4471d
Finish implementation of day-of-year and day-of-month for now, and fix implementation of year-of-week-of-year field. Closes #46. I suspect there are still cases not entirely covered by this implementation, but those can be filed as separate tickets.
cmlenz
parents:
241
diff
changeset
|
734 if char.isupper(): |
910a6fe4471d
Finish implementation of day-of-year and day-of-month for now, and fix implementation of year-of-week-of-year field. Closes #46. I suspect there are still cases not entirely covered by this implementation, but those can be filed as separate tickets.
cmlenz
parents:
241
diff
changeset
|
735 week = self.get_week_number(self.get_day_of_year()) |
910a6fe4471d
Finish implementation of day-of-year and day-of-month for now, and fix implementation of year-of-week-of-year field. Closes #46. I suspect there are still cases not entirely covered by this implementation, but those can be filed as separate tickets.
cmlenz
parents:
241
diff
changeset
|
736 if week == 0: |
910a6fe4471d
Finish implementation of day-of-year and day-of-month for now, and fix implementation of year-of-week-of-year field. Closes #46. I suspect there are still cases not entirely covered by this implementation, but those can be filed as separate tickets.
cmlenz
parents:
241
diff
changeset
|
737 value -= 1 |
1 | 738 year = self.format(value, num) |
739 if num == 2: | |
740 year = year[-2:] | |
741 return year | |
742 | |
15 | 743 def format_month(self, char, num): |
1 | 744 if num <= 2: |
745 return ('%%0%dd' % num) % self.value.month | |
746 width = {3: 'abbreviated', 4: 'wide', 5: 'narrow'}[num] | |
15 | 747 context = {3: 'format', 4: 'format', 5: 'stand-alone'}[num] |
1 | 748 return get_month_names(width, context, self.locale)[self.value.month] |
749 | |
215
7fcdcdf8972d
Dummy/stub implementation for week-in-year and week-in-month date format fields. Also, treat extended year the same as the regular year field, not even ICU seems to handle it specially.
cmlenz
parents:
129
diff
changeset
|
750 def format_week(self, char, num): |
239 | 751 if char.islower(): # week of year |
242
910a6fe4471d
Finish implementation of day-of-year and day-of-month for now, and fix implementation of year-of-week-of-year field. Closes #46. I suspect there are still cases not entirely covered by this implementation, but those can be filed as separate tickets.
cmlenz
parents:
241
diff
changeset
|
752 day_of_year = self.get_day_of_year() |
910a6fe4471d
Finish implementation of day-of-year and day-of-month for now, and fix implementation of year-of-week-of-year field. Closes #46. I suspect there are still cases not entirely covered by this implementation, but those can be filed as separate tickets.
cmlenz
parents:
241
diff
changeset
|
753 week = self.get_week_number(day_of_year) |
240 | 754 if week == 0: |
242
910a6fe4471d
Finish implementation of day-of-year and day-of-month for now, and fix implementation of year-of-week-of-year field. Closes #46. I suspect there are still cases not entirely covered by this implementation, but those can be filed as separate tickets.
cmlenz
parents:
241
diff
changeset
|
755 date = self.value - timedelta(days=day_of_year) |
910a6fe4471d
Finish implementation of day-of-year and day-of-month for now, and fix implementation of year-of-week-of-year field. Closes #46. I suspect there are still cases not entirely covered by this implementation, but those can be filed as separate tickets.
cmlenz
parents:
241
diff
changeset
|
756 week = self.get_week_number(self.get_day_of_year(date), |
910a6fe4471d
Finish implementation of day-of-year and day-of-month for now, and fix implementation of year-of-week-of-year field. Closes #46. I suspect there are still cases not entirely covered by this implementation, but those can be filed as separate tickets.
cmlenz
parents:
241
diff
changeset
|
757 date.weekday()) |
240 | 758 return self.format(week, num) |
239 | 759 else: # week of month |
240 | 760 week = self.get_week_number(self.value.day) |
761 if week == 0: | |
242
910a6fe4471d
Finish implementation of day-of-year and day-of-month for now, and fix implementation of year-of-week-of-year field. Closes #46. I suspect there are still cases not entirely covered by this implementation, but those can be filed as separate tickets.
cmlenz
parents:
241
diff
changeset
|
762 date = self.value - timedelta(days=self.value.day) |
910a6fe4471d
Finish implementation of day-of-year and day-of-month for now, and fix implementation of year-of-week-of-year field. Closes #46. I suspect there are still cases not entirely covered by this implementation, but those can be filed as separate tickets.
cmlenz
parents:
241
diff
changeset
|
763 week = self.get_week_number(date.day, date.weekday()) |
240 | 764 pass |
765 return '%d' % week | |
215
7fcdcdf8972d
Dummy/stub implementation for week-in-year and week-in-month date format fields. Also, treat extended year the same as the regular year field, not even ICU seems to handle it specially.
cmlenz
parents:
129
diff
changeset
|
766 |
15 | 767 def format_weekday(self, char, num): |
768 if num < 3: | |
769 if char.islower(): | |
770 value = 7 - self.locale.first_week_day + self.value.weekday() | |
771 return self.format(value % 7 + 1, num) | |
772 num = 3 | |
773 weekday = self.value.weekday() | |
774 width = {3: 'abbreviated', 4: 'wide', 5: 'narrow'}[num] | |
775 context = {3: 'format', 4: 'format', 5: 'stand-alone'}[num] | |
1 | 776 return get_day_names(width, context, self.locale)[weekday] |
777 | |
221
2af0d1085dd4
Implement day-of-year date format field. Closes #49.
cmlenz
parents:
217
diff
changeset
|
778 def format_day_of_year(self, num): |
239 | 779 return self.format(self.get_day_of_year(), num) |
221
2af0d1085dd4
Implement day-of-year date format field. Closes #49.
cmlenz
parents:
217
diff
changeset
|
780 |
241
15acce6db1da
Implement day-of-week-in-month field in date formatting. Closes #50.
cmlenz
parents:
240
diff
changeset
|
781 def format_day_of_week_in_month(self): |
15acce6db1da
Implement day-of-week-in-month field in date formatting. Closes #50.
cmlenz
parents:
240
diff
changeset
|
782 return '%d' % ((self.value.day - 1) / 7 + 1) |
15acce6db1da
Implement day-of-week-in-month field in date formatting. Closes #50.
cmlenz
parents:
240
diff
changeset
|
783 |
15 | 784 def format_period(self, char): |
1 | 785 period = {0: 'am', 1: 'pm'}[int(self.value.hour > 12)] |
786 return get_period_names(locale=self.locale)[period] | |
787 | |
217 | 788 def format_frac_seconds(self, num): |
216
72813ca69416
Support for fractional seconds field in date formatting. Closes #47.
cmlenz
parents:
215
diff
changeset
|
789 value = str(self.value.microsecond) |
72813ca69416
Support for fractional seconds field in date formatting. Closes #47.
cmlenz
parents:
215
diff
changeset
|
790 return self.format(round(float('.%s' % value), num) * 10**num, num) |
72813ca69416
Support for fractional seconds field in date formatting. Closes #47.
cmlenz
parents:
215
diff
changeset
|
791 |
217 | 792 def format_milliseconds_in_day(self, num): |
793 msecs = self.value.microsecond // 1000 + self.value.second * 1000 + \ | |
794 self.value.minute * 60000 + self.value.hour * 3600000 | |
795 return self.format(msecs, num) | |
796 | |
29 | 797 def format_timezone(self, char, num): |
233
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
798 width = {3: 'short', 4: 'long'}[max(3, num)] |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
799 if char == 'z': |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
800 return get_timezone_name(self.value, width, locale=self.locale) |
29 | 801 elif char == 'Z': |
233
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
802 return get_timezone_gmt(self.value, width) |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
803 elif char == 'v': |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
804 return get_timezone_name(self.value.tzinfo, width, |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
805 locale=self.locale) |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
806 elif char == 'V': |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
807 if num == 1: |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
808 return get_timezone_name(self.value.tzinfo, width, |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
809 uncommon=True, locale=self.locale) |
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
810 return get_timezone_location(self.value.tzinfo, locale=self.locale) |
29 | 811 |
1 | 812 def format(self, value, length): |
813 return ('%%0%dd' % length) % value | |
814 | |
242
910a6fe4471d
Finish implementation of day-of-year and day-of-month for now, and fix implementation of year-of-week-of-year field. Closes #46. I suspect there are still cases not entirely covered by this implementation, but those can be filed as separate tickets.
cmlenz
parents:
241
diff
changeset
|
815 def get_day_of_year(self, date=None): |
910a6fe4471d
Finish implementation of day-of-year and day-of-month for now, and fix implementation of year-of-week-of-year field. Closes #46. I suspect there are still cases not entirely covered by this implementation, but those can be filed as separate tickets.
cmlenz
parents:
241
diff
changeset
|
816 if date is None: |
910a6fe4471d
Finish implementation of day-of-year and day-of-month for now, and fix implementation of year-of-week-of-year field. Closes #46. I suspect there are still cases not entirely covered by this implementation, but those can be filed as separate tickets.
cmlenz
parents:
241
diff
changeset
|
817 date = self.value |
910a6fe4471d
Finish implementation of day-of-year and day-of-month for now, and fix implementation of year-of-week-of-year field. Closes #46. I suspect there are still cases not entirely covered by this implementation, but those can be filed as separate tickets.
cmlenz
parents:
241
diff
changeset
|
818 return (date - date_(date.year, 1, 1)).days + 1 |
239 | 819 |
242
910a6fe4471d
Finish implementation of day-of-year and day-of-month for now, and fix implementation of year-of-week-of-year field. Closes #46. I suspect there are still cases not entirely covered by this implementation, but those can be filed as separate tickets.
cmlenz
parents:
241
diff
changeset
|
820 def get_week_number(self, day_of_period, day_of_week=None): |
239 | 821 """Return the number of the week of a day within a period. This may be |
822 the week number in a year or the week number in a month. | |
823 | |
824 Usually this will return a value equal to or greater than 1, but if the | |
825 first week of the period is so short that it actually counts as the last | |
826 week of the previous period, this function will return 0. | |
827 | |
828 >>> format = DateTimeFormat(date(2006, 1, 8), Locale.parse('de_DE')) | |
829 >>> format.get_week_number(6) | |
830 1 | |
831 | |
832 >>> format = DateTimeFormat(date(2006, 1, 8), Locale.parse('en_US')) | |
833 >>> format.get_week_number(6) | |
834 2 | |
835 | |
836 :param day_of_period: the number of the day in the period (usually | |
837 either the day of month or the day of year) | |
242
910a6fe4471d
Finish implementation of day-of-year and day-of-month for now, and fix implementation of year-of-week-of-year field. Closes #46. I suspect there are still cases not entirely covered by this implementation, but those can be filed as separate tickets.
cmlenz
parents:
241
diff
changeset
|
838 :param day_of_week: the week day; if ommitted, the week day of the |
910a6fe4471d
Finish implementation of day-of-year and day-of-month for now, and fix implementation of year-of-week-of-year field. Closes #46. I suspect there are still cases not entirely covered by this implementation, but those can be filed as separate tickets.
cmlenz
parents:
241
diff
changeset
|
839 current date is assumed |
239 | 840 """ |
242
910a6fe4471d
Finish implementation of day-of-year and day-of-month for now, and fix implementation of year-of-week-of-year field. Closes #46. I suspect there are still cases not entirely covered by this implementation, but those can be filed as separate tickets.
cmlenz
parents:
241
diff
changeset
|
841 if day_of_week is None: |
910a6fe4471d
Finish implementation of day-of-year and day-of-month for now, and fix implementation of year-of-week-of-year field. Closes #46. I suspect there are still cases not entirely covered by this implementation, but those can be filed as separate tickets.
cmlenz
parents:
241
diff
changeset
|
842 day_of_week = self.value.weekday() |
910a6fe4471d
Finish implementation of day-of-year and day-of-month for now, and fix implementation of year-of-week-of-year field. Closes #46. I suspect there are still cases not entirely covered by this implementation, but those can be filed as separate tickets.
cmlenz
parents:
241
diff
changeset
|
843 first_day = (day_of_week - self.locale.first_week_day - |
239 | 844 day_of_period + 1) % 7 |
845 if first_day < 0: | |
846 first_day += 7 | |
847 week_number = (day_of_period + first_day - 1) / 7 | |
848 if 7 - first_day >= self.locale.min_week_days: | |
849 week_number += 1 | |
850 return week_number | |
851 | |
1 | 852 |
853 PATTERN_CHARS = { | |
15 | 854 'G': [1, 2, 3, 4, 5], # era |
855 'y': None, 'Y': None, 'u': None, # year | |
856 'Q': [1, 2, 3, 4], 'q': [1, 2, 3, 4], # quarter | |
857 'M': [1, 2, 3, 4, 5], 'L': [1, 2, 3, 4, 5], # month | |
858 'w': [1, 2], 'W': [1], # week | |
859 'd': [1, 2], 'D': [1, 2, 3], 'F': [1], 'g': None, # day | |
860 'E': [1, 2, 3, 4, 5], 'e': [1, 2, 3, 4, 5], 'c': [1, 3, 4, 5], # week day | |
861 'a': [1], # period | |
862 'h': [1, 2], 'H': [1, 2], 'K': [1, 2], 'k': [1, 2], # hour | |
863 'm': [1, 2], # minute | |
864 's': [1, 2], 'S': None, 'A': None, # second | |
233
da97a3138239
Upgraded to CLDR 1.5 and improved timezone formatting.
cmlenz
parents:
221
diff
changeset
|
865 'z': [1, 2, 3, 4], 'Z': [1, 2, 3, 4], 'v': [1, 4], 'V': [1, 4] # zone |
1 | 866 } |
867 | |
868 def parse_pattern(pattern): | |
869 """Parse date, time, and datetime format patterns. | |
870 | |
871 >>> parse_pattern("MMMMd").format | |
872 u'%(MMMM)s%(d)s' | |
873 >>> parse_pattern("MMM d, yyyy").format | |
874 u'%(MMM)s %(d)s, %(yyyy)s' | |
16 | 875 |
876 Pattern can contain literal strings in single quotes: | |
877 | |
1 | 878 >>> parse_pattern("H:mm' Uhr 'z").format |
879 u'%(H)s:%(mm)s Uhr %(z)s' | |
880 | |
16 | 881 An actual single quote can be used by using two adjacent single quote |
882 characters: | |
883 | |
884 >>> parse_pattern("hh' o''clock'").format | |
885 u"%(hh)s o'clock" | |
886 | |
1 | 887 :param pattern: the formatting pattern to parse |
888 """ | |
12
e6ba3e878b10
* Removed pkg_resources/setuptools requirement from various places.
cmlenz
parents:
8
diff
changeset
|
889 if type(pattern) is DateTimePattern: |
1 | 890 return pattern |
891 | |
892 result = [] | |
893 quotebuf = None | |
894 charbuf = [] | |
895 fieldchar = [''] | |
896 fieldnum = [0] | |
897 | |
898 def append_chars(): | |
899 result.append(''.join(charbuf).replace('%', '%%')) | |
900 del charbuf[:] | |
901 | |
902 def append_field(): | |
903 limit = PATTERN_CHARS[fieldchar[0]] | |
15 | 904 if limit and fieldnum[0] not in limit: |
1 | 905 raise ValueError('Invalid length for field: %r' |
906 % (fieldchar[0] * fieldnum[0])) | |
907 result.append('%%(%s)s' % (fieldchar[0] * fieldnum[0])) | |
908 fieldchar[0] = '' | |
909 fieldnum[0] = 0 | |
910 | |
16 | 911 for idx, char in enumerate(pattern.replace("''", '\0')): |
1 | 912 if quotebuf is None: |
913 if char == "'": # quote started | |
914 if fieldchar[0]: | |
915 append_field() | |
916 elif charbuf: | |
917 append_chars() | |
918 quotebuf = [] | |
919 elif char in PATTERN_CHARS: | |
920 if charbuf: | |
921 append_chars() | |
922 if char == fieldchar[0]: | |
923 fieldnum[0] += 1 | |
924 else: | |
925 if fieldchar[0]: | |
926 append_field() | |
927 fieldchar[0] = char | |
928 fieldnum[0] = 1 | |
929 else: | |
930 if fieldchar[0]: | |
931 append_field() | |
932 charbuf.append(char) | |
933 | |
934 elif quotebuf is not None: | |
16 | 935 if char == "'": # end of quote |
1 | 936 charbuf.extend(quotebuf) |
937 quotebuf = None | |
938 else: # inside quote | |
939 quotebuf.append(char) | |
940 | |
941 if fieldchar[0]: | |
942 append_field() | |
943 elif charbuf: | |
944 append_chars() | |
945 | |
16 | 946 return DateTimePattern(pattern, u''.join(result).replace('\0', "'")) |