Skip to content

Commit 2cea849

Browse files
committed
runtime: extend builtin function DATETIME function support for time
1 parent fd57cd0 commit 2cea849

2 files changed

Lines changed: 56 additions & 9 deletions

File tree

fluent.runtime/fluent/runtime/types.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import warnings
2-
from datetime import date, datetime
2+
from datetime import date, datetime, time
33
from decimal import Decimal
44

55
import attr
@@ -297,8 +297,11 @@ class FluentDateType(FluentType):
297297
# So we leave those alone, and implement another `_init_options`
298298
# which is called from other constructors.
299299
def _init_options(self, dt_obj: Union[date, datetime], kwargs: Dict[str, Any]) -> None:
300-
if 'timeStyle' in kwargs and not isinstance(self, datetime):
301-
raise TypeError("timeStyle option can only be specified for datetime instances, not date instance")
300+
if 'timeStyle' in kwargs and not isinstance(self, (datetime, time)):
301+
raise TypeError("timeStyle option can only be specified for datetime or time instances, not date instance")
302+
303+
if 'dateStyle' in kwargs and not isinstance(self, (datetime, date)):
304+
raise TypeError("dateStyle option can only be specified for datetime or time instances, not date instance")
302305

303306
self.options = merge_options(DateFormatOptions,
304307
getattr(dt_obj, 'options', None),
@@ -308,18 +311,18 @@ def _init_options(self, dt_obj: Union[date, datetime], kwargs: Dict[str, Any]) -
308311
warnings.warn(f"FluentDateType option {k} is not yet supported")
309312

310313
def format(self, locale: Locale) -> str:
311-
if isinstance(self, datetime):
314+
if isinstance(self, (datetime, time)):
312315
selftz = _ensure_datetime_tzinfo(self, tzinfo=self.options.timeZone)
313316
else:
314317
selftz = cast(datetime, self)
315318

316319
ds = self.options.dateStyle
317320
ts = self.options.timeStyle
318321
if ds is None:
319-
if ts is None:
322+
if ts is None and not isinstance(selftz, time):
320323
return format_date(selftz, format='medium', locale=locale)
321324
else:
322-
return format_time(selftz, format=ts, locale=locale)
325+
return format_time(selftz, format=ts or 'short', locale=locale)
323326
elif ts is None:
324327
return format_date(selftz, format=ds, locale=locale)
325328

@@ -333,7 +336,7 @@ def format(self, locale: Locale) -> str:
333336
.replace('{1}', format_date(selftz, ds, locale=locale)))
334337

335338

336-
def _ensure_datetime_tzinfo(dt: datetime, tzinfo: Union[str, None] = None) -> datetime:
339+
def _ensure_datetime_tzinfo(dt: Union[datetime, time], tzinfo: Union[str, None] = None) -> Union[datetime, time]:
337340
"""
338341
Ensure the datetime passed has an attached tzinfo.
339342
"""
@@ -353,6 +356,15 @@ def from_date(cls, dt_obj: date, **kwargs: Any) -> 'FluentDate':
353356
return obj
354357

355358

359+
class FluentTime(FluentDateType, time):
360+
@classmethod
361+
def from_time(cls, dt_obj: time, **kwargs) -> 'FluentTime':
362+
obj = cls(dt_obj.hour, dt_obj.minute, dt_obj.second,
363+
dt_obj.microsecond, tzinfo=dt_obj.tzinfo)
364+
obj._init_options(dt_obj, kwargs)
365+
return obj
366+
367+
356368
class FluentDateTime(FluentDateType, datetime):
357369
@classmethod
358370
def from_date_time(cls, dt_obj: datetime, **kwargs: Any) -> 'FluentDateTime':
@@ -371,6 +383,8 @@ def fluent_date(
371383
return dt
372384
if isinstance(dt, datetime):
373385
return FluentDateTime.from_date_time(dt, **kwargs)
386+
elif isinstance(dt, time):
387+
return FluentTime.from_time(dt, **kwargs)
374388
elif isinstance(dt, date):
375389
return FluentDate.from_date(dt, **kwargs)
376390
elif isinstance(dt, FluentNone):

fluent.runtime/tests/test_types.py

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import unittest
22
import warnings
3-
from datetime import date, datetime
3+
from datetime import date, datetime, time
44
from decimal import Decimal
55

66
import pytz
@@ -166,6 +166,8 @@ def setUp(self):
166166
self.a_date = date(2018, 2, 1)
167167
self.a_datetime = datetime(2018, 2, 1, 14, 15, 16, 123456,
168168
tzinfo=pytz.UTC)
169+
self.a_time = time(10, 31, 00, 333,
170+
tzinfo=pytz.UTC)
169171

170172
def test_date(self):
171173
fd = fluent_date(self.a_date)
@@ -175,6 +177,16 @@ def test_date(self):
175177
self.assertEqual(fd.month, self.a_date.month)
176178
self.assertEqual(fd.day, self.a_date.day)
177179

180+
def test_time(self):
181+
fd = fluent_date(self.a_time)
182+
self.assertTrue(isinstance(fd, time))
183+
self.assertTrue(isinstance(fd, FluentDateType))
184+
self.assertEqual(fd.hour, self.a_time.hour)
185+
self.assertEqual(fd.minute, self.a_time.minute)
186+
self.assertEqual(fd.second, self.a_time.second)
187+
self.assertEqual(fd.microsecond, self.a_time.microsecond)
188+
self.assertEqual(fd.tzinfo, self.a_time.tzinfo)
189+
178190
def test_datetime(self):
179191
fd = fluent_date(self.a_datetime)
180192
self.assertTrue(isinstance(fd, datetime))
@@ -188,13 +200,27 @@ def test_datetime(self):
188200
self.assertEqual(fd.microsecond, self.a_datetime.microsecond)
189201
self.assertEqual(fd.tzinfo, self.a_datetime.tzinfo)
190202

191-
def test_format_defaults(self):
203+
def test_date_format_defaults(self):
192204
fd = fluent_date(self.a_date)
193205
en_US = Locale.parse('en_US')
194206
en_GB = Locale.parse('en_GB')
195207
self.assertEqual(fd.format(en_GB), '1 Feb 2018')
196208
self.assertEqual(fd.format(en_US), 'Feb 1, 2018')
197209

210+
def test_time_format_defaults(self):
211+
fd = fluent_date(self.a_time)
212+
en_US = Locale.parse('en_US')
213+
en_GB = Locale.parse('en_GB')
214+
self.assertEqual(fd.format(en_GB), '10:31')
215+
self.assertRegex(fd.format(en_US), '^10:31\\sAM$')
216+
217+
def test_datetime_format_defaults(self):
218+
fd = fluent_date(self.a_datetime)
219+
en_US = Locale.parse('en_US')
220+
en_GB = Locale.parse('en_GB')
221+
self.assertEqual(fd.format(en_GB), '1 Feb 2018')
222+
self.assertEqual(fd.format(en_US), 'Feb 1, 2018')
223+
198224
def test_dateStyle_date(self):
199225
fd = fluent_date(self.a_date, dateStyle='long')
200226
en_US = Locale.parse('en_US')
@@ -216,6 +242,13 @@ def test_timeStyle_datetime(self):
216242
self.assertRegex(fd.format(en_US), '^2:15\\sPM$')
217243
self.assertEqual(fd.format(en_GB), '14:15')
218244

245+
def test_timeStyle_time(self):
246+
fd = fluent_date(self.a_datetime.time(), timeStyle='short')
247+
en_US = Locale.parse('en_US')
248+
en_GB = Locale.parse('en_GB')
249+
self.assertRegex(fd.format(en_US), '^2:15\\sPM$')
250+
self.assertEqual(fd.format(en_GB), '14:15')
251+
219252
def test_dateStyle_and_timeStyle_datetime(self):
220253
fd = fluent_date(self.a_datetime, timeStyle='short', dateStyle='short')
221254
en_US = Locale.parse('en_US')

0 commit comments

Comments
 (0)