def _parse_minute_time(timestr): #Format must be hhmm, hhmm., hh:mm or hh:mm. if timestr.count(':') == 1: #hh:mm or hh:mm. timestrarray = timestr.split(':') isohour = int(timestrarray[0]) isominute = float(timestrarray[1]) #Minute may now be a fraction else: #hhmm or hhmm. isohour = int(timestr[0:2]) isominute = float(timestr[2:]) if isominute >= 60: raise MinutesOutOfBoundsError('Minutes must be less than 60.') if isohour == 24: if isominute != 0: raise MidnightBoundsError('Hour 24 may only represent midnight.') return datetime.time(hour=0, minute=0) #Since the time constructor doesn't handle fractional minutes, we put #the minutes in to a timedelta, and add it to the time before returning minutesdelta = datetime.timedelta(minutes=isominute) return _build_time(datetime.time(hour=isohour), minutesdelta)
def _parse_second_time(timestr): #Format must be hhmmss, hhmmss., hh:mm:ss or hh:mm:ss. if timestr.count(':') == 2: #hh:mm:ss or hh:mm:ss. timestrarray = timestr.split(':') isohour = int(timestrarray[0]) isominute = int(timestrarray[1]) #Since the time constructor doesn't handle fractional seconds, we put #the seconds in to a timedelta, and add it to the time before returning #The seconds value is truncated to microsecond resolution before #conversion: #https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is secondsdelta = datetime.timedelta(seconds=float(timestrarray[2][:9])) else: #hhmmss or hhmmss. isohour = int(timestr[0:2]) isominute = int(timestr[2:4]) #Since the time constructor doesn't handle fractional seconds, we put #the seconds in to a timedelta, and add it to the time before returning #The seconds value is truncated to microsecond resolution before #conversion: #https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is secondsdelta = datetime.timedelta(seconds=float(timestr[4:13])) if isohour == 23 and isominute == 59 and secondsdelta.seconds == 60: #https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is raise LeapSecondError('Leap seconds are not supported.') elif secondsdelta.seconds >= 60: #https://bitbucket.org/nielsenb/aniso8601/issues/13/parsing-of-leap-second-gives-wildly raise SecondsOutOfBoundsError('Seconds must be less than 60.') if isominute >= 60: raise MinutesOutOfBoundsError('Minutes must be less than 60.') if isohour == 24: #Midnight, see 4.2.1, 4.2.3 if isominute != 0 or secondsdelta.total_seconds() != 0: raise MidnightBoundsError('Hour 24 may only represent midnight.') return datetime.time(hour=0, minute=0) return _build_time(datetime.time(hour=isohour, minute=isominute), secondsdelta)
def build_time(cls, hh=None, mm=None, ss=None, tz=None): # Builds a time from the given parts, handling fractional arguments # where necessary hours = 0 minutes = 0 seconds = 0 microseconds = 0 if hh is not None: if "." in hh: hours, remainingmicroseconds = cls._split_to_microseconds( hh, MICROSECONDS_PER_HOUR, "Invalid hour string.") microseconds += remainingmicroseconds else: hours = cls.cast(hh, int, thrownmessage="Invalid hour string.") if mm is not None: if "." in mm: minutes, remainingmicroseconds = cls._split_to_microseconds( mm, MICROSECONDS_PER_MINUTE, "Invalid minute string.") microseconds += remainingmicroseconds else: minutes = cls.cast(mm, int, thrownmessage="Invalid minute string.") if ss is not None: if "." in ss: seconds, remainingmicroseconds = cls._split_to_microseconds( ss, MICROSECONDS_PER_SECOND, "Invalid second string.") microseconds += remainingmicroseconds else: seconds = cls.cast(ss, int, thrownmessage="Invalid second string.") ( hours, minutes, seconds, microseconds, ) = PythonTimeBuilder._distribute_microseconds( microseconds, (hours, minutes, seconds), (MICROSECONDS_PER_HOUR, MICROSECONDS_PER_MINUTE, MICROSECONDS_PER_SECOND), ) # Range checks if hours == 23 and minutes == 59 and seconds == 60: # https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is raise LeapSecondError("Leap seconds are not supported.") if hours == 24 and (minutes != 0 or seconds != 0): raise MidnightBoundsError("Hour 24 may only represent midnight.") if hours > 24: raise HoursOutOfBoundsError("Hour must be between 0..24 with " "24 representing midnight.") if minutes >= 60: raise MinutesOutOfBoundsError("Minutes must be less than 60.") if seconds >= 60: raise SecondsOutOfBoundsError("Seconds must be less than 60.") # Fix ranges that have passed range checks if hours == 24: hours = 0 minutes = 0 seconds = 0 # Datetimes don't handle fractional components, so we use a timedelta if tz is not None: return (datetime.datetime(1, 1, 1, hour=hours, minute=minutes, tzinfo=cls._build_object(tz)) + datetime.timedelta(seconds=seconds, microseconds=microseconds)).timetz() return (datetime.datetime(1, 1, 1, hour=hours, minute=minutes) + datetime.timedelta(seconds=seconds, microseconds=microseconds)).time()
def range_check_duration(cls, PnY=None, PnM=None, PnW=None, PnD=None, TnH=None, TnM=None, TnS=None, rangedict=None): years = 0 months = 0 days = 0 weeks = 0 hours = 0 minutes = 0 seconds = 0 microseconds = 0 PnY, PnM, PnW, PnD, TnH, TnM, TnS = BaseTimeBuilder.range_check_duration( PnY, PnM, PnW, PnD, TnH, TnM, TnS, rangedict=cls.DURATION_RANGE_DICT) if PnY is not None: if type(PnY) is FractionalComponent: years = PnY.principal microseconds = PnY.microsecondremainder else: years = PnY if years * DAYS_PER_YEAR > TIMEDELTA_MAX_DAYS: raise YearOutOfBoundsError( 'Duration exceeds maximum timedelta size.') if PnM is not None: if type(PnM) is FractionalComponent: months = PnM.principal microseconds = PnM.microsecondremainder else: months = PnM if months * DAYS_PER_MONTH > TIMEDELTA_MAX_DAYS: raise MonthOutOfBoundsError( 'Duration exceeds maximum timedelta size.') if PnW is not None: if type(PnW) is FractionalComponent: weeks = PnW.principal microseconds = PnW.microsecondremainder else: weeks = PnW if weeks * DAYS_PER_WEEK > TIMEDELTA_MAX_DAYS: raise WeekOutOfBoundsError( 'Duration exceeds maximum timedelta size.') if PnD is not None: if type(PnD) is FractionalComponent: days = PnD.principal microseconds = PnD.microsecondremainder else: days = PnD if days > TIMEDELTA_MAX_DAYS: raise DayOutOfBoundsError( 'Duration exceeds maximum timedelta size.') if TnH is not None: if type(TnH) is FractionalComponent: hours = TnH.principal microseconds = TnH.microsecondremainder else: hours = TnH if hours // HOURS_PER_DAY > TIMEDELTA_MAX_DAYS: raise HoursOutOfBoundsError( 'Duration exceeds maximum timedelta size.') if TnM is not None: if type(TnM) is FractionalComponent: minutes = TnM.principal microseconds = TnM.microsecondremainder else: minutes = TnM if minutes // MINUTES_PER_DAY > TIMEDELTA_MAX_DAYS: raise MinutesOutOfBoundsError( 'Duration exceeds maximum timedelta size.') if TnS is not None: if type(TnS) is FractionalComponent: seconds = TnS.principal microseconds = TnS.microsecondremainder else: seconds = TnS if seconds // SECONDS_PER_DAY > TIMEDELTA_MAX_DAYS: raise SecondsOutOfBoundsError( 'Duration exceeds maximum timedelta size.') years, months, weeks, days, hours, minutes, seconds, microseconds = PythonTimeBuilder._distribute_microseconds( microseconds, (years, months, weeks, days, hours, minutes, seconds), (MICROSECONDS_PER_YEAR, MICROSECONDS_PER_MONTH, MICROSECONDS_PER_WEEK, MICROSECONDS_PER_DAY, MICROSECONDS_PER_HOUR, MICROSECONDS_PER_MINUTE, MICROSECONDS_PER_SECOND)) #Note that weeks can be handled without conversion to days totaldays = years * DAYS_PER_YEAR + months * DAYS_PER_MONTH + days #Check against timedelta limits if totaldays + weeks * DAYS_PER_WEEK + hours // HOURS_PER_DAY + minutes // MINUTES_PER_DAY + seconds // SECONDS_PER_DAY > TIMEDELTA_MAX_DAYS: raise DayOutOfBoundsError( 'Duration exceeds maximum timedelta size.') return (None, None, weeks, totaldays, hours, minutes, FractionalComponent(seconds, microseconds))
def build_time(cls, hh=None, mm=None, ss=None, tz=None): # Builds a time from the given parts, handling fractional arguments # where necessary hours = 0 minutes = 0 seconds = 0 floathours = float(0) floatminutes = float(0) floatseconds = float(0) if hh is not None: if "." in hh: floathours = BaseTimeBuilder.cast( hh, float, thrownmessage="Invalid hour string.") hours = 0 else: hours = BaseTimeBuilder.cast( hh, int, thrownmessage="Invalid hour string.") if mm is not None: if "." in mm: floatminutes = BaseTimeBuilder.cast( mm, float, thrownmessage="Invalid minute string.") minutes = 0 else: minutes = BaseTimeBuilder.cast( mm, int, thrownmessage="Invalid minute string.") if ss is not None: if "." in ss: # Truncate to maximum supported precision floatseconds = BaseTimeBuilder.cast( ss[0:ss.index(".") + 7], float, thrownmessage="Invalid second string.", ) seconds = 0 else: seconds = BaseTimeBuilder.cast( ss, int, thrownmessage="Invalid second string.") # Range checks if (hours == 23 and floathours == 0 and minutes == 59 and floatminutes == 0 and seconds == 60 and floatseconds == 0): # https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is raise LeapSecondError("Leap seconds are not supported.") if (hours == 24 and floathours == 0 and (minutes != 0 or floatminutes != 0 or seconds != 0 or floatseconds != 0)): raise MidnightBoundsError("Hour 24 may only represent midnight.") if hours > 24 or floathours > 24: raise HoursOutOfBoundsError("Hour must be between 0..24 with " "24 representing midnight.") if minutes >= 60 or floatminutes >= 60: raise MinutesOutOfBoundsError("Minutes must be less than 60.") if seconds >= 60 or floatseconds >= 60: raise SecondsOutOfBoundsError("Seconds must be less than 60.") # Fix ranges that have passed range checks if hours == 24: hours = 0 minutes = 0 seconds = 0 # Datetimes don't handle fractional components, so we use a timedelta if tz is not None: return (datetime.datetime( 1, 1, 1, hour=hours, minute=minutes, second=seconds, tzinfo=cls._build_object(tz), ) + datetime.timedelta(hours=floathours, minutes=floatminutes, seconds=floatseconds)).timetz() return (datetime.datetime( 1, 1, 1, hour=hours, minute=minutes, second=seconds) + datetime.timedelta(hours=floathours, minutes=floatminutes, seconds=floatseconds)).time()
def build_time(cls, hh=None, mm=None, ss=None, tz=None): #Builds a time from the given parts, handling fractional arguments #where necessary hours = 0 minutes = 0 seconds = 0 floathours = float(0) floatminutes = float(0) floatseconds = float(0) if hh is not None: if '.' in hh: hours, floathours = cls._split_and_cast( hh, 'Invalid hour string.') else: hours = cls.cast(hh, int, thrownmessage='Invalid hour string.') if mm is not None: if '.' in mm: minutes, floatminutes = cls._split_and_cast( mm, 'Invalid minute string.') else: minutes = cls.cast(mm, int, thrownmessage='Invalid minute string.') if ss is not None: if '.' in ss: seconds, floatseconds = cls._split_and_cast( ss, 'Invalid second string.') else: seconds = cls.cast(ss, int, thrownmessage='Invalid second string.') if floathours != 0: remainderhours, remainderminutes = cls._split_and_convert( floathours, 60) hours += remainderhours floatminutes += remainderminutes if floatminutes != 0: remainderminutes, remainderseconds = cls._split_and_convert( floatminutes, 60) minutes += remainderminutes floatseconds += remainderseconds if floatseconds != 0: totalseconds = float(seconds) + floatseconds #Truncate to maximum supported precision seconds = cls._truncate(totalseconds, 6) #Range checks if hours == 23 and minutes == 59 and seconds == 60: #https://bitbucket.org/nielsenb/aniso8601/issues/10/sub-microsecond-precision-in-durations-is raise LeapSecondError('Leap seconds are not supported.') if (hours == 24 and (minutes != 0 or seconds != 0)): raise MidnightBoundsError('Hour 24 may only represent midnight.') if hours > 24: raise HoursOutOfBoundsError('Hour must be between 0..24 with ' '24 representing midnight.') if minutes >= 60: raise MinutesOutOfBoundsError('Minutes must be less than 60.') if seconds >= 60: raise SecondsOutOfBoundsError('Seconds must be less than 60.') #Fix ranges that have passed range checks if hours == 24: hours = 0 minutes = 0 seconds = 0 #Datetimes don't handle fractional components, so we use a timedelta if tz is not None: return (datetime.datetime(1, 1, 1, hour=hours, minute=minutes, tzinfo=cls._build_object(tz)) + datetime.timedelta(seconds=seconds)).timetz() return (datetime.datetime(1, 1, 1, hour=hours, minute=minutes) + datetime.timedelta(seconds=seconds)).time()