Skip to content

Commit

Permalink
Require formatter to_string to support undate and undate interval
Browse files Browse the repository at this point in the history
  • Loading branch information
rlskoeser committed Aug 29, 2024
1 parent c65bc3e commit 640705c
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 4 deletions.
4 changes: 2 additions & 2 deletions src/undate/dateformat/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
import importlib
import logging
import pkgutil
from typing import Dict, Type
from functools import lru_cache # functools.cache not available until 3.9
from typing import Dict, Type, Union
from functools import lru_cache


logger = logging.getLogger(__name__)
Expand Down
12 changes: 11 additions & 1 deletion src/undate/dateformat/edtf/formatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,17 @@ def _convert_missing_digits(
return value.replace(old_missing_digit, EDTF_UNSPECIFIED_DIGIT)
return None

def to_string(self, undate: Undate) -> str:
def to_string(self, undate: Union[Undate, UndateInterval]) -> str:
if isinstance(undate, Undate):
return self._undate_to_string(undate)
elif isinstance(undate, UndateInterval):
# NOTE: what is the difference between an open interval and unknown start/end?
# spec distinguishes between these, open is ".." but unknown is ""
start = self._undate_to_string(undate.earliest) if undate.earliest else ".."
end = self._undate_to_string(undate.latest) if undate.latest else ".."
return f"{start}/{end}"

def _undate_to_string(self, undate: Undate) -> str:
# in theory it's possible to use the parser and reconstruct using a tree,
# but that seems much more complicated and would be harder to read
parts = []
Expand Down
15 changes: 14 additions & 1 deletion src/undate/dateformat/iso8601.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,25 @@ def _parse_single_date(self, value: str) -> Undate:
# Argument of type "int | None" cannot be assigned to parameter "formatter" of type "BaseDateFormat | None" in function "__init__"
return Undate(*date_parts) # type: ignore

def to_string(self, undate: Undate) -> str:
def to_string(self, undate: Union[Undate, UndateInterval]) -> str:
if isinstance(undate, Undate):
return self._undate_to_string(undate)
elif isinstance(undate, UndateInterval):
# strictly speaking I don't think ISO8601 supports open-ended ranges
# should we add an exception for dates that can't be represented by a particular format?
# (we'll likely need it for uncertain/approx, which ISO8601 doesn't handle')
start = self._undate_to_string(undate.earliest) if undate.earliest else ""
end = self._undate_to_string(undate.latest) if undate.latest else ""
return f"{start}/{end}"

def _undate_to_string(self, undate: Undate) -> str:
# serialize to iso format for simplicity, for now
date_parts: List[Union[str, None]] = []
# for each part of the date that is known, generate the string format
# then combine
# TODO: should error if we have year and day but no month
# TODO: may want to refactor and take advantage of the year/month/day properties
# added for use in EDTF formatter code
for date_portion, iso_format in self.iso_format.items():
if undate.is_known(date_portion):
# NOTE: datetime strftime for %Y for 3-digit year
Expand Down

0 comments on commit 640705c

Please sign in to comment.