def test_local_time_positive_integer(self): d = Pendulum(2016, 8, 7, 12, 34, 56) t = local_time(d.timestamp, 0) self.assertEqual(d.year, t[0]) self.assertEqual(d.month, t[1]) self.assertEqual(d.day, t[2]) self.assertEqual(d.hour, t[3]) self.assertEqual(d.minute, t[4]) self.assertEqual(d.second, t[5])
def fromutc(self, dt): # type: (_D) -> _D stamp = timestamp(dt) transition = self._lookup_transition(stamp, is_utc=True) if stamp < transition.at and transition.previous is not None: transition = transition.previous stamp += transition.ttype.offset return dt.__class__(*local_time(stamp, 0, dt.microsecond), tzinfo=self)
def _normalize( self, dt, dst_rule=None # type: datetime # type: Union[str, None] ): # type: (...) -> datetime sec = timestamp(dt) fold = 0 transition = self._lookup_transition(sec) if not _HAS_FOLD and dst_rule is None: dst_rule = POST_TRANSITION if dst_rule is None: dst_rule = PRE_TRANSITION if dt.fold == 1: dst_rule = POST_TRANSITION if sec < transition.local: if transition.is_ambiguous(sec): # Ambiguous time if dst_rule == TRANSITION_ERROR: raise AmbiguousTime(dt) # We set the fold attribute for later if dst_rule == POST_TRANSITION: fold = 1 else: transition = transition.previous if transition.is_ambiguous(sec): # Ambiguous time if dst_rule == TRANSITION_ERROR: raise AmbiguousTime(dt) # We set the fold attribute for later if dst_rule == POST_TRANSITION: fold = 1 elif transition.is_missing(sec): # Skipped time if dst_rule == TRANSITION_ERROR: raise NonExistingTime(dt) # We adjust accordingly if dst_rule == POST_TRANSITION: sec += transition.fix fold = 1 else: sec -= transition.fix kwargs = {"tzinfo": self} if _HAS_FOLD or isinstance(dt, pendulum.DateTime): kwargs["fold"] = fold return dt.__class__(*local_time(sec, 0, dt.microsecond), **kwargs)
def test_local_time_negative_integer(self): d = Pendulum(1951, 8, 7, 12, 34, 56, 123456) t = local_time(d.int_timestamp, 0, d.microsecond) self.assertEqual(d.year, t[0]) self.assertEqual(d.month, t[1]) self.assertEqual(d.day, t[2]) self.assertEqual(d.hour, t[3]) self.assertEqual(d.minute, t[4]) self.assertEqual(d.second, t[5]) self.assertEqual(d.microsecond, t[6])
def test_local_time_positive_integer(): d = pendulum.datetime(2016, 8, 7, 12, 34, 56, 123456) t = local_time(d.int_timestamp, 0, d.microsecond) assert d.year == t[0] assert d.month == t[1] assert d.day == t[2] assert d.hour == t[3] assert d.minute == t[4] assert d.second == t[5] assert d.microsecond == t[6]
def _convert(self, dt): # type: (datetime) -> datetime if dt.tzinfo is self: return self._normalize(dt, dst_rule=POST_TRANSITION) if not isinstance(dt.tzinfo, Timezone): return dt.astimezone(self) stamp = timestamp(dt) if isinstance(dt.tzinfo, FixedTimezone): offset = dt.tzinfo.offset else: transition = dt.tzinfo._lookup_transition(stamp) offset = transition.ttype.offset if stamp < transition.local: if (transition.previous.is_ambiguous(stamp) and getattr(dt, 'fold', 1) == 0): pass else: offset = transition.previous.ttype.offset stamp -= offset transition = self._lookup_transition(stamp, is_utc=True) if stamp < transition.at: transition = transition.previous offset = transition.ttype.offset stamp += offset fold = int(not transition.ttype.is_dst()) kwargs = { 'tzinfo': self, } if _HAS_FOLD or isinstance(dt, pendulum.DateTime): kwargs['fold'] = fold return dt.__class__(*local_time(stamp, 0, dt.microsecond), **kwargs)
def _check_parsed(self, parsed, now): # type: (dict, pendulum.DateTime) -> dict """ Checks validity of parsed elements. :param parsed: The elements to parse. :return: The validated elements. """ validated = { "year": parsed["year"], "month": parsed["month"], "day": parsed["day"], "hour": parsed["hour"], "minute": parsed["minute"], "second": parsed["second"], "microsecond": parsed["microsecond"], "tz": None, } # If timestamp has been specified # we use it and don't go any further if parsed["timestamp"] is not None: str_us = str(parsed["timestamp"]) if "." in str_us: microseconds = int("{}".format( str_us.split(".")[1].ljust(6, "0"))) else: microseconds = 0 time = local_time(parsed["timestamp"], 0, microseconds) validated["year"] = time[0] validated["month"] = time[1] validated["day"] = time[2] validated["hour"] = time[3] validated["minute"] = time[4] validated["second"] = time[5] validated["microsecond"] = time[6] return validated if parsed["quarter"] is not None: if validated["year"] is not None: dt = pendulum.datetime(validated["year"], 1, 1) else: dt = now dt = dt.start_of("year") while dt.quarter != parsed["quarter"]: dt = dt.add(months=3) validated["year"] = dt.year validated["month"] = dt.month validated["day"] = dt.day if validated["year"] is None: validated["year"] = now.year if parsed["day_of_year"] is not None: dt = pendulum.parse("{}-{}".format(validated["year"], parsed["day_of_year"])) validated["month"] = dt.month validated["day"] = dt.day if parsed["day_of_week"] is not None: dt = pendulum.datetime( validated["year"], validated["month"] or now.month, validated["day"] or now.day, ) dt = dt.start_of("week").subtract(days=1) dt = dt.next(parsed["day_of_week"]) validated["year"] = dt.year validated["month"] = dt.month validated["day"] = dt.day # Meridiem if parsed["meridiem"] is not None: # If the time is greater than 13:00:00 # This is not valid if validated["hour"] is None: raise ValueError("Invalid Date") t = ( validated["hour"], validated["minute"], validated["second"], validated["microsecond"], ) if t >= (13, 0, 0, 0): raise ValueError("Invalid date") pm = parsed["meridiem"] == "pm" validated["hour"] %= 12 if pm: validated["hour"] += 12 if validated["month"] is None: if parsed["year"] is not None: validated["month"] = parsed["month"] or 1 else: validated["month"] = parsed["month"] or now.month if validated["day"] is None: if parsed["year"] is not None or parsed["month"] is not None: validated["day"] = parsed["day"] or 1 else: validated["day"] = parsed["day"] or now.day for part in ["hour", "minute", "second", "microsecond"]: if validated[part] is None: validated[part] = 0 validated["tz"] = parsed["tz"] return validated
def _extends(self): if not self._posix_rule: return posix = self._posix_rule if not posix.dst_abbr: # std only # The future specification should match the last/default transition ttype = self._transitions[-1].ttype if not self._check_ttype(ttype, posix.std_offset, False, posix.std_abbr): raise ValueError("Posix spec does not match last transition") return if len(self._transitions) < 2: raise ValueError("Too few transitions for POSIX spec") # Extend the transitions for an additional 400 years # using the future specification # The future specification should match the last two transitions, # and those transitions should have different is_dst flags. tr0 = self._transitions[-1] tr1 = self._transitions[-2] tt0 = tr0.ttype tt1 = tr1.ttype if tt0.is_dst(): dst = tt0 std = tt1 else: dst = tt1 std = tt0 self._check_ttype(dst, posix.dst_offset, True, posix.dst_abbr) self._check_ttype(std, posix.std_offset, False, posix.std_abbr) # Add the transitions to tr1 and back to tr0 for each extra year. last_year = local_time(tr0.local, 0, 0)[0] leap_year = is_leap(last_year) jan1 = datetime(last_year, 1, 1) jan1_time = timestamp(jan1) jan1_weekday = week_day(jan1.year, jan1.month, jan1.day) % 7 if local_time(tr1.local, 0, 0)[0] != last_year: # Add a single extra transition to align to a calendar year. if tt0.is_dst(): pt1 = posix.dst_end else: pt1 = posix.dst_start tr1_offset = pt1.trans_offset(leap_year, jan1_weekday) tr = Transition(jan1_time + tr1_offset - tt0.offset, tr1.ttype, tr0) tr0 = tr tr1 = tr0 tt0 = tr0.ttype tt1 = tr1.ttype if tt0.is_dst(): pt1 = posix.dst_end pt0 = posix.dst_start else: pt1 = posix.dst_start pt0 = posix.dst_end tr = tr0 for year in range(last_year + 1, last_year + 401): jan1_time += SECS_PER_YEAR[leap_year] jan1_weekday = (jan1_weekday + DAYS_PER_YEAR[leap_year]) % 7 leap_year = not leap_year and is_leap(year) tr1_offset = pt1.trans_offset(leap_year, jan1_weekday) tr = Transition(jan1_time + tr1_offset - tt0.offset, tt1, tr) self._transitions.append(tr) tr0_offset = pt0.trans_offset(leap_year, jan1_weekday) tr = Transition(jan1_time + tr0_offset - tt1.offset, tt0, tr) self._transitions.append(tr)
def _check_parsed(self, parsed, now): # type: (dict, pendulum.DateTime) -> dict """ Checks validity of parsed elements. :param parsed: The elements to parse. :return: The validated elements. """ validated = { 'year': parsed['year'], 'month': parsed['month'], 'day': parsed['day'], 'hour': parsed['hour'], 'minute': parsed['minute'], 'second': parsed['second'], 'microsecond': parsed['microsecond'], 'tz': None } # If timestamp has been specified # we use it and don't go any further if parsed['timestamp'] is not None: str_us = str(parsed['timestamp']) if '.' in str_us: microseconds = int("{}".format( str_us.split('.')[1].ljust(6, '0'))) else: microseconds = 0 time = local_time(parsed['timestamp'], 0, microseconds) validated['year'] = time[0] validated['month'] = time[1] validated['day'] = time[2] validated['hour'] = time[3] validated['minute'] = time[4] validated['second'] = time[5] validated['microsecond'] = time[6] return validated if parsed['quarter'] is not None: if validated['year'] is not None: dt = pendulum.datetime(validated['year'], 1, 1) else: dt = now dt = dt.start_of('year') while dt.quarter != parsed['quarter']: dt = dt.add(months=3) validated['year'] = dt.year validated['month'] = dt.month validated['day'] = dt.day if validated['year'] is None: validated['year'] = now.year if parsed['day_of_year'] is not None: dt = pendulum.parse("{}-{}".format(validated['year'], parsed['day_of_year'])) validated['month'] = dt.month validated['day'] = dt.day if parsed['day_of_week'] is not None: dt = pendulum.datetime(validated['year'], validated['month'] or now.month, validated['day'] or now.day) dt = dt.start_of('week').subtract(days=1) dt = dt.next(parsed['day_of_week']) validated['year'] = dt.year validated['month'] = dt.month validated['day'] = dt.day # Meridiem if parsed['meridiem'] is not None: # If the time is greater than 13:00:00 # This is not valid if validated['hour'] is None: raise ValueError('Invalid Date') t = (validated['hour'], validated['minute'], validated['second'], validated['microsecond']) if t >= (13, 0, 0, 0): raise ValueError('Invalid date') pm = parsed['meridiem'] == 'pm' validated['hour'] %= 12 if pm: validated['hour'] += 12 if validated['month'] is None: if parsed['year'] is not None: validated['month'] = parsed['month'] or 1 else: validated['month'] = parsed['month'] or now.month if validated['day'] is None: if parsed['year'] is not None or parsed['month'] is not None: validated['day'] = parsed['day'] or 1 else: validated['day'] = parsed['day'] or now.day for part in ['hour', 'minute', 'second', 'microsecond']: if validated[part] is None: validated[part] = 0 validated['tz'] = parsed['tz'] return validated
def _check_parsed(self, parsed, now): # type: (dict, pendulum.DateTime) -> dict """ Checks validity of parsed elements. :param parsed: The elements to parse. :return: The validated elements. """ validated = { "year": parsed["year"], "month": parsed["month"], "day": parsed["day"], "hour": parsed["hour"], "minute": parsed["minute"], "second": parsed["second"], "microsecond": parsed["microsecond"], "tz": None, } # If timestamp has been specified # we use it and don't go any further if parsed["timestamp"] is not None: str_us = str(parsed["timestamp"]) if "." in str_us: microseconds = int("{}".format(str_us.split(".")[1].ljust(6, "0"))) else: microseconds = 0 time = local_time(parsed["timestamp"], 0, microseconds) validated["year"] = time[0] validated["month"] = time[1] validated["day"] = time[2] validated["hour"] = time[3] validated["minute"] = time[4] validated["second"] = time[5] validated["microsecond"] = time[6] return validated if parsed["quarter"] is not None: if validated["year"] is not None: dt = pendulum.datetime(validated["year"], 1, 1) else: dt = now dt = dt.start_of("year") while dt.quarter != parsed["quarter"]: dt = dt.add(months=3) validated["year"] = dt.year validated["month"] = dt.month validated["day"] = dt.day if validated["year"] is None: validated["year"] = now.year if parsed["day_of_year"] is not None: dt = pendulum.parse( "{}-{}".format(validated["year"], parsed["day_of_year"]) ) validated["month"] = dt.month validated["day"] = dt.day if parsed["day_of_week"] is not None: dt = pendulum.datetime( validated["year"], validated["month"] or now.month, validated["day"] or now.day, ) dt = dt.start_of("week").subtract(days=1) dt = dt.next(parsed["day_of_week"]) validated["year"] = dt.year validated["month"] = dt.month validated["day"] = dt.day # Meridiem if parsed["meridiem"] is not None: # If the time is greater than 13:00:00 # This is not valid if validated["hour"] is None: raise ValueError("Invalid Date") t = ( validated["hour"], validated["minute"], validated["second"], validated["microsecond"], ) if t >= (13, 0, 0, 0): raise ValueError("Invalid date") pm = parsed["meridiem"] == "pm" validated["hour"] %= 12 if pm: validated["hour"] += 12 if validated["month"] is None: if parsed["year"] is not None: validated["month"] = parsed["month"] or 1 else: validated["month"] = parsed["month"] or now.month if validated["day"] is None: if parsed["year"] is not None or parsed["month"] is not None: validated["day"] = parsed["day"] or 1 else: validated["day"] = parsed["day"] or now.day for part in ["hour", "minute", "second", "microsecond"]: if validated[part] is None: validated[part] = 0 validated["tz"] = parsed["tz"] return validated