Places

Time zone at a place

The IANA time zone at a latitude and longitude, offline, and the local time and UTC offset there, summer time counted.

Version 1.0.0 · 3 functions · 3 crates

#timezones#geo#dates#maps

Functions

What use timezone_at.qwer gives a program, with the types Quillo sees. To take only some, or under other names: use timezone_at, timezone_all_at from timezone_at (Quillo 0.6).

timezone_at(lat: float, lon: float) → stror an error

The time zone's name at a point, such as "America/New_York". At sea it is an Etc/GMT±n zone.

timezone_all_at(lat: float, lon: float) → listor an error

Every zone that claims a point: more than one only where borders are disputed.

timezone_local(lat: float, lon: float, at: int) → anyor an error

What time it is at a point, or at the Unix time at (seconds; 0 for now): { zone, local, offset, offset_minutes, abbreviation }, local as 2026-10-29T14:05:00, offset as +01:00, summer time counted.

Get it

$ quillo install timezone_at               # timezone_at.qwer into this folder$ quillo install timezone_at --example     # and its example, timezone_at.qwe

Or with curl:

$ curl -O https://quillolang.org/plugins/files/timezone_at.qwer$ curl -O https://quillolang.org/plugins/files/timezone_at.qwe

Then, in your program, all of it or only what you call:

main.qwe
use timezone_at.qweruse timezone_at, timezone_all_at from timezone_at      // Quillo 0.6: only these

It uses these crates, which cargo fetches the first time the plugin is built:

[dependencies]
tzf-rs = "0.4"chrono = { version = "0.4", default-features = false, features = ["std", "clock"] }chrono-tz = "0.10"

Example

timezone_at.qwe
// Delivery slots shown in the customer's own time: the time zone of an address's coordinates,// and what time it is there.////   quillo run timezone_at.qwe      then open http://localhost:8080/zone?lat=40.71&lon=-74.0use "timezone_at.qwer"route GET /zone ? { lat: float, lon: float } {    let here = timezone_local(lat, lon, 0)?    { zone: here.zone, offset: here.offset, now_there: here.local }}// 1 July 2026 12:00 UTC at four warehouses: summer time shows in the offsets.route GET /warehouses = [    { city: "Amsterdam", lat: 52.37, lon: 4.89 }, { city: "Sydney", lat: -33.87, lon: 151.21 },    { city: "Phoenix", lat: 33.45, lon: -112.07 }, { city: "Kathmandu", lat: 27.7, lon: 85.32 },] | map((w) => { let t = timezone_local(w.lat, w.lon, 1782907200)?; { city: w.city, zone: t.zone, local: t.local, abbreviation: t.abbreviation } })route GET /sea = { atlantic: timezone_at(30.0, -40.0)?, bad: timezone_at(95.0, 0.0).error }
$ quillo run timezone_at.qwe$ curl 'localhost:8080/zone?lat=40.71&lon=-74.0'$ curl 'localhost:8080/warehouses'$ curl 'localhost:8080/sea'

Source

timezone_at.qwer
//! The IANA time zone at a latitude and longitude, offline (no API key, no network): "Europe/Amsterdam" for a delivery address or a photo's GPS, and the local time and UTC offset there.//! version: 1.0.0//!//! [dependencies]//! tzf-rs = "0.4"//! chrono = { version = "0.4", default-features = false, features = ["std", "clock"] }//! chrono-tz = "0.10"use chrono::{Offset, TimeZone, Utc};use serde_json::{json, Value};use std::sync::OnceLock;/// The zone finder, built once (its data is in the library; the first call takes a moment).fn finder() -> &'static tzf_rs::DefaultFinder {    static F: OnceLock<tzf_rs::DefaultFinder> = OnceLock::new();    F.get_or_init(tzf_rs::DefaultFinder::new)}fn check(lat: f64, lon: f64) -> Result<(), String> {    if !(-90.0..=90.0).contains(&lat) || !(-180.0..=180.0).contains(&lon) {        return Err(format!("{}, {} is not a place: latitude is -90 to 90, longitude -180 to 180", lat, lon));    }    Ok(())}/// The time zone's name at a point, such as "America/New_York". At sea it is an `Etc/GMT±n` zone.pub fn timezone_at(lat: f64, lon: f64) -> Result<String, String> {    check(lat, lon)?;    Ok(finder().get_tz_name(lon, lat).to_string())}/// Every zone that claims a point: more than one only where borders are disputed.pub fn timezone_all_at(lat: f64, lon: f64) -> Result<Vec<String>, String> {    check(lat, lon)?;    Ok(finder().get_tz_names(lon, lat).into_iter().map(str::to_string).collect())}/// What time it is at a point, or at the Unix time `at` (seconds; 0 for now): `{ zone, local, offset, offset_minutes, abbreviation }`,/// `local` as `2026-10-29T14:05:00`, `offset` as `+01:00`, summer time counted.pub fn timezone_local(lat: f64, lon: f64, at: i64) -> Result<Value, String> {    check(lat, lon)?;    let name = finder().get_tz_name(lon, lat);    let tz: chrono_tz::Tz = name.parse().map_err(|_| format!("{} is not a zone this library knows", name))?;    let when = if at == 0 { Utc::now() } else { Utc.timestamp_opt(at, 0).single().ok_or(format!("{} is not a time", at))? };    let local = when.with_timezone(&tz);    let secs = local.offset().fix().local_minus_utc();    Ok(json!({        "zone": name, "local": local.format("%Y-%m-%dT%H:%M:%S").to_string(), "offset": local.format("%:z").to_string(),        "offset_minutes": secs / 60, "abbreviation": local.format("%Z").to_string(),    }))}
Coordinates coordinates.qwer · 1.0.0Coordinates as people write them, such as 52°22'N 4°53'E or N 52° 22.2', read as one, written as degrees-minutes-seconds, and converted to and from UTM.geomapsformsgps7 views · 8 downloadsH3 hexagons h3.qwer · 1.0.0H3 hexagon cells: the cell of a point at a resolution, its neighbours within k rings, its outline for a map, and distances between cells.geomapshexagonssearchdelivery7 views · 8 downloadsKML and KMZ kml.qwer · 1.0.0KML and KMZ files from Google Earth and My Maps read to GeoJSON, placemarks with their names, descriptions, folders and extended data, and GeoJSON written back as KML or KMZ.geogeojsonmapsimport7 views · 8 downloadsMaidenhead locators maidenhead.qwer · 1.0.0Maidenhead grid locators as radio amateurs use them (FN31pr, JN58td): from a latitude and longitude at 2 to 10 characters, back to the square's centre and corners, and the distance and bearing between two.geomapsgpslocation7 views · 8 downloadsMap clusters map_clusters.qwer · 1.0.0Map markers clustered by zoom as Supercluster does: thousands of points loaded once, then for each view and zoom the clusters with their counts and the single points, a cluster's points, and the zoom where it opens.mapsgeogeojsonperformance7 views · 7 downloadsMap projections projections.qwer · 1.0.0Coordinates moved between map projections offline, by EPSG code or PROJ string: GPS degrees to Web Mercator, UTM, the British, Dutch and Swiss grids and some 6,000 others, for points and whole GeoJSON.geomapsgeojsongps8 views · 9 downloads
Thread
78Useful? Like it, or add to its thread below.

Thread 0 posts

On Time zone at a place: questions, tips, corrections, and code that uses it.

No posts yet. The first one opens the thread.