timelogic-api 1.0.3 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +293 -133
- data/docs/BulkError.md +1 -1
- data/docs/CalendarResponse.md +2 -2
- data/docs/DstResponse.md +2 -2
- data/docs/ElapsedResponse.md +1 -1
- data/docs/ErrorResponse.md +1 -1
- data/docs/TimeApi.md +151 -151
- data/docs/TimePayload.md +1 -1
- data/docs/TimezoneMatch.md +1 -1
- data/docs/TimezoneOffsetResponse.md +2 -2
- data/docs/TimezoneResolvedResponse.md +1 -1
- data/lib/timelogic-api/api/time_api.rb +169 -159
- data/lib/timelogic-api/api/utility_api.rb +1 -1
- data/lib/timelogic-api/api_client.rb +3 -1
- data/lib/timelogic-api/api_error.rb +1 -1
- data/lib/timelogic-api/configuration.rb +1 -1
- data/lib/timelogic-api/models/api_error.rb +1 -1
- data/lib/timelogic-api/models/bulk_error.rb +2 -2
- data/lib/timelogic-api/models/calendar_response.rb +3 -1
- data/lib/timelogic-api/models/diff_endpoint_ref.rb +1 -1
- data/lib/timelogic-api/models/diff_response.rb +1 -1
- data/lib/timelogic-api/models/dst_response.rb +3 -1
- data/lib/timelogic-api/models/elapsed_response.rb +2 -2
- data/lib/timelogic-api/models/error_response.rb +2 -2
- data/lib/timelogic-api/models/get_current_time200_response.rb +1 -1
- data/lib/timelogic-api/models/get_timezone200_response.rb +1 -1
- data/lib/timelogic-api/models/jwk_key.rb +1 -1
- data/lib/timelogic-api/models/jwks_response.rb +1 -1
- data/lib/timelogic-api/models/time_payload.rb +2 -1
- data/lib/timelogic-api/models/time_payload_bulk_item.rb +1 -1
- data/lib/timelogic-api/models/time_payload_bulk_response.rb +1 -1
- data/lib/timelogic-api/models/timezone_match.rb +2 -1
- data/lib/timelogic-api/models/timezone_offset_response.rb +3 -1
- data/lib/timelogic-api/models/timezone_resolved_response.rb +2 -1
- data/lib/timelogic-api/version.rb +1 -1
- data/lib/timelogic-api/world_time_api.rb +192 -0
- data/lib/timelogic-api.rb +2 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5c2aaabeb34292d10a3fa9a740b47b680a83c55d8b804b18e8845e494fa9febb
|
|
4
|
+
data.tar.gz: 85714922fc04495aae65793e4cd412211e2a6e7284bdb96db7c180a9e44221ae
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d831cf4f316848f67d326996d74e191c6a5c50ee76e2f59ce758c15605af66a830b2c93d20ecf6142f91872731a37657206b253926405c3f7d46252b0ad38666
|
|
7
|
+
data.tar.gz: 81edd337490edf0d16218de6c8bc4ccea5fda264431b642aff380c8b4f5ff1020bf446a6a38a82d1bd2e4ab3476aeeeab823b1f876c4424cf516b7265c3d6d68
|
data/README.md
CHANGED
|
@@ -1,188 +1,348 @@
|
|
|
1
|
-
# TimeLogic API
|
|
1
|
+
# TimeLogic API SDK for Ruby
|
|
2
2
|
|
|
3
|
-
Official Ruby
|
|
3
|
+
Official Ruby client for [TimeLogic API](https://api.timelogicapi.com): current time, time zone lookups, conversions, date arithmetic, business-day counts, DST status, calendars, embeddable clocks and signed responses. The package contains two clients:
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
- the `/v1` client, generated from the [TimeLogic API contract](https://github.com/TimeLogic-API-LLC/timelogic-api-sdks/blob/main/openapi/openapi.yaml), with direct and RapidAPI transports;
|
|
6
|
+
- a [WorldTimeAPI-compatible client](#worldtimeapi-compatible-client) for the `/api/timezone` and `/api/ip` routes, which use worldtimeapi.org's paths, fields and plain-text format.
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
Package: [`timelogic-api`](https://rubygems.org/gems/timelogic-api), version 1.1.0. Changes are listed in the [changelog](https://github.com/TimeLogic-API-LLC/timelogic-api-sdks/blob/main/CHANGELOG.md).
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
## Install
|
|
10
11
|
|
|
11
|
-
```
|
|
12
|
-
gem
|
|
12
|
+
```bash
|
|
13
|
+
gem install timelogic-api -v 1.1.0
|
|
13
14
|
```
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
Or in a Gemfile: `gem 'timelogic-api', '1.1.0'`. Requires Ruby 2.7+.
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
gem install ./timelogic-api-1.0.3.gem
|
|
19
|
-
```
|
|
18
|
+
## Quick start
|
|
20
19
|
|
|
21
|
-
|
|
20
|
+
Get an API key, export it as `TIMELOGIC_API_KEY`, and run:
|
|
22
21
|
|
|
23
|
-
|
|
22
|
+
```ruby
|
|
23
|
+
require 'timelogic-api'
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
config = TimeLogic::Api::TransportConfiguration.build(api_key: ENV.fetch('TIMELOGIC_API_KEY'))
|
|
26
|
+
time = TimeLogic::Api::TimeApi.new(TimeLogic::Api::ApiClient.new(config))
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
now = time.get_current_time(tz: 'America/New_York')
|
|
29
|
+
puts "#{now.iso_local} #{now.timezone}"
|
|
30
|
+
```
|
|
28
31
|
|
|
29
|
-
|
|
32
|
+
## Configuration
|
|
30
33
|
|
|
31
|
-
|
|
34
|
+
The transport helper sets the host and credentials for the `/v1` client. Pass a TimeLogic key for the direct API, or a RapidAPI key with the RapidAPI option; the SDK then sends `X-RapidAPI-Key` and `X-RapidAPI-Host` (default host `timelogic-api-world-time-timezones-time-calculations.p.rapidapi.com`, overridable). Keep keys in environment variables or a secret store, not in source control.
|
|
32
35
|
|
|
33
|
-
|
|
36
|
+
```ruby
|
|
37
|
+
require 'timelogic-api'
|
|
38
|
+
|
|
39
|
+
# Direct API (default host https://api.timelogicapi.com, sends Authorization: Bearer <key>)
|
|
40
|
+
direct = TimeLogic::Api::TransportConfiguration.build(api_key: ENV.fetch('TIMELOGIC_API_KEY'))
|
|
34
41
|
|
|
35
|
-
|
|
42
|
+
# RapidAPI: pass only your RapidAPI key; the SDK sets X-RapidAPI-Key and X-RapidAPI-Host
|
|
43
|
+
rapid = TimeLogic::Api::TransportConfiguration.build(api_key: ENV.fetch('RAPIDAPI_KEY'), rapid_api: true)
|
|
36
44
|
|
|
37
|
-
|
|
45
|
+
# A different host (for example a compatible gateway or a test server)
|
|
46
|
+
custom = TimeLogic::Api::TransportConfiguration.build(api_key: ENV.fetch('TIMELOGIC_API_KEY'), base_url: 'https://your-compatible-gateway.example')
|
|
38
47
|
|
|
39
|
-
|
|
40
|
-
|
|
48
|
+
# Request timeout in seconds (default 0, meaning no timeout). The SDK does not retry.
|
|
49
|
+
direct.timeout = 10
|
|
41
50
|
```
|
|
42
51
|
|
|
43
|
-
##
|
|
52
|
+
## Operations
|
|
53
|
+
|
|
54
|
+
| Operation | Endpoint | Method |
|
|
55
|
+
| --- | --- | --- |
|
|
56
|
+
| Current time | `GET /v1/time/current` | `TimeApi#get_current_time` |
|
|
57
|
+
| Convert | `GET /v1/time/convert` | `TimeApi#convert_time` |
|
|
58
|
+
| Add | `GET /v1/time/add` | `TimeApi#add_time` |
|
|
59
|
+
| Difference | `GET /v1/time/diff` | `TimeApi#diff_time` |
|
|
60
|
+
| Elapsed | `GET /v1/time/elapsed` | `TimeApi#get_elapsed` |
|
|
61
|
+
| Timezone | `GET /v1/timezone` | `TimeApi#get_timezone` |
|
|
62
|
+
| Daylight saving | `GET /v1/time/dst` | `TimeApi#get_dst` |
|
|
63
|
+
| Calendar | `GET /v1/time/calendar` | `TimeApi#get_calendar` |
|
|
64
|
+
| Clock | `GET /v1/time/clock` | `TimeApi#get_clock` |
|
|
65
|
+
| Signing keys | `GET /.well-known/time-api-public-key` | `UtilityApi#get_public_signing_key` |
|
|
66
|
+
|
|
67
|
+
Operations take an options hash named after the query parameters in snake_case; `next` is a Ruby keyword, so `get_dst` takes `_next:`. Each operation has a `…_with_http_info` variant that returns `[data, status_code, headers]`. API errors raise `TimeLogic::Api::ApiException` with `code`, `response_headers` and `response_body`. Parameters, response fields and errors for every operation: [How the API works](#how-the-api-works). Generated reference: [TimeApi](https://github.com/TimeLogic-API-LLC/timelogic-api-sdks/blob/main/packages/ruby/docs/TimeApi.md), [UtilityApi](https://github.com/TimeLogic-API-LLC/timelogic-api-sdks/blob/main/packages/ruby/docs/UtilityApi.md) and the models in the same folder.
|
|
44
68
|
|
|
45
|
-
|
|
69
|
+
### Examples
|
|
46
70
|
|
|
47
71
|
```ruby
|
|
48
|
-
# Load the gem
|
|
49
72
|
require 'timelogic-api'
|
|
50
73
|
|
|
51
|
-
|
|
52
|
-
TimeLogic::Api.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
74
|
+
client = TimeLogic::Api::ApiClient.new(TimeLogic::Api::TransportConfiguration.build(api_key: ENV.fetch('TIMELOGIC_API_KEY')))
|
|
75
|
+
time = TimeLogic::Api::TimeApi.new(client)
|
|
76
|
+
|
|
77
|
+
# Convert a New York wall-clock time to Tokyo
|
|
78
|
+
tokyo = time.convert_time(iso: '2026-03-01T09:00:00', source_tz: 'America/New_York', tz: 'Asia/Tokyo')
|
|
79
|
+
|
|
80
|
+
# Add 1 day and 2 hours, shown in New York time
|
|
81
|
+
later = time.add_time(iso: '2026-03-07T12:00:00Z', days: 1, hours: 2, tz: 'America/New_York')
|
|
82
|
+
|
|
83
|
+
# Duration and business days between two instants (Zurich holiday calendar)
|
|
84
|
+
diff = time.diff_time('iso=2026-01-02T00:00:00Z', 'iso=2026-04-30T00:00:00Z', business_days: true, holiday_country: 'CH-ZH')
|
|
85
|
+
puts "#{diff.days} #{diff.direction} #{diff.business_days}" # 118 forward 82
|
|
86
|
+
|
|
87
|
+
# Time left until a deadline
|
|
88
|
+
left = time.get_elapsed(iso: '2027-01-01T00:00:00Z')
|
|
89
|
+
|
|
90
|
+
# Zone details, DST status with the next transition, ISO week number
|
|
91
|
+
berlin = time.get_timezone(tz: 'Europe/Berlin')
|
|
92
|
+
dst = time.get_dst(tz: 'America/New_York', _next: true) # `next` is a Ruby keyword, so the option is _next
|
|
93
|
+
calendar = time.get_calendar(tz: 'Europe/London', week: true)
|
|
94
|
+
|
|
95
|
+
# Embeddable HTML clock
|
|
96
|
+
html = time.get_clock('digital-dashboard', tz: 'Europe/London')
|
|
97
|
+
|
|
98
|
+
# Public signing keys (no API key needed)
|
|
99
|
+
keys = TimeLogic::Api::UtilityApi.new(client).get_public_signing_key
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Errors, headers and signed responses
|
|
103
|
+
|
|
104
|
+
```ruby
|
|
105
|
+
require 'timelogic-api'
|
|
106
|
+
|
|
107
|
+
time = TimeLogic::Api::TimeApi.new(TimeLogic::Api::ApiClient.new(TimeLogic::Api::TransportConfiguration.build(api_key: ENV.fetch('TIMELOGIC_API_KEY'))))
|
|
108
|
+
|
|
109
|
+
begin
|
|
110
|
+
time.get_current_time(tz: 'Bad/Zone')
|
|
111
|
+
rescue TimeLogic::Api::ApiException => e
|
|
112
|
+
puts "#{e.code} #{e.response_body}"
|
|
113
|
+
# 400 {"error":{"code":"INVALID_PARAMETER","message":"Invalid timezone.",...},"request_id":"..."}
|
|
77
114
|
end
|
|
78
115
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
116
|
+
# *_with_http_info returns [data, status code, headers]
|
|
117
|
+
dst, status, headers = time.get_dst_with_http_info(tz: 'Asia/Kolkata', sign: true)
|
|
118
|
+
puts "#{status} #{headers['x-timelogic-quota-limit']} #{headers['x-timelogic-signature']}"
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The SDK does not retry. A `429 QUOTA_EXCEEDED` carries no `Retry-After` header; quotas reset at 00:00 UTC on the 1st of each month. Status codes and error codes: [Errors](#errors).
|
|
122
|
+
|
|
123
|
+
## WorldTimeAPI-compatible client
|
|
124
|
+
|
|
125
|
+
A separate client for the WorldTimeAPI-compatible routes. Code written for worldtimeapi.org needs only the new host and an API key: paths, field names, types and the `.txt` format are the same. The client sends the key as `X-API-Key`, has a 30-second timeout, does not retry, and does not use or change the `/v1` configuration.
|
|
126
|
+
|
|
127
|
+
```ruby
|
|
128
|
+
require 'timelogic-api'
|
|
129
|
+
|
|
130
|
+
wta = TimeLogic::Api::WorldTimeApi::Client.new(api_key: ENV.fetch('TIMELOGIC_API_KEY')) # timeout: 30 seconds
|
|
131
|
+
|
|
132
|
+
zones = wta.list_timezones # ["Africa/Abidjan", ...]
|
|
133
|
+
europe = wta.list_timezones_in_area('Europe') # ["Europe/Amsterdam", ...]
|
|
134
|
+
london = wta.get_timezone('Europe/London')
|
|
135
|
+
puts "#{london.datetime} #{london.utc_offset} #{london.dst}"
|
|
136
|
+
text = wta.get_timezone_text('Europe/London') # "abbreviation: GMT\nclient_ip: ..."
|
|
137
|
+
mine = wta.get_ip # the caller's address
|
|
138
|
+
google = wta.get_ip('8.8.8.8')
|
|
103
139
|
|
|
104
140
|
begin
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
rescue TimeLogic::Api::
|
|
109
|
-
puts "
|
|
141
|
+
wta.get_timezone('Nope/Zone')
|
|
142
|
+
rescue TimeLogic::Api::WorldTimeApi::UnknownLocationError
|
|
143
|
+
puts 'unknown location' # 404 {"error":"unknown location"}
|
|
144
|
+
rescue TimeLogic::Api::WorldTimeApi::Error => e
|
|
145
|
+
puts "#{e.status} #{e.error}"
|
|
110
146
|
end
|
|
111
147
|
|
|
148
|
+
# Signed responses: read the headers (lower-case names) through request_raw
|
|
149
|
+
signed = TimeLogic::Api::WorldTimeApi::Client.new(api_key: ENV.fetch('TIMELOGIC_API_KEY'), sign: true)
|
|
150
|
+
raw = signed.request_raw('/api/timezone/Europe/London')
|
|
151
|
+
puts "#{raw.status} #{raw.headers['x-timelogic-signature']} #{raw.body}"
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Routes, fields and errors: [WorldTimeAPI-compatible routes](#worldtimeapi-compatible-routes).
|
|
155
|
+
|
|
156
|
+
## Known issues
|
|
157
|
+
|
|
158
|
+
Checked against the live API for this release. All other operations, including single-target `current`, `convert` and `timezone` calls, decode normally.
|
|
159
|
+
|
|
160
|
+
- Bulk `get_current_time` / `convert_time` calls (comma-separated selectors) and `offset` lookups with `get_timezone` return `nil`. Ask for the parsed JSON instead of a model:
|
|
161
|
+
|
|
162
|
+
```ruby
|
|
163
|
+
require 'timelogic-api'
|
|
164
|
+
|
|
165
|
+
time = TimeLogic::Api::TimeApi.new(TimeLogic::Api::ApiClient.new(TimeLogic::Api::TransportConfiguration.build(api_key: ENV.fetch('TIMELOGIC_API_KEY'))))
|
|
166
|
+
|
|
167
|
+
# Bulk current/convert and offset timezone lookups: ask for the parsed JSON instead of a model
|
|
168
|
+
items = time.get_current_time(tz: 'Europe/London,Asia/Tokyo', debug_return_type: 'Object')
|
|
169
|
+
puts items[1][:timezone] # Asia/Tokyo
|
|
170
|
+
|
|
171
|
+
offset = time.get_timezone(offset: '+05:30', debug_return_type: 'Object')
|
|
172
|
+
puts offset[:matching_zones].map { |zone| zone[:timezone] }.inspect # ["Asia/Colombo", "Asia/Kolkata"]
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## How the API works
|
|
176
|
+
|
|
177
|
+
### Base URLs
|
|
178
|
+
|
|
179
|
+
| Transport | Base URL | Credentials the SDK sends |
|
|
180
|
+
| --- | --- | --- |
|
|
181
|
+
| Direct API (default) | `https://api.timelogicapi.com` | `Authorization: Bearer <your TimeLogic API key>` |
|
|
182
|
+
| RapidAPI | `https://timelogic-api-world-time-timezones-time-calculations.p.rapidapi.com` | `X-RapidAPI-Key: <your RapidAPI key>` and `X-RapidAPI-Host: <RapidAPI host>` |
|
|
183
|
+
|
|
184
|
+
The gateway accepts a direct key in three places, checked in this order: `Authorization: Bearer <key>`, the `X-API-Key` header, and the `api_key` query parameter. The `/v1` clients in this package send the bearer header; the WorldTimeAPI-compatible client sends `X-API-Key`. Sending two different keys in one request is rejected with `401 UNAUTHORIZED` ("Conflicting API key credentials."). All operations are `GET` requests (`HEAD` is answered like `GET` without a body).
|
|
185
|
+
|
|
186
|
+
### Choosing a target (selector rules)
|
|
187
|
+
|
|
188
|
+
Most time operations take one *target*, chosen with exactly one selector family:
|
|
189
|
+
|
|
190
|
+
| Selector | Example | Notes |
|
|
191
|
+
| --- | --- | --- |
|
|
192
|
+
| `tz` | `America/New_York` | IANA zone, matched case-insensitively. Links and aliases resolve to their canonical zone (`Europe/Stockholm` returns `Europe/Berlin`, `UTC` returns `Etc/UTC`). `Etc/GMT+5` is UTC-05:00 (POSIX sign). |
|
|
193
|
+
| `ip` | `8.8.8.8` | IPv4 or IPv6. Private, reserved and loopback addresses have no zone and return `404 NOT_FOUND`. |
|
|
194
|
+
| `lat` + `lon` | `40.7128`, `-74.006` | Both are required together. |
|
|
195
|
+
| `offset` | `-04:00` | Fixed offset, `+HH:MM` or `-HH:MM` only (`+0530` and `+5` are rejected). The response has `timezone: null`. |
|
|
196
|
+
| `auto_tz` | `true` | Uses the caller's IP address as seen by the gateway. Not available on the clock route. |
|
|
197
|
+
| `utc` | `true` | Forces UTC (convert and add only). The response has `iso_local: null` and `timezone: null`. |
|
|
198
|
+
|
|
199
|
+
Combining two selector families returns `400 AMBIGUOUS_TARGET`. Where a target is optional and none is given, the response is in UTC with `timezone: null` and `iso_local: null`; `/v1/timezone` requires a target and returns `400 MISSING_TARGET` without one.
|
|
200
|
+
|
|
201
|
+
**Bulk requests.** `current` and `convert` accept a comma-separated list in one `tz`, `ip` or `offset` selector (at most 10 values; any comma, even a trailing one, switches to bulk). The response is then an array in request order; each item is either a normal time payload or an item error `{ "item", "error": { "code", "message", "details" }, "request_id" }`, so one bad value does not fail the whole request. Every request URL is limited to 8192 characters.
|
|
202
|
+
|
|
203
|
+
**Input timestamps.** `convert`, `add`, `calendar`, `elapsed` and `clock` take one input instant: `unix` (whole seconds, -62135596800 to 253402300799), `unix_ms` (whole milliseconds) or `iso` (ISO-8601). An `iso` value without an offset is a local wall-clock time; pair it with one hint (`source_tz`, `source_ip`, `source_lat` + `source_lon`, or `source_offset`), otherwise it is read as UTC. Dates must exist (`2027-02-29` returns `400 INVALID_TIMESTAMP`), a local time inside a spring-forward gap returns `400 INVALID_TIMESTAMP`, and an ambiguous fall-back time resolves to its first occurrence.
|
|
204
|
+
|
|
205
|
+
**Custom formatting.** Every JSON time route accepts `format`, a `strftime`-style template that adds a `formatted` field. Supported directives: `%a %A %b %B %C %d %D %e %F %h %H %I %j %k %l %m %M %n %p %P %r %R %s %S %t %T %u %v %w %x %X %y %Y %z %:z %Z %%`, with the `-`, `_` and `0` padding flags on numeric directives. `%Z` prints the IANA zone name (or `UTC+HH:MM` for an offset target), not an abbreviation. Any other directive returns `400 INVALID_PARAMETER`. On `diff` and `elapsed`, `format` is a duration template instead, using `%days`, `%hours`, `%minutes` and `%seconds` (each a total in that unit, so 118 days renders `%days days %hours hours` as `118 days 2832 hours`).
|
|
206
|
+
|
|
207
|
+
### Operations
|
|
208
|
+
|
|
209
|
+
| Operation | Endpoint | What it returns |
|
|
210
|
+
| --- | --- | --- |
|
|
211
|
+
| Current time | `GET /v1/time/current` | The current time for one target, or an array for a bulk selector. |
|
|
212
|
+
| Convert | `GET /v1/time/convert` | One input instant (`unix`, `unix_ms` or `iso`) expressed in a target zone or offset; bulk targets supported. |
|
|
213
|
+
| Add | `GET /v1/time/add` | A base instant (default: now) plus `seconds`, `minutes`, `hours` and `days`, in a target zone. `days` are exact 24-hour days, so the wall-clock time shifts across a DST change. |
|
|
214
|
+
| Difference | `GET /v1/time/diff` | The duration between `from` and `to`, with `direction` and optional business days. |
|
|
215
|
+
| Elapsed | `GET /v1/time/elapsed` | Time elapsed since, or remaining until, a reference instant (compared with now or a `compare_*` instant), with optional business days. |
|
|
216
|
+
| Timezone | `GET /v1/timezone` | Zone metadata for a target: current time plus `offset` (minutes) and `dst`. An `offset` lookup adds `matching_zones`. |
|
|
217
|
+
| Daylight saving | `GET /v1/time/dst` | Whether DST is active for a target; `next=true` adds `next_transition`. |
|
|
218
|
+
| Calendar | `GET /v1/time/calendar` | Calendar fields (`year`, `month`, `month_name`, `day`) for an instant and target; `week=true` adds the ISO `week_number`. |
|
|
219
|
+
| Clock | `GET /v1/time/clock` | An embeddable HTML clock fragment (`text/html`). `style` is required (30 styles, for example `digital-dashboard` or `analog-station`); `auto_tz` and `sign` are not supported here. |
|
|
220
|
+
| Signing keys | `GET /.well-known/time-api-public-key` | The public Ed25519 keys (JWKS) used to verify signed responses. No API key needed; `kid` filters to one key. |
|
|
221
|
+
|
|
222
|
+
#### Time payload fields
|
|
223
|
+
|
|
224
|
+
`current`, `convert`, `add`, `timezone`, `dst` and `calendar` all return these fields:
|
|
225
|
+
|
|
226
|
+
| Field | Type | Meaning |
|
|
227
|
+
| --- | --- | --- |
|
|
228
|
+
| `unix` | integer | Unix seconds. |
|
|
229
|
+
| `unix_ms` | integer | Unix milliseconds. |
|
|
230
|
+
| `utc` | string | UTC timestamp, for example `2026-11-01T13:16:03Z`. |
|
|
231
|
+
| `iso_local` | string or null | Local ISO-8601 time with offset; `null` for UTC-only responses. |
|
|
232
|
+
| `rfc2822` | string | RFC 2822 local time. |
|
|
233
|
+
| `human` | string | Readable local time, for example `November 1, 2026, 8:16 AM America/New_York`. |
|
|
234
|
+
| `day_number` | integer | Day of the week counted from Sunday (1 = Sunday ... 7 = Saturday). |
|
|
235
|
+
| `day_short`, `day_full` | string | `Sun` / `Sunday`. |
|
|
236
|
+
| `timezone` | string or null | Canonical IANA zone; `null` for offset and UTC targets. |
|
|
237
|
+
| `formatted` | string | Present only when `format` was sent. |
|
|
238
|
+
|
|
239
|
+
Extra fields per operation:
|
|
240
|
+
|
|
241
|
+
- `/v1/timezone`: `offset` (minutes east of UTC) and `dst` (boolean); with an `offset` selector also `matching_zones`, the geographic zones currently at that offset (`UTC` and `Etc/*` excluded).
|
|
242
|
+
- `/v1/time/dst`: `dst_active` and, with `next=true`, `next_transition` (the next UTC-offset change, or `null` if the zone has none).
|
|
243
|
+
- `/v1/time/calendar`: `year`, `month`, `month_name`, `day`, and with `week=true` `week_number` (ISO 8601 week).
|
|
244
|
+
- `/v1/time/diff`: `seconds`, `minutes`, `hours`, `days` (each a total, not a remainder), `direction` (`forward`, `backward` or `same`), `human` (always in hours, minutes and seconds), `from.unix_ms`, `to.unix_ms`, and `business_days` when requested.
|
|
245
|
+
- `/v1/time/elapsed`: `seconds`, `minutes`, `hours`, `days`, `human`, `direction` (`left` while the reference is still ahead, `passed` once it is behind), and `business_days` when requested.
|
|
246
|
+
|
|
247
|
+
#### Difference and elapsed
|
|
248
|
+
|
|
249
|
+
`diff` takes two *time specifiers*, `from` and `to`: `now`, `unix=<seconds>`, `unix_ms=<milliseconds>`, `iso=<ISO-8601>`, `offset=±HH:MM`, `tz=<IANA zone>` or `ip=<address>`. The `tz=`, `ip=` and `offset=` forms mean "now" (they only choose the calendar date used for business days). A local `iso` can be placed with `from_tz`/`from_ip`/`from_lat`+`from_lon`/`from_offset` and the matching `to_*` hints.
|
|
250
|
+
|
|
251
|
+
`elapsed` takes one reference instant (`unix`, `unix_ms` or `iso` with `source_*` hints) and compares it with now, with a `compare_unix`/`compare_unix_ms`/`compare_iso` instant (with `compare_source_*` hints), or with the current time at a target selector.
|
|
252
|
+
|
|
253
|
+
**Business days.** Set `business_days=true` to add `business_days`. Days are counted by calendar date, start included and end excluded. Add `holiday_country` (ISO 3166-1 alpha-2, any letter case, optionally with a subdivision such as `US-CA` or `CH-ZH`) to skip that calendar's public holidays; `holiday_subdivision` (for example `ZH`, `ENG`, `01`) selects a region and requires `holiday_country`. Weekends follow the calendar's country (Friday/Saturday for `SA`, Saturday/Sunday when no calendar is given). Holiday coverage is 1900 to 2100. Example: from `2026-01-02T00:00:00Z` to `2026-04-30T00:00:00Z` gives `business_days: 83` with `holiday_country=FR`, `82` with `CH-ZH`, and `79` with `SA`.
|
|
254
|
+
|
|
255
|
+
### Errors
|
|
256
|
+
|
|
257
|
+
Every error has the same JSON body:
|
|
258
|
+
|
|
259
|
+
```json
|
|
260
|
+
{ "error": { "code": "INVALID_PARAMETER", "message": "Invalid timezone.", "details": { "tz": "Bad/Zone" } }, "request_id": "547f27d2-1acc-46e6-a9a6-686ec2ca99d9" }
|
|
112
261
|
```
|
|
113
262
|
|
|
114
|
-
|
|
263
|
+
| Status | Codes | When |
|
|
264
|
+
| --- | --- | --- |
|
|
265
|
+
| 400 | `INVALID_PARAMETER`, `INVALID_TIMESTAMP`, `AMBIGUOUS_TARGET`, `MISSING_TARGET` | A parameter is malformed or out of range, two selector families were combined, or a required target is missing. |
|
|
266
|
+
| 401 | `UNAUTHORIZED` | Missing, invalid or conflicting API key credentials. |
|
|
267
|
+
| 403 | `SUBSCRIPTION_INACTIVE` | The key or the customer subscription is not active. |
|
|
268
|
+
| 404 | `NOT_FOUND` | Unknown route (including a trailing slash), or an `ip` with no timezone mapping. |
|
|
269
|
+
| 405 | `METHOD_NOT_ALLOWED` | A method other than `GET`/`HEAD`; the response carries `Allow: GET, HEAD`. |
|
|
270
|
+
| 429 | `QUOTA_EXCEEDED` | The plan's monthly quota is used up. |
|
|
271
|
+
| 500 | `INTERNAL_ERROR` | Internal failure, including signing failures. |
|
|
272
|
+
| 501 | `DEPENDENCY_NOT_READY` | A required resolver or dependency is not ready. |
|
|
273
|
+
| 502 | `INTERNAL_ERROR` | The gateway could not reach the core service. |
|
|
115
274
|
|
|
116
|
-
|
|
275
|
+
Quote `request_id` (also sent as the `X-Request-Id` header) when you contact support.
|
|
117
276
|
|
|
118
|
-
|
|
119
|
-
------------ | ------------- | ------------- | -------------
|
|
120
|
-
*TimeLogic::Api::TimeApi* | [**add_time**](docs/TimeApi.md#add_time) | **GET** /v1/time/add | Add modifiers to a timestamp
|
|
121
|
-
*TimeLogic::Api::TimeApi* | [**convert_time**](docs/TimeApi.md#convert_time) | **GET** /v1/time/convert | Convert a timestamp into a target timezone or offset
|
|
122
|
-
*TimeLogic::Api::TimeApi* | [**diff_time**](docs/TimeApi.md#diff_time) | **GET** /v1/time/diff | Difference between two instants
|
|
123
|
-
*TimeLogic::Api::TimeApi* | [**get_calendar**](docs/TimeApi.md#get_calendar) | **GET** /v1/time/calendar | Calendar projection for a target instant
|
|
124
|
-
*TimeLogic::Api::TimeApi* | [**get_clock**](docs/TimeApi.md#get_clock) | **GET** /v1/time/clock | Render a live HTML clock
|
|
125
|
-
*TimeLogic::Api::TimeApi* | [**get_current_time**](docs/TimeApi.md#get_current_time) | **GET** /v1/time/current | Get the current time for a target
|
|
126
|
-
*TimeLogic::Api::TimeApi* | [**get_dst**](docs/TimeApi.md#get_dst) | **GET** /v1/time/dst | Daylight-saving status for a target
|
|
127
|
-
*TimeLogic::Api::TimeApi* | [**get_elapsed**](docs/TimeApi.md#get_elapsed) | **GET** /v1/time/elapsed | Time elapsed since or remaining until a reference instant
|
|
128
|
-
*TimeLogic::Api::TimeApi* | [**get_timezone**](docs/TimeApi.md#get_timezone) | **GET** /v1/timezone | Resolve timezone information for a target
|
|
129
|
-
*TimeLogic::Api::UtilityApi* | [**get_public_signing_key**](docs/UtilityApi.md#get_public_signing_key) | **GET** /.well-known/time-api-public-key | Public signing key set
|
|
277
|
+
### Response headers, quotas and limits
|
|
130
278
|
|
|
279
|
+
| Header | Meaning |
|
|
280
|
+
| --- | --- |
|
|
281
|
+
| `X-Request-Id` | Request identifier, on every response. |
|
|
282
|
+
| `X-Auth-Mode` | How the request was authenticated (`api_key`). |
|
|
283
|
+
| `X-TimeLogic-Customer-ID` | Your customer identifier. |
|
|
284
|
+
| `X-TimeLogic-Plan` | Your plan, for example `free`. |
|
|
285
|
+
| `X-TimeLogic-Quota-Limit` | Requests included per month, or `unlimited`. |
|
|
286
|
+
| `X-TimeLogic-Quota-State` | Cached quota state, for example `active`. |
|
|
287
|
+
| `X-TimeLogic-Key-Id` | On unsigned responses, the ID of the API key that made the request; on signed responses, the signing key `kid`. |
|
|
131
288
|
|
|
132
|
-
|
|
289
|
+
Header names are case-insensitive in HTTP. Some SDKs return headers as a plain map keyed by the name as received (most arrive in lower case, the signature headers as `X-TimeLogic-Signature…`), so compare names case-insensitively.
|
|
133
290
|
|
|
134
|
-
-
|
|
135
|
-
- [TimeLogic::Api::BulkError](docs/BulkError.md)
|
|
136
|
-
- [TimeLogic::Api::CalendarResponse](docs/CalendarResponse.md)
|
|
137
|
-
- [TimeLogic::Api::DiffEndpointRef](docs/DiffEndpointRef.md)
|
|
138
|
-
- [TimeLogic::Api::DiffResponse](docs/DiffResponse.md)
|
|
139
|
-
- [TimeLogic::Api::DstResponse](docs/DstResponse.md)
|
|
140
|
-
- [TimeLogic::Api::ElapsedResponse](docs/ElapsedResponse.md)
|
|
141
|
-
- [TimeLogic::Api::ErrorResponse](docs/ErrorResponse.md)
|
|
142
|
-
- [TimeLogic::Api::GetCurrentTime200Response](docs/GetCurrentTime200Response.md)
|
|
143
|
-
- [TimeLogic::Api::GetTimezone200Response](docs/GetTimezone200Response.md)
|
|
144
|
-
- [TimeLogic::Api::JwkKey](docs/JwkKey.md)
|
|
145
|
-
- [TimeLogic::Api::JwksResponse](docs/JwksResponse.md)
|
|
146
|
-
- [TimeLogic::Api::TimePayload](docs/TimePayload.md)
|
|
147
|
-
- [TimeLogic::Api::TimePayloadBulkItem](docs/TimePayloadBulkItem.md)
|
|
148
|
-
- [TimeLogic::Api::TimePayloadBulkResponse](docs/TimePayloadBulkResponse.md)
|
|
149
|
-
- [TimeLogic::Api::TimezoneMatch](docs/TimezoneMatch.md)
|
|
150
|
-
- [TimeLogic::Api::TimezoneOffsetResponse](docs/TimezoneOffsetResponse.md)
|
|
151
|
-
- [TimeLogic::Api::TimezoneResolvedResponse](docs/TimezoneResolvedResponse.md)
|
|
291
|
+
Quotas are counted per UTC calendar month and reset at 00:00 UTC on the 1st. There is no remaining-requests or reset header, no `Retry-After` on `429`, and no published per-second limit. Bulk selectors take at most 10 values and every request URL is limited to 8192 characters.
|
|
152
292
|
|
|
293
|
+
### Signed responses
|
|
153
294
|
|
|
154
|
-
|
|
295
|
+
Pass `sign` (`true`) on any JSON route except the clock to receive a detached Ed25519 signature over the exact response body, in these headers: `X-TimeLogic-Signature` (Base64), `X-TimeLogic-Key-Id`, `X-TimeLogic-Signature-Alg` (`Ed25519`), `X-TimeLogic-Signature-Timestamp`, `X-TimeLogic-Content-SHA256` and `X-TimeLogic-Signature-Input`. To verify: decode `X-TimeLogic-Signature-Input` (Base64URL), check that its `content-sha256` line matches the SHA-256 of the body bytes, then verify the signature over the decoded input with the key whose `kid` matches, from `GET /.well-known/time-api-public-key`. The body is unchanged by signing. The headers are exposed to browsers through CORS.
|
|
155
296
|
|
|
297
|
+
## WorldTimeAPI-compatible routes
|
|
156
298
|
|
|
157
|
-
|
|
158
|
-
### bearerAuth
|
|
299
|
+
### Routes
|
|
159
300
|
|
|
160
|
-
|
|
301
|
+
The client covers all 12 routes of the WorldTimeAPI-compatible contract ([`openapi/openapi-worldtimeapi.yaml`](https://github.com/TimeLogic-API-LLC/timelogic-api-sdks/blob/main/openapi/openapi-worldtimeapi.yaml)). Each JSON route has a plain-text twin ending in `.txt`.
|
|
161
302
|
|
|
162
|
-
|
|
303
|
+
| Route | Returns |
|
|
304
|
+
| --- | --- |
|
|
305
|
+
| `GET /api/timezone`, `/api/timezone.txt` | Every zone name. |
|
|
306
|
+
| `GET /api/timezone/{area}`, `.txt` | The zone names in an area such as `Europe`, or the time object for a one-word zone such as `UTC`. |
|
|
307
|
+
| `GET /api/timezone/{area}/{location}`, `.txt` | The time object for a zone such as `Europe/London`. |
|
|
308
|
+
| `GET /api/timezone/{area}/{location}/{region}`, `.txt` | The time object for a three-part zone such as `America/Argentina/Salta`. |
|
|
309
|
+
| `GET /api/ip`, `/api/ip.txt` | The time object for the caller's IP address. |
|
|
310
|
+
| `GET /api/ip/{ip}`, `.txt` | The time object for an IPv4 or IPv6 address. |
|
|
163
311
|
|
|
312
|
+
Zone names match in any letter case. Query parameters other than `api_key` and `sign` are ignored.
|
|
164
313
|
|
|
165
|
-
|
|
166
|
-
- **API key parameter name**: X-API-Key
|
|
167
|
-
- **Location**: HTTP header
|
|
314
|
+
### Time object fields
|
|
168
315
|
|
|
169
|
-
|
|
316
|
+
| Field | Example | Meaning |
|
|
317
|
+
| --- | --- | --- |
|
|
318
|
+
| `abbreviation` | `GMT` | Zone abbreviation. |
|
|
319
|
+
| `client_ip` | `203.0.113.7` | The caller's IP address. |
|
|
320
|
+
| `datetime` | `2026-11-01T13:18:00.721000+00:00` | Local time with six fractional digits (millisecond resolution, so the last three are `000`). |
|
|
321
|
+
| `day_of_week` | `0` | 0 = Sunday ... 6 = Saturday. |
|
|
322
|
+
| `day_of_year` | `305` | 1-366. |
|
|
323
|
+
| `dst` | `false` | Whether DST is in effect. |
|
|
324
|
+
| `dst_from` | `null` | Start of the current DST period, or `null`. |
|
|
325
|
+
| `dst_offset` | `0` | DST offset in seconds. |
|
|
326
|
+
| `dst_until` | `null` | End of the current DST period, or `null`. |
|
|
327
|
+
| `raw_offset` | `0` | Standard offset in seconds. |
|
|
328
|
+
| `timezone` | `Europe/London` | Zone name. |
|
|
329
|
+
| `unixtime` | `1793539080` | Unix seconds. |
|
|
330
|
+
| `utc_datetime` | `2026-11-01T13:18:00.721000+00:00` | UTC time. |
|
|
331
|
+
| `utc_offset` | `+00:00` | Current total offset. |
|
|
332
|
+
| `week_number` | `44` | ISO 8601 week number. |
|
|
170
333
|
|
|
334
|
+
The `.txt` variants return the same fields as `key: value` lines in alphabetical order.
|
|
171
335
|
|
|
172
|
-
|
|
173
|
-
- **API key parameter name**: api_key
|
|
174
|
-
- **Location**: URL query string
|
|
336
|
+
### Errors and authentication
|
|
175
337
|
|
|
176
|
-
|
|
338
|
+
Unknown zones and malformed addresses return `404` with worldtimeapi.org's bodies: `{"error":"unknown location"}`, `{"error":"malformed ip"}` or `{"error":"not found"}` (on `.txt` routes, a line starting with `Error:`). Authentication and quota errors (`401`, `403`, `429`) use the TimeLogic error body shown in [Errors](#errors). Every route requires a TimeLogic API key, which the client sends as the `X-API-Key` header, and successful calls count toward the monthly quota like `/v1` calls. The client connects to the direct API (`https://api.timelogicapi.com` by default); it does not use the RapidAPI transport.
|
|
177
339
|
|
|
340
|
+
With signing enabled, the client adds `sign=true` and responses carry the same detached signature headers as `/v1` ([Signed responses](#signed-responses)); the body is byte-identical to the unsigned body. Use the raw request method to read those headers.
|
|
178
341
|
|
|
179
|
-
|
|
180
|
-
- **API key parameter name**: X-RapidAPI-Key
|
|
181
|
-
- **Location**: HTTP header
|
|
342
|
+
## Support
|
|
182
343
|
|
|
183
|
-
|
|
344
|
+
Questions and problem reports: [issue tracker](https://github.com/TimeLogic-API-LLC/timelogic-api-sdks/issues). Security issues: see [SECURITY.md](https://github.com/TimeLogic-API-LLC/timelogic-api-sdks/blob/main/SECURITY.md). Service status: [status.timelogicapi.com](https://status.timelogicapi.com).
|
|
184
345
|
|
|
346
|
+
## License
|
|
185
347
|
|
|
186
|
-
-
|
|
187
|
-
- **API key parameter name**: X-RapidAPI-Host
|
|
188
|
-
- **Location**: HTTP header
|
|
348
|
+
[Unlicense](https://github.com/TimeLogic-API-LLC/timelogic-api-sdks/blob/main/LICENSE).
|
data/docs/BulkError.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
| ---- | ---- | ----------- | ----- |
|
|
7
7
|
| **error** | [**ApiError**](ApiError.md) | | |
|
|
8
8
|
| **request_id** | **String** | | |
|
|
9
|
-
| **timestamp** | **Time** | Intentionally omitted from public API error responses to avoid exposing request timing; use request_id for support correlation. | [optional] |
|
|
9
|
+
| **timestamp** | **Time** | Intentionally omitted from public API error responses, including per-item errors inside bulk arrays, to avoid exposing request timing; use request_id for support correlation. | [optional] |
|
|
10
10
|
| **item** | **String** | | |
|
|
11
11
|
|
|
12
12
|
## Example
|
data/docs/CalendarResponse.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
| **iso_local** | **String** | | |
|
|
11
11
|
| **rfc2822** | **String** | | |
|
|
12
12
|
| **human** | **String** | | |
|
|
13
|
-
| **day_number** | **Integer** |
|
|
13
|
+
| **day_number** | **Integer** | Day of the week counted from Sunday (1 = Sunday, 2 = Monday ... 7 = Saturday). | |
|
|
14
14
|
| **day_short** | **String** | | |
|
|
15
15
|
| **day_full** | **String** | | |
|
|
16
16
|
| **timezone** | **String** | | |
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
| **month** | **Integer** | | |
|
|
20
20
|
| **month_name** | **String** | | |
|
|
21
21
|
| **day** | **Integer** | | |
|
|
22
|
-
| **week_number** | **Integer** |
|
|
22
|
+
| **week_number** | **Integer** | ISO 8601 week number (present with `week=true`). It belongs to the ISO week-year, which is not returned and can differ from `year` near January 1 (2027-01-01 is week 53 of 2026). | [optional] |
|
|
23
23
|
|
|
24
24
|
## Example
|
|
25
25
|
|
data/docs/DstResponse.md
CHANGED
|
@@ -10,13 +10,13 @@
|
|
|
10
10
|
| **iso_local** | **String** | | |
|
|
11
11
|
| **rfc2822** | **String** | | |
|
|
12
12
|
| **human** | **String** | | |
|
|
13
|
-
| **day_number** | **Integer** |
|
|
13
|
+
| **day_number** | **Integer** | Day of the week counted from Sunday (1 = Sunday, 2 = Monday ... 7 = Saturday). | |
|
|
14
14
|
| **day_short** | **String** | | |
|
|
15
15
|
| **day_full** | **String** | | |
|
|
16
16
|
| **timezone** | **String** | | |
|
|
17
17
|
| **formatted** | **String** | | [optional] |
|
|
18
18
|
| **dst_active** | **Boolean** | | |
|
|
19
|
-
| **next_transition** | **Time** |
|
|
19
|
+
| **next_transition** | **Time** | Present only with `next=true`. The instant of the next UTC offset change, written in the offset in force before it (e.g. `2026-11-01T02:00:00-04:00`); the new offset is not returned. `null` when no change is scheduled, for offset targets and with no selector. Tracks offset changes only, so `dst_active` can change without one. | [optional] |
|
|
20
20
|
|
|
21
21
|
## Example
|
|
22
22
|
|
data/docs/ElapsedResponse.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
| **hours** | **Integer** | | |
|
|
10
10
|
| **days** | **Integer** | | |
|
|
11
11
|
| **human** | **String** | | |
|
|
12
|
-
| **direction** | **String** | `left` means the
|
|
12
|
+
| **direction** | **String** | `left` means the reference instant is after the compared instant (now, or `compare_*`). `passed` means it is before it, or equal to it. | |
|
|
13
13
|
| **formatted** | **String** | | [optional] |
|
|
14
14
|
| **business_days** | **Integer** | | [optional] |
|
|
15
15
|
|
data/docs/ErrorResponse.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
| ---- | ---- | ----------- | ----- |
|
|
7
7
|
| **error** | [**ApiError**](ApiError.md) | | |
|
|
8
8
|
| **request_id** | **String** | | |
|
|
9
|
-
| **timestamp** | **Time** | Intentionally omitted from public API error responses to avoid exposing request timing; use request_id for support correlation. | [optional] |
|
|
9
|
+
| **timestamp** | **Time** | Intentionally omitted from public API error responses, including per-item errors inside bulk arrays, to avoid exposing request timing; use request_id for support correlation. | [optional] |
|
|
10
10
|
|
|
11
11
|
## Example
|
|
12
12
|
|