Home
Softono
Geo2tz

Geo2tz

Open source MIT Go
94
Stars
17
Forks
2
Issues
2
Watchers
1 week
Last Commit

About Geo2tz

# Geo2Tz [![QA](https://github.com/noandrea/geo2tz/actions/workflows/quality.yml/badge.svg)](https://github.com/noandrea/geo2tz/actions/workflows/quality.yml) [![GoDoc](https://godoc.org/github.com/noandrea/geo2tz?status.svg)](https://godoc.org/github.com/noandrea/geo2tz) [![Go Report Card](https://goreportcard.com/badge/github.com/noandrea/geo2tz)](https://goreportcard.com/report/github.com/noandrea/geo2tz) A self-hostable service to get the timezone given geo-coordinates (lat/lng) Timezone data comes from [github.com/evansiroky/timezone-boundary-builder](https://github.com/evansiroky/timezone-boundary-builder). [![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-direct.svg)](https://stand-with-ukraine.pp.ua/) ## Maturity Level This project is considered mature and stable, having undergone extensive testing and refinement over time. It is now in a state where it can be reliably used in production environments. The badge below shows the number of Docker pul ...

Platforms

Web Self-hosted

Languages

Go

Geo2Tz

QA GoDoc Go Report Card

A self-hostable service to get the timezone given geo-coordinates (lat/lng)

Timezone data comes from github.com/evansiroky/timezone-boundary-builder.

Stand With Ukraine

Maturity Level

This project is considered mature and stable, having undergone extensive testing and refinement over time. It is now in a state where it can be reliably used in production environments. The badge below shows the number of Docker pulls for the project:

GHCR Pulls

Contributing

We value your feedback and contributions! If you encounter any bugs or have ideas for new features, please don't hesitate to open an issue. Your input is crucial in helping us improve and evolve the project.

Motivations

Geo-coordinates can be sensitive information. This project provides a privacy-friendly, self-hosted solution that ensures coordinates are not leaked to third-party services.

API

The service exposes two endpoints: one to look up the timezone for a pair of coordinates, and one to report the version of the timezone database in use.

Timezone lookup

GET /tz/${LATITUDE}/${LONGITUDE}

Returns a JSON reply (http/200), for example:

curl -s http://localhost:2004/tz/51.477811/0 | jq
{
  "coords": {
    "lat": 51.47781,
    "lon": 0
  },
  "tz": "Europe/London"
}

On invalid input it returns a 4xx response, for example:

curl -v http://localhost:2004/tz/51.477811/1000 | jq
*   Trying 127.0.0.1:2004...
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0* Connected to localhost (127.0.0.1) port 2004 (#0)
> GET /tz/51.477811/1000 HTTP/1.1
> Host: localhost:2004
> User-Agent: curl/7.81.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 400 Bad Request
< Content-Type: application/json; charset=UTF-8
< Vary: Origin
< Date: Fri, 23 Jun 2023 19:09:29 GMT
< Content-Length: 54
<
{ [54 bytes data]
100    54  100    54    0     0  89403      0 --:--:-- --:--:-- --:--:-- 54000
* Connection #0 to host localhost left intact
{
  "message": "lon value 1000 out of range (-180/+180)"
}

Database version

The version of the database in use is exposed at /tz/version:

curl -s http://localhost:2004/tz/version | jq
{
  "version": "2026b",
  "url": "https://github.com/evansiroky/timezone-boundary-builder/releases/tag/2026b",
  "geo_data_url": "https://github.com/evansiroky/timezone-boundary-builder/releases/download/2026b/timezones-with-oceans.geojson.zip"
}

Coordinates are decimal degrees in the ranges [-90, 90] for latitude and [-180, 180] for longitude.

Authorization

Geo2Tz supports a basic token authorization mechanism, if the configuration value for web.auth_token_value is a non-empty string, geo2tz will check the query parameter value to authorize incoming requests.

For example, running the service with:

docker run --pull=always -p 2004:2004 -e GEO2TZ_WEB_AUTH_TOKEN_VALUE=secret ghcr.io/noandrea/geo2tz:latest

will enable authorization. With the authorization enabled, a query that does not specify the token will fail with an HTTP code 401:

> curl -sv http://localhost:2004/tz/41.902782/12.496365 | jq
*   Trying 127.0.0.1:2004...
* Connected to localhost (127.0.0.1) port 2004 (#0)
> GET /tz/41.902782/12.496365 HTTP/1.1
> Host: localhost:2004
> User-Agent: curl/7.81.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 401 Unauthorized
< Content-Type: application/json; charset=UTF-8
< Vary: Origin
< Date: Sun, 31 Jul 2022 20:06:56 GMT
< Content-Length: 27
<
{ [27 bytes data]
* Connection #0 to host localhost left intact
{
  "message": "unauthorized"
}

Passing the token in the query parameters will succeed instead:

> curl -s http://localhost:2004/tz/41.902782/12.496365\?t\=secret | jq
{
  "coords": {
    "lat": 41.902782,
    "lon": 12.496365
  },
  "tz": "Europe/Rome"
}

Configuration

Geo2Tz is configured via environment variables (prefixed with GEO2TZ_) or an optional config file. Defaults are listed below.

Environment variable Default Description
GEO2TZ_WEB_LISTEN_ADDRESS :2004 Address the HTTP server binds to.
GEO2TZ_WEB_AUTH_TOKEN_VALUE (empty) When non-empty, enables token authorization.
GEO2TZ_WEB_AUTH_TOKEN_PARAM_NAME t Query-parameter name carrying the auth token.
GEO2TZ_TZ_DATABASE_NAME bundled tz DB Path to the timezone GeoJSON database.
GEO2TZ_TZ_VERSION_FILE bundled version file Path to the version metadata file.

A config file is loaded automatically when present at /etc/geo2tz/config.{yaml,toml,json}. A custom path can be passed with --config. Keys mirror the env vars but are nested under web.* / tz.* (e.g. web.auth_token_value).

Docker

Docker image is available at geo2tz

docker run --pull=always -p 2004:2004 ghcr.io/noandrea/geo2tz:latest

The image is built FROM scratch, so it contains only the geo2tz binary and the bundled timezone database — no shell, package manager, or utilities.

Docker Compose

Docker Compose YAML example:

services:
  geo2tz:
    container_name: geo2tz
    image: ghcr.io/noandrea/geo2tz:latest   # pin to a release tag for production deployments
    ports:
      - "2004:2004"
    restart: unless-stopped
    # uncomment to enable authorization via request token
    # environment:
    #   GEO2TZ_WEB_AUTH_TOKEN_VALUE: ${GEO2TZ_TOKEN}
    #   GEO2TZ_WEB_AUTH_TOKEN_PARAM_NAME: t
    #   GEO2TZ_WEB_LISTEN_ADDRESS: ":2004"

The version top-level field has been removed from the Compose spec and is no longer needed. The image is built FROM scratch, so it has no shell or wget/curl — Compose healthchecks based on those will not work; use an external probe instead.

K8s

Kubernetes configuration example:

---
# Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: geo2tz
  name: geo2tz
spec:
  replicas: 1
  revisionHistoryLimit: 3
  selector:
    matchLabels:
      app: geo2tz
  template:
    metadata:
      labels:
        app: geo2tz
    spec:
      containers:
        - name: geo2tz
          image: ghcr.io/noandrea/geo2tz:latest   # pin to a release tag for production deployments
          imagePullPolicy: Always
          ports:
            - name: http
              containerPort: 2004
          # if GEO2TZ_WEB_AUTH_TOKEN_VALUE is non-empty, token authorization is enabled
          # env:
          #   - name: GEO2TZ_WEB_AUTH_TOKEN_VALUE
          #     value: "secretsmaybebetter" # default is empty
          #   - name: GEO2TZ_WEB_AUTH_TOKEN_PARAM_NAME
          #     value: "t"                  # default value
          #   - name: GEO2TZ_WEB_LISTEN_ADDRESS
          #     value: ":2004"              # default value
          readinessProbe:
            httpGet:
              path: /tz/version
              port: http
            initialDelaySeconds: 2
            periodSeconds: 10
          livenessProbe:
            httpGet:
              path: /tz/version
              port: http
            initialDelaySeconds: 10
            periodSeconds: 30
          resources:
            requests:
              cpu: 50m
              memory: 128Mi
            limits:
              cpu: 500m
              memory: 512Mi
---
# Service for the above deployment
apiVersion: v1
kind: Service
metadata:
  name: geo2tz-service
spec:
  type: ClusterIP
  ports:
    - name: http
      port: 80
      protocol: TCP
      targetPort: http
  selector:
    app: geo2tz

Development notes

To update the timezone database you have a few options:

  1. download the version specified in the tzdata/version.json file
geo2tz update current
  1. update to the latest version available
geo2tz update latest
  1. update to a specific version
geo2tz update 2023b

The update command downloads the timezone GeoJSON zip and writes a version file into the tzdata directory; the version file is used to track the current version of the database.