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:00
1pip 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:00
1pip 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 seconds
1pip 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 seconds
1pip 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 seconds
1pip 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)