timelogic-api 1.0.3 → 2.0.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 +314 -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/JwkKey.md +5 -1
- data/docs/TimeApi.md +157 -155
- data/docs/TimePayload.md +1 -1
- data/docs/TimezoneMatch.md +3 -23
- data/docs/TimezoneResponse.md +46 -0
- data/lib/timelogic-api/api/time_api.rb +175 -180
- 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/jwk_key.rb +27 -5
- 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 +29 -183
- data/lib/timelogic-api/models/timezone_match.rb +6 -186
- data/lib/timelogic-api/models/{timezone_offset_response.rb → timezone_response.rb} +21 -14
- data/lib/timelogic-api/version.rb +1 -1
- data/lib/timelogic-api/world_time_api.rb +192 -0
- data/lib/timelogic-api.rb +3 -4
- metadata +5 -8
- data/docs/GetTimezone200Response.md +0 -49
- data/docs/TimezoneOffsetResponse.md +0 -44
- data/docs/TimezoneResolvedResponse.md +0 -42
- data/lib/timelogic-api/models/get_timezone200_response.rb +0 -105
- data/lib/timelogic-api/models/timezone_resolved_response.rb +0 -434
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
=begin
|
|
2
2
|
#TimeLogic API | A World Time API
|
|
3
3
|
|
|
4
|
-
#
|
|
4
|
+
#Direct API contract for client integrations. It documents authentication, endpoint parameters, response shapes, public signing keys, and signed JSON controls. Authentication: - the API supports `Authorization: Bearer <token>`, `X-API-Key`, and `api_key` query credentials - RapidAPI access uses `X-RapidAPI-Key` and `X-RapidAPI-Host`; the SDKs expose this as a `rapidApi` transport option that accepts only the RapidAPI key Behavioral notes: - all documented operations are `GET` - only one selector family may be used at a time - current and convert support bulk only through one comma-separated `tz`, `ip`, or `offset` selector - bulk selectors accept at most 10 values, and every request URL is limited to 8192 characters - add, diff, calendar, dst, elapsed, timezone, and clock are single-target routes - credentials are extracted in Authorization, X-API-Key, then api_key query order; conflicting values are rejected - the first server is the default API host. The second server is the RapidAPI gateway and can be selected or overridden by SDK configuration - `sign` is available on supported JSON routes and is not supported on `/v1/time/clock`
|
|
5
5
|
|
|
6
6
|
The version of the OpenAPI document: 1.0.0
|
|
7
7
|
|
|
@@ -14,47 +14,21 @@ require 'date'
|
|
|
14
14
|
require 'time'
|
|
15
15
|
|
|
16
16
|
module TimeLogic::Api
|
|
17
|
+
# One geographic zone whose current offset equals the requested offset.
|
|
17
18
|
class TimezoneMatch
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
attr_accessor :unix_ms
|
|
21
|
-
|
|
22
|
-
attr_accessor :utc
|
|
23
|
-
|
|
24
|
-
attr_accessor :iso_local
|
|
25
|
-
|
|
26
|
-
attr_accessor :rfc2822
|
|
27
|
-
|
|
28
|
-
attr_accessor :human
|
|
29
|
-
|
|
30
|
-
attr_accessor :day_number
|
|
31
|
-
|
|
32
|
-
attr_accessor :day_short
|
|
33
|
-
|
|
34
|
-
attr_accessor :day_full
|
|
35
|
-
|
|
19
|
+
# IANA timezone name.
|
|
36
20
|
attr_accessor :timezone
|
|
37
21
|
|
|
38
|
-
|
|
39
|
-
|
|
22
|
+
# Current UTC offset of the zone in minutes.
|
|
40
23
|
attr_accessor :offset
|
|
41
24
|
|
|
25
|
+
# Whether daylight saving time is currently in effect in the zone.
|
|
42
26
|
attr_accessor :dst
|
|
43
27
|
|
|
44
28
|
# Attribute mapping from ruby-style variable name to JSON key.
|
|
45
29
|
def self.attribute_map
|
|
46
30
|
{
|
|
47
|
-
:'unix' => :'unix',
|
|
48
|
-
:'unix_ms' => :'unix_ms',
|
|
49
|
-
:'utc' => :'utc',
|
|
50
|
-
:'iso_local' => :'iso_local',
|
|
51
|
-
:'rfc2822' => :'rfc2822',
|
|
52
|
-
:'human' => :'human',
|
|
53
|
-
:'day_number' => :'day_number',
|
|
54
|
-
:'day_short' => :'day_short',
|
|
55
|
-
:'day_full' => :'day_full',
|
|
56
31
|
:'timezone' => :'timezone',
|
|
57
|
-
:'formatted' => :'formatted',
|
|
58
32
|
:'offset' => :'offset',
|
|
59
33
|
:'dst' => :'dst'
|
|
60
34
|
}
|
|
@@ -68,17 +42,7 @@ module TimeLogic::Api
|
|
|
68
42
|
# Attribute type mapping.
|
|
69
43
|
def self.openapi_types
|
|
70
44
|
{
|
|
71
|
-
:'unix' => :'Integer',
|
|
72
|
-
:'unix_ms' => :'Integer',
|
|
73
|
-
:'utc' => :'Time',
|
|
74
|
-
:'iso_local' => :'String',
|
|
75
|
-
:'rfc2822' => :'String',
|
|
76
|
-
:'human' => :'String',
|
|
77
|
-
:'day_number' => :'Integer',
|
|
78
|
-
:'day_short' => :'String',
|
|
79
|
-
:'day_full' => :'String',
|
|
80
45
|
:'timezone' => :'String',
|
|
81
|
-
:'formatted' => :'String',
|
|
82
46
|
:'offset' => :'Integer',
|
|
83
47
|
:'dst' => :'Boolean'
|
|
84
48
|
}
|
|
@@ -87,17 +51,9 @@ module TimeLogic::Api
|
|
|
87
51
|
# List of attributes with nullable: true
|
|
88
52
|
def self.openapi_nullable
|
|
89
53
|
Set.new([
|
|
90
|
-
:'iso_local',
|
|
91
54
|
])
|
|
92
55
|
end
|
|
93
56
|
|
|
94
|
-
# List of class defined in allOf (OpenAPI v3)
|
|
95
|
-
def self.openapi_all_of
|
|
96
|
-
[
|
|
97
|
-
:'TimePayload'
|
|
98
|
-
]
|
|
99
|
-
end
|
|
100
|
-
|
|
101
57
|
# Initializes the object
|
|
102
58
|
# @param [Hash] attributes Model attributes in the form of hash
|
|
103
59
|
def initialize(attributes = {})
|
|
@@ -113,70 +69,12 @@ module TimeLogic::Api
|
|
|
113
69
|
h[k.to_sym] = v
|
|
114
70
|
}
|
|
115
71
|
|
|
116
|
-
if attributes.key?(:'unix')
|
|
117
|
-
self.unix = attributes[:'unix']
|
|
118
|
-
else
|
|
119
|
-
self.unix = nil
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
if attributes.key?(:'unix_ms')
|
|
123
|
-
self.unix_ms = attributes[:'unix_ms']
|
|
124
|
-
else
|
|
125
|
-
self.unix_ms = nil
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
if attributes.key?(:'utc')
|
|
129
|
-
self.utc = attributes[:'utc']
|
|
130
|
-
else
|
|
131
|
-
self.utc = nil
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
if attributes.key?(:'iso_local')
|
|
135
|
-
self.iso_local = attributes[:'iso_local']
|
|
136
|
-
else
|
|
137
|
-
self.iso_local = nil
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
if attributes.key?(:'rfc2822')
|
|
141
|
-
self.rfc2822 = attributes[:'rfc2822']
|
|
142
|
-
else
|
|
143
|
-
self.rfc2822 = nil
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
if attributes.key?(:'human')
|
|
147
|
-
self.human = attributes[:'human']
|
|
148
|
-
else
|
|
149
|
-
self.human = nil
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
if attributes.key?(:'day_number')
|
|
153
|
-
self.day_number = attributes[:'day_number']
|
|
154
|
-
else
|
|
155
|
-
self.day_number = nil
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
if attributes.key?(:'day_short')
|
|
159
|
-
self.day_short = attributes[:'day_short']
|
|
160
|
-
else
|
|
161
|
-
self.day_short = nil
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
if attributes.key?(:'day_full')
|
|
165
|
-
self.day_full = attributes[:'day_full']
|
|
166
|
-
else
|
|
167
|
-
self.day_full = nil
|
|
168
|
-
end
|
|
169
|
-
|
|
170
72
|
if attributes.key?(:'timezone')
|
|
171
73
|
self.timezone = attributes[:'timezone']
|
|
172
74
|
else
|
|
173
75
|
self.timezone = nil
|
|
174
76
|
end
|
|
175
77
|
|
|
176
|
-
if attributes.key?(:'formatted')
|
|
177
|
-
self.formatted = attributes[:'formatted']
|
|
178
|
-
end
|
|
179
|
-
|
|
180
78
|
if attributes.key?(:'offset')
|
|
181
79
|
self.offset = attributes[:'offset']
|
|
182
80
|
else
|
|
@@ -195,46 +93,6 @@ module TimeLogic::Api
|
|
|
195
93
|
def list_invalid_properties
|
|
196
94
|
warn '[DEPRECATED] the `list_invalid_properties` method is obsolete'
|
|
197
95
|
invalid_properties = Array.new
|
|
198
|
-
if @unix.nil?
|
|
199
|
-
invalid_properties.push('invalid value for "unix", unix cannot be nil.')
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
if @unix_ms.nil?
|
|
203
|
-
invalid_properties.push('invalid value for "unix_ms", unix_ms cannot be nil.')
|
|
204
|
-
end
|
|
205
|
-
|
|
206
|
-
if @utc.nil?
|
|
207
|
-
invalid_properties.push('invalid value for "utc", utc cannot be nil.')
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
if @rfc2822.nil?
|
|
211
|
-
invalid_properties.push('invalid value for "rfc2822", rfc2822 cannot be nil.')
|
|
212
|
-
end
|
|
213
|
-
|
|
214
|
-
if @human.nil?
|
|
215
|
-
invalid_properties.push('invalid value for "human", human cannot be nil.')
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
if @day_number.nil?
|
|
219
|
-
invalid_properties.push('invalid value for "day_number", day_number cannot be nil.')
|
|
220
|
-
end
|
|
221
|
-
|
|
222
|
-
if @day_number > 7
|
|
223
|
-
invalid_properties.push('invalid value for "day_number", must be smaller than or equal to 7.')
|
|
224
|
-
end
|
|
225
|
-
|
|
226
|
-
if @day_number < 1
|
|
227
|
-
invalid_properties.push('invalid value for "day_number", must be greater than or equal to 1.')
|
|
228
|
-
end
|
|
229
|
-
|
|
230
|
-
if @day_short.nil?
|
|
231
|
-
invalid_properties.push('invalid value for "day_short", day_short cannot be nil.')
|
|
232
|
-
end
|
|
233
|
-
|
|
234
|
-
if @day_full.nil?
|
|
235
|
-
invalid_properties.push('invalid value for "day_full", day_full cannot be nil.')
|
|
236
|
-
end
|
|
237
|
-
|
|
238
96
|
if @timezone.nil?
|
|
239
97
|
invalid_properties.push('invalid value for "timezone", timezone cannot be nil.')
|
|
240
98
|
end
|
|
@@ -254,56 +112,18 @@ module TimeLogic::Api
|
|
|
254
112
|
# @return true if the model is valid
|
|
255
113
|
def valid?
|
|
256
114
|
warn '[DEPRECATED] the `valid?` method is obsolete'
|
|
257
|
-
return false if @unix.nil?
|
|
258
|
-
return false if @unix_ms.nil?
|
|
259
|
-
return false if @utc.nil?
|
|
260
|
-
return false if @rfc2822.nil?
|
|
261
|
-
return false if @human.nil?
|
|
262
|
-
return false if @day_number.nil?
|
|
263
|
-
return false if @day_number > 7
|
|
264
|
-
return false if @day_number < 1
|
|
265
|
-
return false if @day_short.nil?
|
|
266
|
-
return false if @day_full.nil?
|
|
267
115
|
return false if @timezone.nil?
|
|
268
116
|
return false if @offset.nil?
|
|
269
117
|
return false if @dst.nil?
|
|
270
118
|
true
|
|
271
119
|
end
|
|
272
120
|
|
|
273
|
-
# Custom attribute writer method with validation
|
|
274
|
-
# @param [Object] day_number Value to be assigned
|
|
275
|
-
def day_number=(day_number)
|
|
276
|
-
if day_number.nil?
|
|
277
|
-
fail ArgumentError, 'day_number cannot be nil'
|
|
278
|
-
end
|
|
279
|
-
|
|
280
|
-
if day_number > 7
|
|
281
|
-
fail ArgumentError, 'invalid value for "day_number", must be smaller than or equal to 7.'
|
|
282
|
-
end
|
|
283
|
-
|
|
284
|
-
if day_number < 1
|
|
285
|
-
fail ArgumentError, 'invalid value for "day_number", must be greater than or equal to 1.'
|
|
286
|
-
end
|
|
287
|
-
|
|
288
|
-
@day_number = day_number
|
|
289
|
-
end
|
|
290
|
-
|
|
291
121
|
# Checks equality by comparing each attribute.
|
|
292
122
|
# @param [Object] Object to be compared
|
|
293
123
|
def ==(o)
|
|
294
124
|
return true if self.equal?(o)
|
|
295
125
|
self.class == o.class &&
|
|
296
|
-
unix == o.unix &&
|
|
297
|
-
unix_ms == o.unix_ms &&
|
|
298
|
-
utc == o.utc &&
|
|
299
|
-
iso_local == o.iso_local &&
|
|
300
|
-
rfc2822 == o.rfc2822 &&
|
|
301
|
-
human == o.human &&
|
|
302
|
-
day_number == o.day_number &&
|
|
303
|
-
day_short == o.day_short &&
|
|
304
|
-
day_full == o.day_full &&
|
|
305
126
|
timezone == o.timezone &&
|
|
306
|
-
formatted == o.formatted &&
|
|
307
127
|
offset == o.offset &&
|
|
308
128
|
dst == o.dst
|
|
309
129
|
end
|
|
@@ -317,7 +137,7 @@ module TimeLogic::Api
|
|
|
317
137
|
# Calculates hash code according to all attributes.
|
|
318
138
|
# @return [Integer] Hash code
|
|
319
139
|
def hash
|
|
320
|
-
[
|
|
140
|
+
[timezone, offset, dst].hash
|
|
321
141
|
end
|
|
322
142
|
|
|
323
143
|
# Builds the object from hash
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
=begin
|
|
2
2
|
#TimeLogic API | A World Time API
|
|
3
3
|
|
|
4
|
-
#
|
|
4
|
+
#Direct API contract for client integrations. It documents authentication, endpoint parameters, response shapes, public signing keys, and signed JSON controls. Authentication: - the API supports `Authorization: Bearer <token>`, `X-API-Key`, and `api_key` query credentials - RapidAPI access uses `X-RapidAPI-Key` and `X-RapidAPI-Host`; the SDKs expose this as a `rapidApi` transport option that accepts only the RapidAPI key Behavioral notes: - all documented operations are `GET` - only one selector family may be used at a time - current and convert support bulk only through one comma-separated `tz`, `ip`, or `offset` selector - bulk selectors accept at most 10 values, and every request URL is limited to 8192 characters - add, diff, calendar, dst, elapsed, timezone, and clock are single-target routes - credentials are extracted in Authorization, X-API-Key, then api_key query order; conflicting values are rejected - the first server is the default API host. The second server is the RapidAPI gateway and can be selected or overridden by SDK configuration - `sign` is available on supported JSON routes and is not supported on `/v1/time/clock`
|
|
5
5
|
|
|
6
6
|
The version of the OpenAPI document: 1.0.0
|
|
7
7
|
|
|
@@ -14,8 +14,8 @@ require 'date'
|
|
|
14
14
|
require 'time'
|
|
15
15
|
|
|
16
16
|
module TimeLogic::Api
|
|
17
|
-
#
|
|
18
|
-
class
|
|
17
|
+
# Timezone lookup result. It is the time payload for the resolved target plus `offset` (minutes east of UTC) and `dst`. Every selector returns this one shape. `tz`, `ip`, `lat` + `lon` and `auto_tz` lookups resolve a named zone, so `timezone` is set and `matching_zones` is absent. `offset` lookups return `timezone=null` and add `matching_zones`, the geographic zones whose current offset equals the requested one.
|
|
18
|
+
class TimezoneResponse
|
|
19
19
|
attr_accessor :unix
|
|
20
20
|
|
|
21
21
|
attr_accessor :unix_ms
|
|
@@ -28,6 +28,7 @@ module TimeLogic::Api
|
|
|
28
28
|
|
|
29
29
|
attr_accessor :human
|
|
30
30
|
|
|
31
|
+
# Day of the week counted from Sunday (1 = Sunday, 2 = Monday ... 7 = Saturday).
|
|
31
32
|
attr_accessor :day_number
|
|
32
33
|
|
|
33
34
|
attr_accessor :day_short
|
|
@@ -38,10 +39,16 @@ module TimeLogic::Api
|
|
|
38
39
|
|
|
39
40
|
attr_accessor :formatted
|
|
40
41
|
|
|
42
|
+
# UTC offset of the resolved target in minutes, for example `-240` for UTC-04:00.
|
|
41
43
|
attr_accessor :offset
|
|
42
44
|
|
|
45
|
+
# Whether daylight saving time is in effect for the resolved target. Always `false` for `offset` lookups.
|
|
43
46
|
attr_accessor :dst
|
|
44
47
|
|
|
48
|
+
# Exact UTC offset in seconds. Present only when the resolved offset has a seconds part (historical local mean time); no zone has one at the current instant, so lookups today do not include it.
|
|
49
|
+
attr_accessor :offset_seconds
|
|
50
|
+
|
|
51
|
+
# Present only for `offset=` lookups. The geographic zones whose current offset equals the requested one. `UTC` and `Etc/*` zones are intentionally excluded; use `tz=UTC` for UTC.
|
|
45
52
|
attr_accessor :matching_zones
|
|
46
53
|
|
|
47
54
|
# Attribute mapping from ruby-style variable name to JSON key.
|
|
@@ -60,6 +67,7 @@ module TimeLogic::Api
|
|
|
60
67
|
:'formatted' => :'formatted',
|
|
61
68
|
:'offset' => :'offset',
|
|
62
69
|
:'dst' => :'dst',
|
|
70
|
+
:'offset_seconds' => :'offset_seconds',
|
|
63
71
|
:'matching_zones' => :'matching_zones'
|
|
64
72
|
}
|
|
65
73
|
end
|
|
@@ -85,6 +93,7 @@ module TimeLogic::Api
|
|
|
85
93
|
:'formatted' => :'String',
|
|
86
94
|
:'offset' => :'Integer',
|
|
87
95
|
:'dst' => :'Boolean',
|
|
96
|
+
:'offset_seconds' => :'Integer',
|
|
88
97
|
:'matching_zones' => :'Array<TimezoneMatch>'
|
|
89
98
|
}
|
|
90
99
|
end
|
|
@@ -100,7 +109,7 @@ module TimeLogic::Api
|
|
|
100
109
|
# List of class defined in allOf (OpenAPI v3)
|
|
101
110
|
def self.openapi_all_of
|
|
102
111
|
[
|
|
103
|
-
:'
|
|
112
|
+
:'TimePayload'
|
|
104
113
|
]
|
|
105
114
|
end
|
|
106
115
|
|
|
@@ -108,13 +117,13 @@ module TimeLogic::Api
|
|
|
108
117
|
# @param [Hash] attributes Model attributes in the form of hash
|
|
109
118
|
def initialize(attributes = {})
|
|
110
119
|
if (!attributes.is_a?(Hash))
|
|
111
|
-
fail ArgumentError, "The input argument (attributes) must be a hash in `TimeLogic::Api::
|
|
120
|
+
fail ArgumentError, "The input argument (attributes) must be a hash in `TimeLogic::Api::TimezoneResponse` initialize method"
|
|
112
121
|
end
|
|
113
122
|
|
|
114
123
|
# check to see if the attribute exists and convert string to symbol for hash key
|
|
115
124
|
attributes = attributes.each_with_object({}) { |(k, v), h|
|
|
116
125
|
if (!self.class.attribute_map.key?(k.to_sym))
|
|
117
|
-
fail ArgumentError, "`#{k}` is not a valid attribute in `TimeLogic::Api::
|
|
126
|
+
fail ArgumentError, "`#{k}` is not a valid attribute in `TimeLogic::Api::TimezoneResponse`. Please check the name to make sure it's valid. List of attributes: " + self.class.attribute_map.keys.inspect
|
|
118
127
|
end
|
|
119
128
|
h[k.to_sym] = v
|
|
120
129
|
}
|
|
@@ -195,12 +204,14 @@ module TimeLogic::Api
|
|
|
195
204
|
self.dst = nil
|
|
196
205
|
end
|
|
197
206
|
|
|
207
|
+
if attributes.key?(:'offset_seconds')
|
|
208
|
+
self.offset_seconds = attributes[:'offset_seconds']
|
|
209
|
+
end
|
|
210
|
+
|
|
198
211
|
if attributes.key?(:'matching_zones')
|
|
199
212
|
if (value = attributes[:'matching_zones']).is_a?(Array)
|
|
200
213
|
self.matching_zones = value
|
|
201
214
|
end
|
|
202
|
-
else
|
|
203
|
-
self.matching_zones = nil
|
|
204
215
|
end
|
|
205
216
|
end
|
|
206
217
|
|
|
@@ -257,10 +268,6 @@ module TimeLogic::Api
|
|
|
257
268
|
invalid_properties.push('invalid value for "dst", dst cannot be nil.')
|
|
258
269
|
end
|
|
259
270
|
|
|
260
|
-
if @matching_zones.nil?
|
|
261
|
-
invalid_properties.push('invalid value for "matching_zones", matching_zones cannot be nil.')
|
|
262
|
-
end
|
|
263
|
-
|
|
264
271
|
invalid_properties
|
|
265
272
|
end
|
|
266
273
|
|
|
@@ -280,7 +287,6 @@ module TimeLogic::Api
|
|
|
280
287
|
return false if @day_full.nil?
|
|
281
288
|
return false if @offset.nil?
|
|
282
289
|
return false if @dst.nil?
|
|
283
|
-
return false if @matching_zones.nil?
|
|
284
290
|
true
|
|
285
291
|
end
|
|
286
292
|
|
|
@@ -320,6 +326,7 @@ module TimeLogic::Api
|
|
|
320
326
|
formatted == o.formatted &&
|
|
321
327
|
offset == o.offset &&
|
|
322
328
|
dst == o.dst &&
|
|
329
|
+
offset_seconds == o.offset_seconds &&
|
|
323
330
|
matching_zones == o.matching_zones
|
|
324
331
|
end
|
|
325
332
|
|
|
@@ -332,7 +339,7 @@ module TimeLogic::Api
|
|
|
332
339
|
# Calculates hash code according to all attributes.
|
|
333
340
|
# @return [Integer] Hash code
|
|
334
341
|
def hash
|
|
335
|
-
[unix, unix_ms, utc, iso_local, rfc2822, human, day_number, day_short, day_full, timezone, formatted, offset, dst, matching_zones].hash
|
|
342
|
+
[unix, unix_ms, utc, iso_local, rfc2822, human, day_number, day_short, day_full, timezone, formatted, offset, dst, offset_seconds, matching_zones].hash
|
|
336
343
|
end
|
|
337
344
|
|
|
338
345
|
# Builds the object from hash
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# WorldTimeAPI-compatible client for the TimeLogic API /api/* routes.
|
|
4
|
+
#
|
|
5
|
+
# Contract: openapi/openapi-worldtimeapi.yaml. The routes answer the same paths, field
|
|
6
|
+
# names and plain-text variants as worldtimeapi.org; a TimeLogic API key is required and
|
|
7
|
+
# is sent as the X-API-Key header. This module uses Ruby's standard library only and does
|
|
8
|
+
# not use or change the generated /v1 ApiClient, Configuration or TransportConfiguration.
|
|
9
|
+
#
|
|
10
|
+
# client = TimeLogic::Api::WorldTimeApi::Client.new(api_key: ENV.fetch('TIMELOGIC_API_KEY'))
|
|
11
|
+
# now = client.get_timezone('Europe/London')
|
|
12
|
+
# puts now.datetime
|
|
13
|
+
|
|
14
|
+
require 'json'
|
|
15
|
+
require 'net/http'
|
|
16
|
+
require 'uri'
|
|
17
|
+
|
|
18
|
+
module TimeLogic
|
|
19
|
+
module Api
|
|
20
|
+
module WorldTimeApi
|
|
21
|
+
DEFAULT_BASE_URL = 'https://api.timelogicapi.com'
|
|
22
|
+
|
|
23
|
+
FIELDS = %i[
|
|
24
|
+
abbreviation client_ip datetime day_of_week day_of_year dst dst_from dst_offset
|
|
25
|
+
dst_until raw_offset timezone unixtime utc_datetime utc_offset week_number
|
|
26
|
+
].freeze
|
|
27
|
+
|
|
28
|
+
# Time object with the worldtimeapi.org field names and types.
|
|
29
|
+
DateTime = Struct.new(*FIELDS, keyword_init: true) do
|
|
30
|
+
def self.from_hash(hash)
|
|
31
|
+
new(**FIELDS.to_h { |field| [field, hash[field.to_s]] })
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# HTTP answer, including the X-TimeLogic-Signature* headers when signing is enabled.
|
|
36
|
+
RawResponse = Struct.new(:status, :headers, :body, keyword_init: true)
|
|
37
|
+
|
|
38
|
+
# Raised for any non-2xx answer. +error+ is the worldtimeapi.org-style message (for
|
|
39
|
+
# example "unknown location") or the TimeLogic message for authentication and quota errors.
|
|
40
|
+
class Error < StandardError
|
|
41
|
+
attr_reader :status, :error, :code, :body
|
|
42
|
+
|
|
43
|
+
def initialize(status, error, code, body)
|
|
44
|
+
super("WorldTimeAPI-compatible request failed (#{status}): #{error}")
|
|
45
|
+
@status = status
|
|
46
|
+
@error = error
|
|
47
|
+
@code = code
|
|
48
|
+
@body = body
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def unknown_location?
|
|
52
|
+
status == 404 && error == 'unknown location'
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def malformed_ip?
|
|
56
|
+
status == 404 && error == 'malformed ip'
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# The 404 {"error":"unknown location"} answer.
|
|
61
|
+
class UnknownLocationError < Error; end
|
|
62
|
+
|
|
63
|
+
def self.error_from_response(status, body)
|
|
64
|
+
message = body.to_s.strip
|
|
65
|
+
code = nil
|
|
66
|
+
if message.start_with?('Error:')
|
|
67
|
+
message = message.delete_prefix('Error:').strip
|
|
68
|
+
else
|
|
69
|
+
begin
|
|
70
|
+
parsed = JSON.parse(body.to_s)
|
|
71
|
+
if parsed.is_a?(Hash) && parsed.key?('error')
|
|
72
|
+
if parsed['error'].is_a?(String)
|
|
73
|
+
message = parsed['error']
|
|
74
|
+
elsif parsed['error'].is_a?(Hash)
|
|
75
|
+
message = parsed['error']['message'].to_s
|
|
76
|
+
code = parsed['error']['code']&.to_s
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
rescue JSON::ParserError
|
|
80
|
+
# keep the raw body as the message
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
klass = status == 404 && message == 'unknown location' ? UnknownLocationError : Error
|
|
84
|
+
klass.new(status, message, code, body.to_s)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Path for "Europe/London", "America/Argentina/Salta" or a one-word zone such as "UTC".
|
|
88
|
+
def self.zone_path(timezone, text = false)
|
|
89
|
+
segments = timezone.to_s.split('/').reject(&:empty?)
|
|
90
|
+
unless (1..3).cover?(segments.length)
|
|
91
|
+
raise ArgumentError, 'timezone must have one to three segments, for example "Europe/London"'
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
"/api/timezone/#{segments.map { |s| URI.encode_www_form_component(s).gsub('+', '%20') }.join('/')}#{text ? '.txt' : ''}"
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def self.ip_path(ip = nil, text = false)
|
|
98
|
+
base = ip.nil? || ip.to_s.empty? ? '/api/ip' : "/api/ip/#{URI.encode_www_form_component(ip.to_s)}"
|
|
99
|
+
"#{base}#{text ? '.txt' : ''}"
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Client for the WorldTimeAPI-compatible routes.
|
|
103
|
+
class Client
|
|
104
|
+
# transport: optional callable (url, headers) -> RawResponse, used by tests.
|
|
105
|
+
def initialize(api_key:, base_url: DEFAULT_BASE_URL, sign: false, timeout: 30, transport: nil)
|
|
106
|
+
raise ArgumentError, 'api_key is required' if api_key.nil? || api_key.to_s.empty?
|
|
107
|
+
|
|
108
|
+
@api_key = api_key.to_s
|
|
109
|
+
@base_url = base_url.to_s.sub(%r{/+\z}, '')
|
|
110
|
+
@sign = sign
|
|
111
|
+
@timeout = timeout
|
|
112
|
+
@transport = transport
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# GET /api/timezone
|
|
116
|
+
def list_timezones
|
|
117
|
+
get_json('/api/timezone')
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# GET /api/timezone.txt
|
|
121
|
+
def list_timezones_text
|
|
122
|
+
get_text('/api/timezone.txt')
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# GET /api/timezone/{area}
|
|
126
|
+
def list_timezones_in_area(area)
|
|
127
|
+
value = get_json(WorldTimeApi.zone_path(area))
|
|
128
|
+
raise Error.new(200, "#{area} is a timezone, not an area; use get_timezone", nil, JSON.generate(value)) unless value.is_a?(Array)
|
|
129
|
+
|
|
130
|
+
value
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# GET /api/timezone/{area}.txt
|
|
134
|
+
def list_timezones_in_area_text(area)
|
|
135
|
+
get_text(WorldTimeApi.zone_path(area, true))
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# GET /api/timezone/{area}/{location}[/{region}], or a one-word zone such as UTC.
|
|
139
|
+
def get_timezone(timezone)
|
|
140
|
+
DateTime.from_hash(get_json(WorldTimeApi.zone_path(timezone)))
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def get_timezone_text(timezone)
|
|
144
|
+
get_text(WorldTimeApi.zone_path(timezone, true))
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# GET /api/ip (the caller's address) or /api/ip/{ip}.
|
|
148
|
+
def get_ip(ip = nil)
|
|
149
|
+
DateTime.from_hash(get_json(WorldTimeApi.ip_path(ip)))
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def get_ip_text(ip = nil)
|
|
153
|
+
get_text(WorldTimeApi.ip_path(ip, true))
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# GET any /api/* path and return status, headers and body without raising.
|
|
157
|
+
def request_raw(path)
|
|
158
|
+
url = "#{@base_url}#{path}#{@sign ? '?sign=true' : ''}"
|
|
159
|
+
headers = { 'X-API-Key' => @api_key, 'Accept' => path.end_with?('.txt') ? 'text/plain' : 'application/json' }
|
|
160
|
+
return @transport.call(url, headers) if @transport
|
|
161
|
+
|
|
162
|
+
uri = URI.parse(url)
|
|
163
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
164
|
+
http.use_ssl = uri.scheme == 'https'
|
|
165
|
+
http.open_timeout = @timeout
|
|
166
|
+
http.read_timeout = @timeout
|
|
167
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
|
168
|
+
headers.each { |name, value| request[name] = value }
|
|
169
|
+
response = http.request(request)
|
|
170
|
+
RawResponse.new(
|
|
171
|
+
status: response.code.to_i,
|
|
172
|
+
headers: response.each_header.to_h { |name, value| [name.downcase, value] },
|
|
173
|
+
body: response.body.to_s.dup.force_encoding('UTF-8')
|
|
174
|
+
)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
private
|
|
178
|
+
|
|
179
|
+
def get_text(path)
|
|
180
|
+
raw = request_raw(path)
|
|
181
|
+
raise WorldTimeApi.error_from_response(raw.status, raw.body) unless (200..299).cover?(raw.status)
|
|
182
|
+
|
|
183
|
+
raw.body
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def get_json(path)
|
|
187
|
+
JSON.parse(get_text(path))
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
end
|
data/lib/timelogic-api.rb
CHANGED
|
@@ -4,7 +4,7 @@ end
|
|
|
4
4
|
=begin
|
|
5
5
|
#TimeLogic API | A World Time API
|
|
6
6
|
|
|
7
|
-
#
|
|
7
|
+
#Direct API contract for client integrations. It documents authentication, endpoint parameters, response shapes, public signing keys, and signed JSON controls. Authentication: - the API supports `Authorization: Bearer <token>`, `X-API-Key`, and `api_key` query credentials - RapidAPI access uses `X-RapidAPI-Key` and `X-RapidAPI-Host`; the SDKs expose this as a `rapidApi` transport option that accepts only the RapidAPI key Behavioral notes: - all documented operations are `GET` - only one selector family may be used at a time - current and convert support bulk only through one comma-separated `tz`, `ip`, or `offset` selector - bulk selectors accept at most 10 values, and every request URL is limited to 8192 characters - add, diff, calendar, dst, elapsed, timezone, and clock are single-target routes - credentials are extracted in Authorization, X-API-Key, then api_key query order; conflicting values are rejected - the first server is the default API host. The second server is the RapidAPI gateway and can be selected or overridden by SDK configuration - `sign` is available on supported JSON routes and is not supported on `/v1/time/clock`
|
|
8
8
|
|
|
9
9
|
The version of the OpenAPI document: 1.0.0
|
|
10
10
|
|
|
@@ -30,14 +30,12 @@ require 'timelogic-api/models/dst_response'
|
|
|
30
30
|
require 'timelogic-api/models/elapsed_response'
|
|
31
31
|
require 'timelogic-api/models/error_response'
|
|
32
32
|
require 'timelogic-api/models/get_current_time200_response'
|
|
33
|
-
require 'timelogic-api/models/get_timezone200_response'
|
|
34
33
|
require 'timelogic-api/models/jwk_key'
|
|
35
34
|
require 'timelogic-api/models/jwks_response'
|
|
36
35
|
require 'timelogic-api/models/time_payload'
|
|
37
36
|
require 'timelogic-api/models/time_payload_bulk_item'
|
|
38
37
|
require 'timelogic-api/models/timezone_match'
|
|
39
|
-
require 'timelogic-api/models/
|
|
40
|
-
require 'timelogic-api/models/timezone_resolved_response'
|
|
38
|
+
require 'timelogic-api/models/timezone_response'
|
|
41
39
|
require 'timelogic-api/models/time_payload_bulk_response'
|
|
42
40
|
|
|
43
41
|
# APIs
|
|
@@ -61,3 +59,4 @@ module TimeLogic::Api
|
|
|
61
59
|
end
|
|
62
60
|
end
|
|
63
61
|
end
|
|
62
|
+
require 'timelogic-api/world_time_api'
|