diff options
Diffstat (limited to 'scripts/rpki/sundial.py')
-rw-r--r-- | scripts/rpki/sundial.py | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/scripts/rpki/sundial.py b/scripts/rpki/sundial.py new file mode 100644 index 00000000..2360732d --- /dev/null +++ b/scripts/rpki/sundial.py @@ -0,0 +1,110 @@ +# $Id$ + +"""Unified RPKI date/time handling, based on the standard Python datetime module. + +Module name chosen to sidestep a nightmare of import-related errors +that occur with the more obvious module names. +""" + +import datetime as pydatetime + +class datetime(pydatetime.datetime): + """RPKI extensions to standard datetime.datetime class. All work + here is in UTC, so we use naive datetime objects. + """ + + def totimestamp(self): + """Convert to seconds from epoch (like time.time()). Conversion + method is a bit silly, but avoids time module timezone whackiness. + """ + return int(self.strftime("%s")) + + @classmethod + def fromUTCTime(cls, x): + """Convert from ASN.1 UTCTime.""" + return cls.strptime(x, "%y%m%d%H%M%SZ") + + def toUTCTime(self): + """Convert to ASN.1 UTCTime.""" + return self.strftime("%y%m%d%H%M%SZ") + + @classmethod + def fromGeneralizedTime(cls, x): + """Convert from ASN.1 GeneralizedTime.""" + return cls.strptime(x, "%Y%m%d%H%M%SZ") + + def toGeneralizedTime(self): + """Convert to ASN.1 GeneralizedTime.""" + return self.strftime("%Y%m%d%H%M%SZ") + + @classmethod + def fromASN1tuple(cls, x): + """Convert from ASN.1 tuple representation.""" + assert isinstance(x, tuple) and len(x) == 2 and x[0] in ("utcTime", "generalTime") + if x[0] == "utcTime": + return cls.fromUTCTime(x) + else: + return cls.fromGeneralizedTime(x) + + ## @var PKIX_threshhold + # Threshold specified in RFC 3280 for switchover from UTCTime to GeneralizedTime. + + PKIX_threshhold = pydatetime.datetime(2050, 1, 1) + + def toASN1tuple(self): + """Convert to ASN.1 tuple representation.""" + if self < self.PKIX_threshhold: + return "utcTime", self.toUTCTime() + else: + return "generalTime", self.toGeneralizedTime() + + @classmethod + def fromXMLtime(cls, x): + """Convert from XML time representation.""" + return cls.strptime(x, "%Y-%m-%dT%H:%M:%SZ") + + def toXMLtime(self): + """Convert to XML time representation.""" + return self.strftime("%Y-%m-%dT%H:%M:%SZ") + + @classmethod + def _cast(cls, x): + """Convert a datetime.datetime object into this subclass. + This is whacky due to the weird constructors for datetime. + """ + return cls.combine(x.date(), x.time()) + + def __add__(self, other): + """Force correct class for timedelta results.""" + return self._cast(pydatetime.datetime.__add__(self, other)) + + def __sub__(self, other): + """Force correct class for timedelta results.""" + return self._cast(pydatetime.datetime.__sub__(self, other)) + +# Alias to simplify imports for callers + +timedelta = pydatetime.timedelta + +if __name__ == "__main__": + + now = datetime.utcnow() + print now + print repr(now) + print now.strftime("%s") + print now.toUTCTime() + print now.toGeneralizedTime() + print now.toASN1tuple() + print now.toXMLtime() + + print + + then = now + then += timedelta(days = 30) + print then + print repr(then) + print then.strftime("%s") + print then.toUTCTime() + print then.toGeneralizedTime() + print then.toASN1tuple() + print then.toXMLtime() |