1# 2# This file is part of pyasn1 software. 3# 4# Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com> 5# License: http://snmplabs.com/pyasn1/license.html 6# 7import datetime 8 9from pyasn1 import error 10from pyasn1.compat import dateandtime 11from pyasn1.compat import string 12from pyasn1.type import char 13from pyasn1.type import tag 14from pyasn1.type import univ 15 16__all__ = ['ObjectDescriptor', 'GeneralizedTime', 'UTCTime'] 17 18NoValue = univ.NoValue 19noValue = univ.noValue 20 21 22class ObjectDescriptor(char.GraphicString): 23 __doc__ = char.GraphicString.__doc__ 24 25 #: Default :py:class:`~pyasn1.type.tag.TagSet` object for |ASN.1| objects 26 tagSet = char.GraphicString.tagSet.tagImplicitly( 27 tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 7) 28 ) 29 30 # Optimization for faster codec lookup 31 typeId = char.GraphicString.getTypeId() 32 33 34class TimeMixIn(object): 35 36 _yearsDigits = 4 37 _hasSubsecond = False 38 _optionalMinutes = False 39 _shortTZ = False 40 41 class FixedOffset(datetime.tzinfo): 42 """Fixed offset in minutes east from UTC.""" 43 44 # defaulted arguments required 45 # https: // docs.python.org / 2.3 / lib / datetime - tzinfo.html 46 def __init__(self, offset=0, name='UTC'): 47 self.__offset = datetime.timedelta(minutes=offset) 48 self.__name = name 49 50 def utcoffset(self, dt): 51 return self.__offset 52 53 def tzname(self, dt): 54 return self.__name 55 56 def dst(self, dt): 57 return datetime.timedelta(0) 58 59 UTC = FixedOffset() 60 61 @property 62 def asDateTime(self): 63 """Create :py:class:`datetime.datetime` object from a |ASN.1| object. 64 65 Returns 66 ------- 67 : 68 new instance of :py:class:`datetime.datetime` object 69 """ 70 text = str(self) 71 if text.endswith('Z'): 72 tzinfo = TimeMixIn.UTC 73 text = text[:-1] 74 75 elif '-' in text or '+' in text: 76 if '+' in text: 77 text, plusminus, tz = string.partition(text, '+') 78 else: 79 text, plusminus, tz = string.partition(text, '-') 80 81 if self._shortTZ and len(tz) == 2: 82 tz += '00' 83 84 if len(tz) != 4: 85 raise error.PyAsn1Error('malformed time zone offset %s' % tz) 86 87 try: 88 minutes = int(tz[:2]) * 60 + int(tz[2:]) 89 if plusminus == '-': 90 minutes *= -1 91 92 except ValueError: 93 raise error.PyAsn1Error('unknown time specification %s' % self) 94 95 tzinfo = TimeMixIn.FixedOffset(minutes, '?') 96 97 else: 98 tzinfo = None 99 100 if '.' in text or ',' in text: 101 if '.' in text: 102 text, _, ms = string.partition(text, '.') 103 else: 104 text, _, ms = string.partition(text, ',') 105 106 try: 107 ms = int(ms) * 1000 108 109 except ValueError: 110 raise error.PyAsn1Error('bad sub-second time specification %s' % self) 111 112 else: 113 ms = 0 114 115 if self._optionalMinutes and len(text) - self._yearsDigits == 6: 116 text += '0000' 117 elif len(text) - self._yearsDigits == 8: 118 text += '00' 119 120 try: 121 dt = dateandtime.strptime(text, self._yearsDigits == 4 and '%Y%m%d%H%M%S' or '%y%m%d%H%M%S') 122 123 except ValueError: 124 raise error.PyAsn1Error('malformed datetime format %s' % self) 125 126 return dt.replace(microsecond=ms, tzinfo=tzinfo) 127 128 @classmethod 129 def fromDateTime(cls, dt): 130 """Create |ASN.1| object from a :py:class:`datetime.datetime` object. 131 132 Parameters 133 ---------- 134 dt: :py:class:`datetime.datetime` object 135 The `datetime.datetime` object to initialize the |ASN.1| object 136 from 137 138 Returns 139 ------- 140 : 141 new instance of |ASN.1| value 142 """ 143 text = dt.strftime(cls._yearsDigits == 4 and '%Y%m%d%H%M%S' or '%y%m%d%H%M%S') 144 if cls._hasSubsecond: 145 text += '.%d' % (dt.microsecond // 1000) 146 147 if dt.utcoffset(): 148 seconds = dt.utcoffset().seconds 149 if seconds < 0: 150 text += '-' 151 else: 152 text += '+' 153 text += '%.2d%.2d' % (seconds // 3600, seconds % 3600) 154 else: 155 text += 'Z' 156 157 return cls(text) 158 159 160class GeneralizedTime(char.VisibleString, TimeMixIn): 161 __doc__ = char.VisibleString.__doc__ 162 163 #: Default :py:class:`~pyasn1.type.tag.TagSet` object for |ASN.1| objects 164 tagSet = char.VisibleString.tagSet.tagImplicitly( 165 tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 24) 166 ) 167 168 # Optimization for faster codec lookup 169 typeId = char.VideotexString.getTypeId() 170 171 _yearsDigits = 4 172 _hasSubsecond = True 173 _optionalMinutes = True 174 _shortTZ = True 175 176 177class UTCTime(char.VisibleString, TimeMixIn): 178 __doc__ = char.VisibleString.__doc__ 179 180 #: Default :py:class:`~pyasn1.type.tag.TagSet` object for |ASN.1| objects 181 tagSet = char.VisibleString.tagSet.tagImplicitly( 182 tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 23) 183 ) 184 185 # Optimization for faster codec lookup 186 typeId = char.VideotexString.getTypeId() 187 188 _yearsDigits = 2 189 _hasSubsecond = False 190 _optionalMinutes = False 191 _shortTZ = False 192