import re
import numpy as np
[docs]class AnyCalendarDateTime:
"""
A class to represent a datetime that could be of any calendar.
Has the ability to add and subtract a day from the input based on MAX_DAY, MIN_DAY, MAX_MONTH and MIN_MONTH
"""
MONTH_RANGE = range(1, 13)
# 31 is the maximum number of days in any month in any of the calendars supported by cftime
DAY_RANGE = range(1, 32)
HOUR_RANGE = range(0, 24)
MINUTE_RANGE = range(0, 60)
SECOND_RANGE = range(0, 60)
def __init__(self, year, month, day, hour, minute, second):
self.year = year
self.month = month
self.validate_input(self.month, "month", self.MONTH_RANGE)
self.day = day
self.validate_input(self.day, "day", self.DAY_RANGE)
self.hour = hour
self.validate_input(self.hour, "hour", self.HOUR_RANGE)
self.minute = minute
self.validate_input(self.minute, "minute", self.MINUTE_RANGE)
self.second = second
self.validate_input(self.second, "second", self.SECOND_RANGE)
def __repr__(self):
return self.value
@property
def value(self):
return (
f"{self.year}-{self.month:02d}-{self.day:02d}"
f"T{self.hour:02d}:{self.minute:02d}:{self.second:02d}"
)
[docs] def add_day(self):
"""
Add a day to the input datetime.
"""
self.day += 1
if self.day > self.DAY_RANGE[-1]:
self.month += 1
self.day = 1
if self.month > self.MONTH_RANGE[-1]:
self.year += 1
self.month = self.MONTH_RANGE[0]
[docs] def sub_day(self, n=1):
"""
Subtract a day to the input datetime.
"""
self.day -= 1
if self.day < self.DAY_RANGE[0]:
self.month -= 1
self.day = self.DAY_RANGE[-1]
if self.month < self.MONTH_RANGE[0]:
self.year -= 1
self.month = self.MONTH_RANGE[-1]
[docs]def str_to_AnyCalendarDateTime(dt):
"""
Takes a string representing date/time and returns a DateTimeAnyTime object.
String formats should start with Year and go through to Second, but you
can miss out anything from month onwards.
:param dt: string representing a date/time [string]
:return: AnyCalendarDateTime object
"""
if len(dt) < 1:
raise Exception(
"Must provide at least the year as argument to create date time."
)
# Start with most common pattern
regex = re.compile(r"^(\d+)-(\d+)-(\d+)[T ](\d+):(\d+):(\d+)$")
match = regex.match(dt)
if match:
items = match.groups()
else:
# Try a more complex split and build of the time string
defaults = [-1, 1, 1, 0, 0, 0]
components = re.split("[- T:]", dt)
# Build a list of time components
items = components + defaults[len(components) :]
return AnyCalendarDateTime(*[int(i) for i in items])