aboutsummaryrefslogtreecommitdiff
path: root/scripts/rpki/sundial.py
blob: 2360732de8586efaae292702d6e85a0a0eac76ea (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
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()