Decode a JSON datetime to python datetime.datetime.
(
doc: Any, json_options: JSONOptions
)
| 596 | |
| 597 | |
| 598 | def _parse_canonical_datetime( |
| 599 | doc: Any, json_options: JSONOptions |
| 600 | ) -> Union[datetime.datetime, DatetimeMS]: |
| 601 | """Decode a JSON datetime to python datetime.datetime.""" |
| 602 | dtm = doc["$date"] |
| 603 | if len(doc) != 1: |
| 604 | raise TypeError(f"Bad $date, extra field(s): {doc}") |
| 605 | # mongoexport 2.6 and newer |
| 606 | if isinstance(dtm, str): |
| 607 | try: |
| 608 | # Parse offset |
| 609 | if dtm[-1] == "Z": |
| 610 | dt = dtm[:-1] |
| 611 | offset = "Z" |
| 612 | elif dtm[-6] in ("+", "-") and dtm[-3] == ":": |
| 613 | # (+|-)HH:MM |
| 614 | dt = dtm[:-6] |
| 615 | offset = dtm[-6:] |
| 616 | elif dtm[-5] in ("+", "-"): |
| 617 | # (+|-)HHMM |
| 618 | dt = dtm[:-5] |
| 619 | offset = dtm[-5:] |
| 620 | elif dtm[-3] in ("+", "-"): |
| 621 | # (+|-)HH |
| 622 | dt = dtm[:-3] |
| 623 | offset = dtm[-3:] |
| 624 | else: |
| 625 | dt = dtm |
| 626 | offset = "" |
| 627 | except IndexError as exc: |
| 628 | raise ValueError(f"time data {dtm!r} does not match ISO-8601 datetime format") from exc |
| 629 | |
| 630 | # Parse the optional factional seconds portion. |
| 631 | dot_index = dt.rfind(".") |
| 632 | microsecond = 0 |
| 633 | if dot_index != -1: |
| 634 | microsecond = int(float(dt[dot_index:]) * 1000000) |
| 635 | dt = dt[:dot_index] |
| 636 | |
| 637 | aware = datetime.datetime.strptime(dt, "%Y-%m-%dT%H:%M:%S").replace( |
| 638 | microsecond=microsecond, tzinfo=utc |
| 639 | ) |
| 640 | |
| 641 | if offset and offset != "Z": |
| 642 | if len(offset) == 6: |
| 643 | hours, minutes = offset[1:].split(":") |
| 644 | secs = int(hours) * 3600 + int(minutes) * 60 |
| 645 | elif len(offset) == 5: |
| 646 | secs = int(offset[1:3]) * 3600 + int(offset[3:]) * 60 |
| 647 | elif len(offset) == 3: |
| 648 | secs = int(offset[1:3]) * 3600 |
| 649 | if offset[0] == "-": |
| 650 | secs *= -1 |
| 651 | aware = aware - datetime.timedelta(seconds=secs) |
| 652 | |
| 653 | if json_options.tz_aware: |
| 654 | if json_options.tzinfo: |
| 655 | aware = aware.astimezone(json_options.tzinfo) |
nothing calls this directly
no test coverage detected