コード例 #1
0
ファイル: acetz.py プロジェクト: smcicoss/AceTime
class acetz(tzinfo):
    """An implementation of datetime.tzinfo using the ZoneSpecifier class
    from AceTime/tools.
    """
    def __init__(self, zone_info: ZoneInfo):
        self.zone_info = zone_info
        self.zs = ZoneSpecifier(zone_info, use_python_transition=True)

    def utcoffset(self, dt: Optional[datetime]) -> timedelta:
        assert dt
        info = self.zs.get_timezone_info_for_datetime(dt)
        if not info:
            raise Exception(f'Unknown timezone info for '
                            f'{dt.year:04}-{dt.month:02}-{dt.day:02} '
                            f'{dt.hour:02}:{dt.minute:02}:{dt.second:02}')

        return timedelta(seconds=info.total_offset)

    def dst(self, dt: Optional[datetime]) -> timedelta:
        assert dt
        offset_info = self.zs.get_timezone_info_for_datetime(dt)
        if not offset_info:
            raise Exception(f'Unknown timezone info for '
                            f'{dt.year:04}-{dt.month:02}-{dt.day:02} '
                            f'{dt.hour:02}:{dt.minute:02}:{dt.second:02}')
        return timedelta(seconds=offset_info.dst_offset)

    def tzname(self, dt: Optional[datetime]) -> str:
        assert dt
        offset_info = self.zs.get_timezone_info_for_datetime(dt)
        if not offset_info:
            raise Exception(f'Unknown timezone info for '
                            f'{dt.year:04}-{dt.month:02}-{dt.day:02} '
                            f'{dt.hour:02}:{dt.minute:02}:{dt.second:02}')
        return offset_info.abbrev

    def fromutc(self, dt: Optional[datetime]) -> datetime:
        """Override the default implementation in tzinfo which does not make
        sense for acetz.

        The 'dt' passed into this function from datetime.astimezone() is a weird
        one: the components are in UTC time, but the timezone is the target
        tzinfo, in other words, the same acetz as self.

        Warning: Do NOT call dt.isoformat() from this method, because it causes
        an infinite recursion as it tries to figure out the UTC offset. Use
        {dt.date()} and {dt.time()} instead.
        """
        if not isinstance(dt, datetime):
            raise TypeError("fromutc() requires a datetime argument")
        if dt.tzinfo is not self:
            raise ValueError("dt.tzinfo is not self")

        # Extract the epoch_seconds of the source 'dt'
        assert dt is not None
        utcdt = dt.replace(tzinfo=timezone.utc)
        unix_seconds = int(utcdt.timestamp())
        epoch_seconds = unix_seconds - SECONDS_SINCE_UNIX_EPOCH

        # Search the transitions for the matching Transition
        offset_info = self.zs.get_timezone_info_for_seconds(epoch_seconds)
        if not offset_info:
            raise ValueError(f"transition not found for {epoch_seconds}")

        # Convert the date/time fields into local date/time and attach
        # the current acetz object.
        newutcdt = utcdt + timedelta(seconds=offset_info.total_offset)
        newdt = newutcdt.replace(tzinfo=self, fold=offset_info.fold)

        return newdt

    def zone_specifier(self) -> ZoneSpecifier:
        return self.zs
コード例 #2
0
def main() -> None:
    # Configure command line flags.
    parser = argparse.ArgumentParser(description='Zone Agent.')
    parser.add_argument(
        '--viewing_months',
        help='Number of months to use for calculations (12, 13, 14, 36)',
        type=int,
        default=14)
    parser.add_argument('--transition',
                        help='Print the transition instead of timezone info',
                        action='store_true')
    parser.add_argument('--debug',
                        help='Print debugging info',
                        action='store_true')
    parser.add_argument(
        '--in_place_transitions',
        help='Use in-place Transition array to determine Active Transitions',
        action="store_true",
        default=True)
    parser.add_argument('--no_in_place_transitions',
                        help='Disable --in_place_transitions',
                        action="store_false",
                        dest='in_place_transitions')
    parser.add_argument('--optimize_candidates',
                        help='Optimize the candidate transitions',
                        action='store_true',
                        default=True)
    parser.add_argument('--no_optimize_candidates',
                        help='Disable --optimize_candidates',
                        action='store_false',
                        dest='optimize_candidates')
    parser.add_argument('--zone', help='Name of time zone', required=True)
    parser.add_argument('--year', help='Year of interest', type=int)
    parser.add_argument('--date', help='DateTime of interest')
    args = parser.parse_args()

    # Configure logging
    logging.basicConfig(level=logging.INFO)

    # Find the zone.
    zone_info = cast(ZoneInfo, zone_infos.ZONE_INFO_MAP.get(args.zone))
    if not zone_info:
        logging.error("Zone '%s' not found", args.zone)
        sys.exit(1)

    # Create the ZoneSpecifier for zone
    zone_specifier = ZoneSpecifier(
        zone_info_data=zone_info,
        viewing_months=args.viewing_months,
        debug=args.debug,
        in_place_transitions=args.in_place_transitions,
        optimize_candidates=args.optimize_candidates)

    if args.year:
        zone_specifier.init_for_year(args.year)
        if args.debug:
            logging.info('==== Final matches and transitions')
        zone_specifier.print_matches_and_transitions()
    elif args.date:
        dt: datetime = datetime.strptime(args.date, "%Y-%m-%dT%H:%M")
        if args.transition:
            transition = zone_specifier.get_transition_for_datetime(dt)
            if transition:
                logging.info(transition)
            else:
                logging.error('Transition not found')
        else:
            offset_info = zone_specifier.get_timezone_info_for_datetime(dt)
            if not offset_info:
                logging.info('Invalid time')
            else:
                logging.info(
                    '%s (%s)',
                    to_utc_string(
                        offset_info.utc_offset,
                        offset_info.dst_offset,
                    ),
                    offset_info.abbrev,
                )
    else:
        print("One of --year or --date must be provided")
        sys.exit(1)