|
| 1 | +import datetime |
| 2 | +from typing import Any, Literal, Optional |
| 3 | + |
| 4 | +from .. import settings |
| 5 | +from ..platform import platform |
| 6 | +from .base_field_descriptor import BaseFieldDescriptor |
| 7 | +from .field_constraints import ValueConstraints |
| 8 | + |
| 9 | + |
| 10 | +class DatetimeFieldDescriptor(BaseFieldDescriptor): |
| 11 | + """The field contains a date with a time.""" |
| 12 | + |
| 13 | + type: Literal["datetime"] = "datetime" |
| 14 | + format: Optional[str] = None |
| 15 | + constraints: Optional[ValueConstraints[datetime.datetime]] = None |
| 16 | + |
| 17 | + def read_value(self, cell: Any) -> Optional[datetime.datetime]: |
| 18 | + if not isinstance(cell, datetime.datetime): |
| 19 | + if not isinstance(cell, str): |
| 20 | + return None |
| 21 | + try: |
| 22 | + format_value = self.format or "default" |
| 23 | + if format_value == "default": |
| 24 | + # Guard against shorter formats supported by dateutil |
| 25 | + assert cell[16] == ":" |
| 26 | + assert len(cell) >= 19 |
| 27 | + cell = platform.dateutil_parser.isoparse(cell) |
| 28 | + elif format_value == "any": |
| 29 | + cell = platform.dateutil_parser.parse(cell) |
| 30 | + else: |
| 31 | + cell = datetime.datetime.strptime(cell, format_value) |
| 32 | + except Exception: |
| 33 | + return None |
| 34 | + return cell |
| 35 | + |
| 36 | + def write_value(self, cell: Optional[datetime.datetime]) -> Optional[str]: |
| 37 | + if cell is None: |
| 38 | + return None |
| 39 | + format_value = self.format or "default" |
| 40 | + if format_value == settings.DEFAULT_FIELD_FORMAT: |
| 41 | + format_value = settings.DEFAULT_DATETIME_PATTERN |
| 42 | + result = cell.strftime(format_value) |
| 43 | + result = result.replace("+0000", "Z") |
| 44 | + return result |
0 commit comments