Skip to content

Commit

Permalink
Add Kml DateTime class
Browse files Browse the repository at this point in the history
  • Loading branch information
cleder committed Jan 13, 2023
1 parent 18550d3 commit 56955a0
Showing 1 changed file with 90 additions and 0 deletions.
90 changes: 90 additions & 0 deletions fastkml/times.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,94 @@
year_month = re.compile(r"^(?P<year>\d{4})(?:-?)(?P<month>\d{2})$")


class KmlDateTime:
"""A KML DateTime object.
This class is used to parse and format KML DateTime objects.
A KML DateTime object is a string that conforms to the ISO 8601 standard
for date and time representation. The following formats are supported:
- yyyy-mm-ddThh:mm:sszzzzzz
- yyyy-mm-ddThh:mm:ss
- yyyy-mm-dd
- yyyy-mm
- yyyy
The T is the separator between the date and the time, and the time zone
is either Z (for UTC) or zzzzzz, which represents ±hh:mm in relation to
UTC. Additionally, the value can be expressed as a date only.
The precision of the DateTime is dictated by the DateTime value
which can be one of the following:
- dateTime gives second resolution
- date gives day resolution
- gYearMonth gives month resolution
- gYear gives year resolution
The KmlDateTime class can be used to parse a KML DateTime string into a
Python datetime object, or to format a Python datetime object into a
KML DateTime string.
The KmlDateTime class is used by the TimeStamp and TimeSpan classes.
"""

def __init__(
self,
dt: Union[date, datetime],
resolution: Optional[str] = None,
):
"""Initialize a KmlDateTime object."""
self.dt = dt
self.resolution = resolution
if resolution is None:
# sourcery skip: swap-if-expression
self.resolution = "date" if not isinstance(dt, datetime) else "dateTime"

def __str__(self) -> str:
"""Return the KML DateTime string representation of the object."""
if self.resolution == "gYear":
return self.dt.strftime("%Y")
if self.resolution == "gYearMonth":
return self.dt.strftime("%Y-%m")
if self.resolution == "date":
return (
self.dt.date().isoformat()
if isinstance(self.dt, datetime)
else self.dt.isoformat()
)
if self.resolution == "dateTime":
return self.dt.isoformat()
raise ValueError

@classmethod
def parse(cls, datestr: str) -> "KmlDateTime":
"""Parse a KML DateTime string into a KmlDateTime object."""
resolution = None
dt = None
if len(datestr) == 4:
year = int(datestr)
dt = datetime(year, 1, 1)
resolution = "gYear"
elif len(datestr) in {6, 7}:
ym = year_month.match(datestr)
if ym:
year = int(ym.group("year"))
month = int(ym.group("month"))
dt = datetime(year, month, 1)
resolution = "gYearMonth"
elif len(datestr) in {8, 10}: # 8 is YYYYMMDDS
dt = dateutil.parser.parse(datestr)
resolution = "date"
elif len(datestr) > 10:
dt = dateutil.parser.parse(datestr)
resolution = "dateTime"
if dt is None:
raise ValueError
return cls(dt, resolution)


class _TimePrimitive(_BaseObject):
"""The dateTime is defined according to XML Schema time.
The value can be expressed as yyyy-mm-ddThh:mm:sszzzzzz, where T is
Expand All @@ -37,6 +125,8 @@ class _TimePrimitive(_BaseObject):
- date gives day resolution
- gYearMonth gives month resolution
- gYear gives year resolution
https://developers.google.com/kml/documentation/kmlreference#timeprimitive
"""

RESOLUTIONS = ["gYear", "gYearMonth", "date", "dateTime"]
Expand Down

0 comments on commit 56955a0

Please sign in to comment.