# ##### BEGIN LICENSE BLOCK #####
#
# (C) Copyright 2003, 2004 Hewlett-Packard Development Company, L.P.
# (C) Copyright 2006, 2007 Novell, Inc.
# (C) Copyright 2014, 2015 Red Hat, Inc.
#
# Copyright (C) 2014-2015, Peter Hatina <phatina@redhat.com>
#
# This library is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation, either version 2.1 of the
# License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA
#
# The code is taken from pywbem-0.6
#
# Authors: Tim Potter <tpot@hp.com>
# Bart Whiteley <bwhiteley@suse.de>
# Peter Hatina <phatina@redhat.com>
#
# ##### END LICENSE BLOCK #####
import sys
from datetime import datetime
from datetime import timedelta
from datetime import tzinfo
import re
[docs]class MinutesFromUTC(tzinfo):
'''
Fixed offset in minutes from UTC
'''
def __init__(self, offset):
self.__offset = timedelta(minutes=offset)
[docs] def utcoffset(self, dt):
return self.__offset
[docs] def dst(self, dt):
return timedelta(0)
[docs]class CIMType(object):
'''
Base type for all CIM types
'''
[docs]class CIMDateTime(CIMType) :
'''
A CIM DateTime
'''
def __init__(self, dtarg):
self.cimtype = 'datetime'
self.__timedelta = None
self.__datetime = None
if isinstance(dtarg, basestring):
date_pattern = re.compile(r'^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})\.(\d{6})([+|-])(\d{3})')
s = date_pattern.search(dtarg)
if s is not None:
g = s.groups()
offset = int(g[8])
if g[7] == '-':
offset = -offset
self.__datetime = datetime(
int(g[0]), int(g[1]),
int(g[2]), int(g[3]),
int(g[4]), int(g[5]),
int(g[6]), MinutesFromUTC(offset))
else:
tv_pattern = re.compile(r'^(\d{8})(\d{2})(\d{2})(\d{2})\.(\d{6})(:)(000)')
s = tv_pattern.search(dtarg)
if s is None:
raise ValueError('Invalid Datetime format \'%s\'' % dtarg)
else:
g = s.groups()
self.__timedelta = timedelta(
days=int(g[0]),
hours=int(g[1]),
minutes=int(g[2]),
seconds=int(g[3]),
microseconds=int(g[4]))
elif isinstance(dtarg, datetime):
self.__datetime = dtarg;
elif isinstance(dtarg, timedelta):
self.__timedelta = dtarg
elif isinstance(dtarg, CIMDateTime):
self.__datetime = dtarg.__datetime
self.__timedelta = dtarg.__timedelta
else:
raise ValueError('Expected datetime, timedelta, or string')
@property
[docs] def minutes_from_utc(self):
'''
Return the timezone as +/- minutes from UTC
'''
offset = 0
if self.__datetime is not None and \
self.__datetime.utcoffset() is not None:
offset = self.__datetime.utcoffset().seconds / 60
if self.__datetime.utcoffset().days == -1:
offset = -(60*24 - offset)
return offset
@property
[docs] def datetime(self):
return self.__datetime
@property
[docs] def timedelta(self):
return self.__timedelta
@property
[docs] def is_interval(self):
return self.__timedelta is not None
@staticmethod
[docs] def get_local_utcoffset():
'''
Return minutes +/- UTC for the local timezone
'''
utc = datetime.utcnow()
local = datetime.now()
if local < utc:
return - int(float((utc - local).seconds) / 60 + .5)
else:
return int(float((local - utc).seconds) / 60 + .5)
@classmethod
[docs] def now(cls, tzi=None):
if tzi is None:
tzi = MinutesFromUTC(cls.get_local_utcoffset())
return cls(datetime.now(tzi))
@classmethod
[docs] def fromtimestamp(cls, ts, tzi=None):
if tzi is None:
tzi = MinutesFromUTC(cls.get_local_utcoffset())
return cls(datetime.fromtimestamp(ts, tzi))
def __str__ (self):
if self.is_interval:
hour = self.__timedelta.seconds / 3600
minute = (self.__timedelta.seconds - hour * 3600) / 60
second = self.__timedelta.seconds - hour * 3600 - minute * 60
return '%08d%02d%02d%02d.%06d:000' % \
(self.__timedelta.days, hour, minute, second,
self.__timedelta.microseconds)
else:
offset = self.minutes_from_utc
sign = '+'
if offset < 0:
sign = '-'
offset = -offset
return '%d%02d%02d%02d%02d%02d.%06d%s%03d' % \
(self.__datetime.year, self.__datetime.month,
self.__datetime.day, self.__datetime.hour,
self.__datetime.minute, self.__datetime.second,
self.__datetime.microsecond, sign, offset)
def __repr__ (self):
return '%s(%s)'%(self.__class__.__name__, str(self))
def __getstate__(self):
return str(self)
def __setstate__(self, arg):
self.__init__(arg)
def __cmp__(self, other):
if self is other:
return 0
elif not isinstance(other, CIMDateTime):
return 1
return (cmp(self.__datetime, other.__datetime) or
cmp(self.__timedelta, other.__timedelta))
# CIM integer types
if sys.version_info >= (3, 0):
# Python3 no longer uses 'long' type.
base = int
else:
base = long
[docs]class CIMInt(CIMType, base):
pass
[docs]class Uint8(CIMInt):
cimtype = 'uint8'
[docs]class Sint8(CIMInt):
cimtype = 'sint8'
[docs]class Uint16(CIMInt):
cimtype = 'uint16'
[docs]class Sint16(CIMInt):
cimtype = 'sint16'
[docs]class Uint32(CIMInt):
cimtype = 'uint32'
[docs]class Sint32(CIMInt):
cimtype = 'sint32'
[docs]class Uint64(CIMInt):
cimtype = 'uint64'
[docs]class Sint64(CIMInt):
cimtype = 'sint64'
# CIM float types
[docs]class CIMFloat(CIMType, float):
pass
[docs]class Real32(CIMFloat):
cimtype = 'real32'
[docs]class Real64(CIMFloat):
cimtype = 'real64'
[docs]def cimtype(obj):
'''
Return the CIM type name of an object as a string. For a list, the
type is the type of the first element as CIM arrays must be
homogeneous.
'''
if isinstance(obj, CIMType):
return obj.cimtype
if isinstance(obj, bool):
return 'boolean'
if isinstance(obj, (str, unicode)):
return 'string'
if isinstance(obj, list):
return cimtype(obj[0])
if isinstance(obj, (datetime, timedelta)):
return 'datetime'
raise TypeError('Invalid CIM type for %s' % str(obj))