blob: 7536b95cee68af0b608e85791eec3fe0b4c9bf14 [file] [log] [blame]
#
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
# License: http://snmplabs.com/pyasn1/license.html
#
import datetime
from pyasn1 import error
from pyasn1.compat import dateandtime
from pyasn1.compat import string
from pyasn1.type import char
from pyasn1.type import tag
from pyasn1.type import univ
__all__ = ['ObjectDescriptor', 'GeneralizedTime', 'UTCTime']
NoValue = univ.NoValue
noValue = univ.noValue
class ObjectDescriptor(char.GraphicString):
__doc__ = char.GraphicString.__doc__
#: Default :py:class:`~pyasn1.type.tag.TagSet` object for |ASN.1| objects
tagSet = char.GraphicString.tagSet.tagImplicitly(
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 7)
)
# Optimization for faster codec lookup
typeId = char.GraphicString.getTypeId()
class TimeMixIn(object):
_yearsDigits = 4
_hasSubsecond = False
_optionalMinutes = False
_shortTZ = False
class FixedOffset(datetime.tzinfo):
"""Fixed offset in minutes east from UTC."""
# defaulted arguments required
# https: // docs.python.org / 2.3 / lib / datetime - tzinfo.html
def __init__(self, offset=0, name='UTC'):
self.__offset = datetime.timedelta(minutes=offset)
self.__name = name
def utcoffset(self, dt):
return self.__offset
def tzname(self, dt):
return self.__name
def dst(self, dt):
return datetime.timedelta(0)
UTC = FixedOffset()
@property
def asDateTime(self):
"""Create :py:class:`datetime.datetime` object from a |ASN.1| object.
Returns
-------
:
new instance of :py:class:`datetime.datetime` object
"""
text = str(self)
if text.endswith('Z'):
tzinfo = TimeMixIn.UTC
text = text[:-1]
elif '-' in text or '+' in text:
if '+' in text:
text, plusminus, tz = string.partition(text, '+')
else:
text, plusminus, tz = string.partition(text, '-')
if self._shortTZ and len(tz) == 2:
tz += '00'
if len(tz) != 4:
raise error.PyAsn1Error('malformed time zone offset %s' % tz)
try:
minutes = int(tz[:2]) * 60 + int(tz[2:])
if plusminus == '-':
minutes *= -1
except ValueError:
raise error.PyAsn1Error('unknown time specification %s' % self)
tzinfo = TimeMixIn.FixedOffset(minutes, '?')
else:
tzinfo = None
if '.' in text or ',' in text:
if '.' in text:
text, _, ms = string.partition(text, '.')
else:
text, _, ms = string.partition(text, ',')
try:
ms = int(ms) * 1000
except ValueError:
raise error.PyAsn1Error('bad sub-second time specification %s' % self)
else:
ms = 0
if self._optionalMinutes and len(text) - self._yearsDigits == 6:
text += '0000'
elif len(text) - self._yearsDigits == 8:
text += '00'
try:
dt = dateandtime.strptime(text, self._yearsDigits == 4 and '%Y%m%d%H%M%S' or '%y%m%d%H%M%S')
except ValueError:
raise error.PyAsn1Error('malformed datetime format %s' % self)
return dt.replace(microsecond=ms, tzinfo=tzinfo)
@classmethod
def fromDateTime(cls, dt):
"""Create |ASN.1| object from a :py:class:`datetime.datetime` object.
Parameters
----------
dt: :py:class:`datetime.datetime` object
The `datetime.datetime` object to initialize the |ASN.1| object
from
Returns
-------
:
new instance of |ASN.1| value
"""
text = dt.strftime(cls._yearsDigits == 4 and '%Y%m%d%H%M%S' or '%y%m%d%H%M%S')
if cls._hasSubsecond:
text += '.%d' % (dt.microsecond // 1000)
if dt.utcoffset():
seconds = dt.utcoffset().seconds
if seconds < 0:
text += '-'
else:
text += '+'
text += '%.2d%.2d' % (seconds // 3600, seconds % 3600)
else:
text += 'Z'
return cls(text)
class GeneralizedTime(char.VisibleString, TimeMixIn):
__doc__ = char.VisibleString.__doc__
#: Default :py:class:`~pyasn1.type.tag.TagSet` object for |ASN.1| objects
tagSet = char.VisibleString.tagSet.tagImplicitly(
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 24)
)
# Optimization for faster codec lookup
typeId = char.VideotexString.getTypeId()
_yearsDigits = 4
_hasSubsecond = True
_optionalMinutes = True
_shortTZ = True
class UTCTime(char.VisibleString, TimeMixIn):
__doc__ = char.VisibleString.__doc__
#: Default :py:class:`~pyasn1.type.tag.TagSet` object for |ASN.1| objects
tagSet = char.VisibleString.tagSet.tagImplicitly(
tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 23)
)
# Optimization for faster codec lookup
typeId = char.VideotexString.getTypeId()
_yearsDigits = 2
_hasSubsecond = False
_optionalMinutes = False
_shortTZ = False