Movatterモバイル変換


[0]ホーム

URL:


Skip to content
Search Gists
Sign in Sign up

Instantly share code, notes, and snippets.

@RhetTbull
Last activeFebruary 3, 2025 11:13
    • Star(2)You must be signed in to star a gist
    • Fork(2)You must be signed in to fork a gist
    Save RhetTbull/db70c113efd03029c6ff619f4699ce34 to your computer and use it in GitHub Desktop.
    Get the named timezone for a given location in python using native macOS CoreLocation APIs
    """Get named timezone for a location on macOS using CoreLocation
    To use this script, you need to have pyobjc-core and pyobjc-framework-CoreLocation installed:
    pip install pyobjc-core pyobjc-framework-CoreLocation
    This script uses CoreLocation to get the timezone for a given latitude and longitude
    as well as the timezone offset for a given date.
    It effectively does the same thing as python packages like [tzfpy](https://pypi.org/project/tzfpy/)
    or [timezonefinder](https://pypi.org/project/timezonefinder/) but uses macOS native APIs.
    """
    # /// script
    # dependencies = [
    # "pyobjc-core",
    # "pyobjc-framework-CoreLocation"
    # ]
    # ///
    importdatetime
    importobjc
    fromCoreLocationimportCLGeocoder,CLLocation
    fromFoundationimportNSDate,NSRunLoop,NSTimeZone
    WAIT_FOR_COMPLETION=0.01# wait time for async completion in seconds
    COMPLETION_TIMEOUT=5.0# timeout for async completion in seconds
    deftimezone_for_location(latitude:float,longitude:float)->NSTimeZone:
    withobjc.autorelease_pool():
    location=CLLocation.alloc().initWithLatitude_longitude_(latitude,longitude)
    geocoder=CLGeocoder.alloc().init()
    result= {"timezone":None,"error":None}
    completed=False
    defcompletion(placemarks,error):
    nonlocalcompleted
    iferror:
    result["error"]=error.localizedDescription()
    else:
    placemark=placemarks[0]ifplacemarkselseNone
    ifplacemarkandplacemark.timeZone():
    result["timezone"]=placemark.timeZone()
    else:
    result["error"]="Unable to determine timezone"
    completed=True
    geocoder.reverseGeocodeLocation_completionHandler_(location,completion)
    # reverseGeocodeLocation_completionHandler_ is async so run the event loop until completion
    # I usuall use threading.Event for this type of thing in pyobjc but the the thread blocked forever
    waiting=0
    whilenotcompleted:
    NSRunLoop.currentRunLoop().runMode_beforeDate_(
    "NSDefaultRunLoopMode",
    NSDate.dateWithTimeIntervalSinceNow_(WAIT_FOR_COMPLETION),
    )
    waiting+=WAIT_FOR_COMPLETION
    ifwaiting>=COMPLETION_TIMEOUT:
    raiseTimeoutError(
    f"Timeout waiting for completion of reverseGeocodeLocation_completionHandler_:{waiting} seconds"
    )
    ifresult["error"]:
    raiseException(f"Error:{result['error']}")
    returnresult["timezone"]
    if__name__=="__main__":
    importargparse
    importtime
    defparse_date(date_str):
    try:
    returndatetime.datetime.strptime(date_str,"%Y-%m-%d %H:%M:%S")
    exceptValueError:
    returndatetime.datetime.strptime(date_str,"%Y-%m-%d")
    parser=argparse.ArgumentParser(description="Get timezone for a location")
    parser.add_argument("latitude",type=float,help="Latitude of location")
    parser.add_argument("longitude",type=float,help="Longitude of location")
    parser.add_argument(
    "--date",
    type=lambdad:parse_date(d),
    default=datetime.datetime.now(),
    help="Date/time for timezone offset in format 'YYYY-MM-DD HH:MM:SS' or 'YYYY-MM-DD'",
    )
    args=parser.parse_args()
    try:
    start_t=time.time_ns()
    timezone=timezone_for_location(args.latitude,args.longitude)
    offset=timezone.secondsFromGMTForDate_(
    args.date
    )# takes an NSDate but pybojc will convert
    end_t=time.time_ns()
    print(
    f"Timezone:{timezone.name()}, offset:{offset}, took:{(end_t-start_t)/1e6:.2f} ms"
    )
    exceptExceptionase:
    print(f"Error:{e}")
    @RhetTbull
    Copy link
    Author

    MIT License

    @RhetTbull
    Copy link
    Author

    Run like this:

    uv run"https://gist.githubusercontent.com/RhetTbull/db70c113efd03029c6ff619f4699ce34/raw/06f34e6d64f054faa88c1caea4a4fa3968e14848/tzname.py" 34 -118

    Which ouputs:

    Timezone: America/Los_Angeles, offset: -28800, took: 317.20 ms

    Or

    uv run"https://gist.githubusercontent.com/RhetTbull/db70c113efd03029c6ff619f4699ce34/raw/06f34e6d64f054faa88c1caea4a4fa3968e14848/tzname.py" 34 -118 --date"2024-06-01"

    which outputs

    Timezone: America/Los_Angeles, offset: -25200, took: 264.47 ms

    @RhetTbull
    Copy link
    Author

    Thanks to@simonw for the tip on including uvscript block.

    @oPromessa
    Copy link

    oPromessa commentedJan 26, 2025
    edited
    Loading

    Amazing. Offset accounts for DST based on sample date.

    Tries to extract DST status viatimezone.isDaylightSavingTime() but it comes as False in both cases. Sorry don't master Apple Foundation framework.

    $ python tzname.py 43 -9 --date"2024-06-01 10:00:00"Timezone: Europe/Madrid, offset: 7200, took: 254.66 ms$ python tzname.py  43 -9 --date"2024-01-01 10:00:00" Timezone: Europe/Madrid, offset: 3600, took: 304.73 ms

    Added:

    # Get DST informationis_dst=timezone.isDaylightSavingTimeForDate_(args.date)dst_offset=timezone.daylightSavingTimeOffsetForDate_(args.date)dst_timezone_name=timezone.abbreviationForDate_(args.date)print(f"Timezone:{timezone.name()}, offset:{offset}, "f"DST:{is_dst}, DST offset:{dst_offset}, "f"DST timezone name:{dst_timezone_name}, "f"took:{(end_t-start_t)/1e6:.2f} ms"        )

    @RhetTbull
    Copy link
    Author

    RhetTbull commentedJan 27, 2025
    edited
    Loading

    Weird.timezone.isDaylightSavingTimeForDate_(args.date) works correctly for me.

    ❯ python tz.py 34 -118 --date"2021-06-01"Timezone: America/Los_Angeles, offset: -25200, DST: True, took: 281.25 ms❯ python tz.py 34 -118 --date"2021-01-01"Timezone: America/Los_Angeles, offset: -28800, DST: False, took: 292.69 ms

    I added:

    is_dst=timezone.isDaylightSavingTimeForDate_(args.date)print(f"Timezone:{timezone.name()}, offset:{offset}, DST:{is_dst}, took:{(end_t-start_t)/1e6:.2f} ms"        )

    @agouliel
    Copy link

    Very nice, thank you

    Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

    [8]ページ先頭

    ©2009-2025 Movatter.jp