def value_from_raw(self, raw): if raw.value is None: return raw.missing_value('Missing datetime') try: chunks = raw.value.split(' ') date_info = [int(bit) for bit in chunks[0].split('-')] time_info = [int(bit) for bit in chunks[1].split(':')] datetime_info = date_info + time_info result = datetime(*datetime_info) if len(chunks) > 2: try: tz = get_timezone(chunks[-1]) except LookupError: if len(chunks[-1]) > 5: chunks[-1] = chunks[-1][-5:] delta = int(chunks[-1][1:3]) * 60 + int(chunks[-1][3:]) if chunks[-1][0] == '-': delta *= -1 tz = FixedOffset(delta) return tz.localize(result) return result except Exception: return raw.bad_value('Bad date format')
def convert_to_datetime(input, tz, arg_name): """ Converts the given object to a timezone aware datetime object. If a timezone aware datetime object is passed, it is returned unmodified. If a native datetime object is passed, it is given the specified timezone. If the input is a string, it is parsed as a datetime with the given timezone. Date strings are accepted in three different forms: date only (Y-m-d), date with time (Y-m-d H:M:S) or with date+time with microseconds (Y-m-d H:M:S.micro). Additionally you can override the time zone by giving a specific offset in the format specified by ISO 8601: Z (UTC), +HH:MM or -HH:MM. :param str|datetime input: the datetime or string to convert to a timezone aware datetime :param datetime.tzinfo tz: timezone to interpret ``input`` in :param str arg_name: the name of the argument (used in an error message) :rtype: datetime """ if input is None: return elif isinstance(input, datetime): datetime_ = input elif isinstance(input, date): datetime_ = datetime.combine(input, time()) elif isinstance(input, six.string_types): m = _DATE_REGEX.match(input) if not m: raise ValueError('Invalid date string') values = m.groupdict() tzname = values.pop('timezone') if tzname == 'Z': tz = utc elif tzname: hours, minutes = (int(x) for x in tzname[1:].split(':')) sign = 1 if tzname[0] == '+' else -1 tz = FixedOffset(sign * (hours * 60 + minutes)) values = {k: int(v or 0) for k, v in values.items()} datetime_ = datetime(**values) else: raise TypeError('Unsupported type for %s: %s' % (arg_name, input.__class__.__name__)) if datetime_.tzinfo is not None: return datetime_ if tz is None: raise ValueError( 'The "tz" argument must be specified if %s has no timezone information' % arg_name) if isinstance(tz, six.string_types): tz = timezone(tz) try: return tz.localize(datetime_, is_dst=None) except AttributeError: raise TypeError( 'Only pytz timezones are supported (need the localize() and normalize() methods)' )
def hydrate_datetime(seconds, nanoseconds, tz=None): """ Hydrator for `DateTime` and `LocalDateTime` values. :param seconds: :param nanoseconds: :param tz: :return: datetime """ microseconds, nanoseconds = divmod(nanoseconds, 1000) if nanoseconds != 0: warn( "Nanosecond resolution is not available on this platform, value is truncated at microsecond resolution" ) minutes, seconds = divmod(seconds, 60) hours, minutes = divmod(minutes, 60) days, hours = divmod(hours, 24) t = datetime.combine(UNIX_EPOCH_DATE + timedelta(days=days), time(hours, minutes, seconds, microseconds)) if tz is None: return t if isinstance(tz, int): tz_offset_minutes, tz_offset_seconds = divmod(tz, 60) zone = FixedOffset(tz_offset_minutes) else: zone = timezone(tz) return zone.localize(t)
def convert_to_datetime(input, tz, arg_name): """ Converts the given object to a timezone aware datetime object. If a timezone aware datetime object is passed, it is returned unmodified. If a native datetime object is passed, it is given the specified timezone. If the input is a string, it is parsed as a datetime with the given timezone. Date strings are accepted in three different forms: date only (Y-m-d), date with time (Y-m-d H:M:S) or with date+time with microseconds (Y-m-d H:M:S.micro). Additionally you can override the time zone by giving a specific offset in the format specified by ISO 8601: Z (UTC), +HH:MM or -HH:MM. :param str|datetime input: the datetime or string to convert to a timezone aware datetime :param datetime.tzinfo tz: timezone to interpret ``input`` in :param str arg_name: the name of the argument (used in an error message) :rtype: datetime """ if input is None: return elif isinstance(input, datetime): datetime_ = input elif isinstance(input, date): datetime_ = datetime.combine(input, time()) elif isinstance(input, six.string_types): m = _DATE_REGEX.match(input) if not m: raise ValueError('Invalid date string') values = m.groupdict() tzname = values.pop('timezone') if tzname == 'Z': tz = utc elif tzname: hours, minutes = (int(x) for x in tzname[1:].split(':')) sign = 1 if tzname[0] == '+' else -1 tz = FixedOffset(sign * (hours * 60 + minutes)) values = {k: int(v or 0) for k, v in values.items()} datetime_ = datetime(**values) else: raise TypeError('Unsupported type for %s: %s' % (arg_name, input.__class__.__name__)) if datetime_.tzinfo is not None: return datetime_ if tz is None: raise ValueError( 'The "tz" argument must be specified if %s has no timezone information' % arg_name) if isinstance(tz, six.string_types): tz = timezone(tz) try: return tz.localize(datetime_, is_dst=None) except AttributeError: raise TypeError( 'Only pytz timezones are supported (need the localize() and normalize() methods)')
def _hydrate_time(self, nanoseconds, tz=None): """ Hydrator for `Time` and `LocalTime` values. :param nanoseconds: :param tz: :return: Time """ seconds, nanoseconds = map(int, divmod(nanoseconds, 1000000000)) minutes, seconds = map(int, divmod(seconds, 60)) hours, minutes = map(int, divmod(minutes, 60)) seconds = (1000000000 * seconds + nanoseconds) / 1000000000 t = Time(hours, minutes, seconds) if tz is None: return t tz_offset_minutes, tz_offset_seconds = divmod(tz, 60) zone = FixedOffset(tz_offset_minutes) return zone.localize(t)
def hydrate_datetime(seconds, nanoseconds, tz=None): """ Hydrator for `DateTime` and `LocalDateTime` values. :param seconds: :param nanoseconds: :param tz: :return: datetime """ minutes, seconds = map(int, divmod(seconds, 60)) hours, minutes = map(int, divmod(minutes, 60)) days, hours = map(int, divmod(hours, 24)) seconds = (1000000000 * seconds + nanoseconds) / 1000000000 t = DateTime.combine(UNIX_EPOCH_DATE_ORDINAL + days, Time(hours, minutes, seconds)) if tz is None: return t if isinstance(tz, int): tz_offset_minutes, tz_offset_seconds = divmod(tz, 60) zone = FixedOffset(tz_offset_minutes) else: zone = timezone(tz) return zone.localize(t)
def hydrate_time(nanoseconds, tz=None): """ Hydrator for `Time` and `LocalTime` values. :param nanoseconds: :param tz: :return: time """ microseconds, nanoseconds = divmod(nanoseconds, 1000) if nanoseconds != 0: warn( "Nanosecond resolution is not available on this platform, value is truncated at microsecond resolution" ) seconds, microseconds = divmod(microseconds, 1000000) minutes, seconds = divmod(seconds, 60) hours, minutes = divmod(minutes, 60) t = time(hours, minutes, seconds, microseconds) if tz is None: return t tz_offset_minutes, tz_offset_seconds = divmod(tz, 60) zone = FixedOffset(tz_offset_minutes) return zone.localize(t)
def hydrate_datetime(seconds, nanoseconds, tz=None): """ Hydrator for `DateTime` and `LocalDateTime` values. :param seconds: :param nanoseconds: :param tz: :return: datetime """ from pytz import FixedOffset, timezone minutes, seconds = map(int, divmod(seconds, 60)) hours, minutes = map(int, divmod(minutes, 60)) days, hours = map(int, divmod(hours, 24)) seconds = (1000000000 * seconds + nanoseconds) / 1000000000 t = DateTime.combine(Date.from_ordinal(get_date_unix_epoch_ordinal() + days), Time(hours, minutes, seconds)) if tz is None: return t if isinstance(tz, int): tz_offset_minutes, tz_offset_seconds = divmod(tz, 60) zone = FixedOffset(tz_offset_minutes) else: zone = timezone(tz) return zone.localize(t)