Title here
Summary here
tzfpy’s feature is very simple, only convert GPS coordinates to timezone name. In fact, those name will be used with other datatime related functions and other use cases.
1pip install tzfpy 1# https://github.com/ringsaturn/tzfpy/blob/main/examples/tzfpy_with_datetime.py
 2from datetime import datetime, timezone
 3from zoneinfo import ZoneInfo
 4
 5from tzfpy import get_tz
 6
 7tz = get_tz(139.7744, 35.6812)  # Tokyo
 8
 9now = datetime.now(timezone.utc)
10now = now.replace(tzinfo=ZoneInfo(tz))
11print(now)Output:
12025-04-29 01:33:56.325194+09:001pip install arrow tzfpy 1# https://github.com/ringsaturn/tzfpy/blob/main/examples/tzfpy_with_arrow.py
 2from zoneinfo import ZoneInfo
 3
 4import arrow
 5from tzfpy import get_tz
 6
 7tz = get_tz(139.7744, 35.6812)  # Tokyo
 8
 9arrow_now = arrow.now(ZoneInfo(tz))
10print(arrow_now)Output:
12025-04-29T10:33:45.551282+09:001pip install tzfpy whenever 1# https://github.com/ringsaturn/tzfpy/blob/main/examples/tzfpy_with_whenever.py
 2from tzfpy import get_tz
 3from whenever import Instant
 4
 5now = Instant.now()
 6
 7tz = get_tz(139.7744, 35.6812)  # Tokyo
 8
 9now = now.to_tz(tz)
10
11print(now)Output:
12025-04-29T10:33:28.427784+09:00[Asia/Tokyo]Consider a table that contains many cities and their GPS coordinates. The fastest way to get their timezone name is to use dataframes’ own map/apply functions.
Pandas does provide built-in apply feature, however, it’s not very efficient. With NumPy’s help, we can get a much faster solution.
1pip install pandas numpy tzfpy 1# https://github.com/ringsaturn/tzfpy/blob/main/examples/tzfpy_with_dataframe_pandas.py
 2import time
 3
 4import citiespy
 5import numpy as np
 6import pandas as pd
 7import tzfpy
 8
 9# lazy init
10_ = tzfpy.get_tz(0, 0)
11
12
13cities_as_dict = []
14for city in citiespy.all_cities():
15    cities_as_dict.append({"name": city.name, "lng": city.lng, "lat": city.lat})
16
17df = pd.DataFrame(cities_as_dict)
18
19
20start = time.perf_counter()
21df["tz_from_tzfpy"] = df.apply(lambda x: tzfpy.get_tz(x.lng, x.lat), axis=1)
22end = time.perf_counter()
23print(f"[tzfpy_with_dataframe] Pandas apply Time taken: {end - start} seconds")
24
25vec_tzfpy_get_tz = np.vectorize(tzfpy.get_tz)
26start = time.perf_counter()
27df["tz_from_tzfpy_vec"] = vec_tzfpy_get_tz(df.lng, df.lat)
28end = time.perf_counter()
29print(
30    f"[tzfpy_with_dataframe] Pandas apply with NumPy vectorize Time taken: {end - start} seconds"
31)Output:
1[tzfpy_with_dataframe] Pandas apply Time taken: 0.8276746249757707 seconds
2[tzfpy_with_dataframe] Pandas apply with NumPy vectorize Time taken: 0.348435917054303 seconds1pip install polars tzfpy 1import time
 2
 3import citiespy
 4import polars as pl
 5import tzfpy
 6
 7# lazy init
 8_ = tzfpy.get_tz(0, 0)
 9
10
11cities_as_dict = []
12for city in citiespy.all_cities():
13    cities_as_dict.append({"name": city.name, "lng": city.lng, "lat": city.lat})
14
15df = pl.from_dicts(cities_as_dict)
16
17start = time.perf_counter()
18df = df.with_columns(
19    pl.struct(["lng", "lat"])
20    .map_elements(
21        lambda cols: tzfpy.get_tz(cols["lng"], cols["lat"]), return_dtype=pl.Utf8
22    )
23    .alias("tz_from_tzfpy")
24)
25end = time.perf_counter()
26print(f"[tzfpy_with_dataframe] Polars Time taken: {end - start} seconds")Output:
1[tzfpy_with_dataframe] Polars Time taken: 0.34632241702638566 seconds1pip install numpy tzfpy 1import time
 2
 3import citiespy
 4import numpy as np
 5import pandas as pd
 6import tzfpy
 7
 8# lazy init
 9_ = tzfpy.get_tz(0, 0)
10
11
12cities_as_dict = []
13for city in citiespy.all_cities():
14    cities_as_dict.append({"name": city.name, "lng": city.lng, "lat": city.lat})
15
16df = pd.DataFrame(cities_as_dict)
17
18lngs = df.lng.values
19lats = df.lat.values
20
21vec_tzfpy_get_tz = np.vectorize(tzfpy.get_tz)
22
23start = time.perf_counter()
24_ = vec_tzfpy_get_tz(lngs, lats)
25end = time.perf_counter()
26print(f"[tzfpy_with_dataframe] Numpy Time taken: {end - start} seconds")Output:
1[tzfpy_with_dataframe] Numpy Time taken: 0.33512612502090633 seconds1pip install fastapi uvicorn tzfpy  1from fastapi import FastAPI, Query
  2from pydantic import BaseModel, Field
  3from tzfpy import data_version, get_tz, get_tzs, timezonenames
  4
  5# lazy init
  6_ = get_tz(0, 0)
  7
  8
  9class TimezoneResponse(BaseModel):
 10    timezone: str = Field(..., description="Timezone", examples=["Asia/Tokyo"])
 11
 12
 13class TimezonesResponse(BaseModel):
 14    timezones: list[str] = Field(
 15        ..., description="Timezones", examples=[["Asia/Shanghai", "Asia/Urumqi"]]
 16    )
 17
 18
 19class TimezonenamesResponse(BaseModel):
 20    timezonenames: list[str] = Field(
 21        ..., description="Timezonenames", examples=[["Etc/GMT+1", "Etc/GMT+2"]]
 22    )
 23
 24
 25class DataVersionResponse(BaseModel):
 26    data_version: str = Field(..., description="Data version", examples=["2025b"])
 27
 28
 29app = FastAPI(
 30    title="tzfpy with FastAPI",
 31    description="tzfpy with FastAPI",
 32    contact={
 33        "name": "tzfpy",
 34        "url": "https://github.com/ringsaturn/tzfpy",
 35    },
 36)
 37
 38
 39@app.get("/")
 40def read_root():
 41    return {"message": "Hello, World!"}
 42
 43
 44@app.get("/timezone", response_model=TimezoneResponse)
 45def get_timezone(
 46    longitude: float = Query(
 47        ...,
 48        description="Longitude",
 49        ge=-180,
 50        le=180,
 51        examples=[139.767125],
 52        openapi_examples={"example-Tokyo": {"value": 139.767125}},
 53    ),
 54    latitude: float = Query(
 55        ...,
 56        description="Latitude",
 57        ge=-90,
 58        le=90,
 59        examples=[35.681236],
 60        openapi_examples={"example-Tokyo": {"value": 35.681236}},
 61    ),
 62):
 63    return TimezoneResponse(timezone=get_tz(longitude, latitude))
 64
 65
 66@app.get("/timezones", response_model=TimezonesResponse)
 67def get_timezones(
 68    longitude: float = Query(
 69        ...,
 70        description="Longitude",
 71        ge=-180,
 72        le=180,
 73        examples=[87.617733],
 74        openapi_examples={"example-Urumqi": {"value": 87.617733}},
 75    ),
 76    latitude: float = Query(
 77        ...,
 78        description="Latitude",
 79        ge=-90,
 80        le=90,
 81        examples=[43.792818],
 82        openapi_examples={"example-Urumqi": {"value": 43.792818}},
 83    ),
 84):
 85    return TimezonesResponse(timezones=get_tzs(longitude, latitude))
 86
 87
 88@app.get("/timezonenames", response_model=TimezonenamesResponse)
 89def get_all_timezones():
 90    return TimezonenamesResponse(timezonenames=timezonenames())
 91
 92
 93@app.get("/data_version", response_model=DataVersionResponse)
 94def get_data_version():
 95    return DataVersionResponse(data_version=data_version())
 96
 97
 98if __name__ == "__main__":
 99    import uvicorn
100
101    uvicorn.run(app, host="0.0.0.0", port=8010)