iers 0.1.0 → 0.2.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/CHANGELOG.md +35 -0
- data/README.md +44 -2
- data/Rakefile +28 -0
- data/data/finals2000A.all +926 -800
- data/lib/iers/data.rb +17 -7
- data/lib/iers/data_status.rb +1 -1
- data/lib/iers/leap_second.rb +32 -5
- data/lib/iers/parsers/finals.rb +1 -1
- data/lib/iers/parsers/leap_second.rb +54 -4
- data/lib/iers/tai_utc_drift.rb +144 -0
- data/lib/iers/update_result.rb +1 -1
- data/lib/iers/version.rb +1 -1
- data/lib/iers.rb +1 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4132b4709810d88306f0ea6bde33b1664d1fdbfeef985e0191cba65c98c01f8a
|
|
4
|
+
data.tar.gz: 5e3bef64e668f1320bc9c3876e571bf4bb452ea2df52cd09539303bafbf03ea0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c2bd5f8b1d3a088bc9aa8d822013a9c04570cea94c6036f080eb4d34d8ad53ac0346e6547092f5ce95fe61f95df6de32006e59371894e3b77768565be15354a1
|
|
7
|
+
data.tar.gz: 8b32049edecc0955026664f02cbf89a1af9d518050374538cbf1b1c3b08d572509b971d522a1d368490d6d07bcbd90bb807bd9fd5c4223d074431a60583244f5
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.0 - 2026-07-25
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- `LeapSecond.expires_on`, `LeapSecond.expired?` and
|
|
8
|
+
`LeapSecond.updated_through` expose the expiry date and IERS bulletin that
|
|
9
|
+
`Leap_Second.dat` states in its header. Both were previously discarded with
|
|
10
|
+
the rest of the comment lines. Unlike `Data.status.cache_age`, which measures
|
|
11
|
+
when a file was downloaded, these describe how long the data itself stays
|
|
12
|
+
authoritative.
|
|
13
|
+
- `LeapSecond.at` now answers 1961-01-01 through 1972-01-01, the era when UTC
|
|
14
|
+
was steered by rate adjustments rather than whole leap seconds. It returns
|
|
15
|
+
those values as exact `Rational`s. The coefficients come from the USNO
|
|
16
|
+
`tai-utc.dat` file and are bundled in source, since they are fixed. The
|
|
17
|
+
change is additive: the pre-1972 range previously raised, so no successful
|
|
18
|
+
call returns anything different. `TAI.utc_to_tai` and `TAI.tai_to_utc` gain
|
|
19
|
+
the same range for free.
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- `Parsers::LeapSecond.parse` returns a `Table` of `entries` and `metadata`
|
|
24
|
+
instead of an array of entries. `Parsers` is internal; the public API is
|
|
25
|
+
unaffected.
|
|
26
|
+
- `Parsers::LeapSecond.parse` no longer raises `Encoding::CompatibilityError`
|
|
27
|
+
on a file containing invalid UTF-8. Header metadata is read on a best-effort
|
|
28
|
+
basis and an unreadable data row raises `ParseError` as before.
|
|
29
|
+
|
|
30
|
+
## 0.1.1 - 2026-06-27
|
|
31
|
+
|
|
32
|
+
### Changed
|
|
33
|
+
|
|
34
|
+
- Refreshed the bundled `finals2000A.all` snapshot from IERS. Final values now
|
|
35
|
+
extend through 2026-06-25 (previously 2026-02-19) and predictions through
|
|
36
|
+
2027-08-22.
|
|
37
|
+
|
|
3
38
|
## 0.1.0 - 2026-02-27
|
|
4
39
|
|
|
5
40
|
Initial public release.
|
data/README.md
CHANGED
|
@@ -242,14 +242,28 @@ entries = IERS::EOP.between(
|
|
|
242
242
|
Look up TAI−UTC at a given date:
|
|
243
243
|
|
|
244
244
|
```ruby
|
|
245
|
-
IERS::LeapSecond.at(Time.utc(2017, 1, 1)) # => 37
|
|
245
|
+
IERS::LeapSecond.at(Time.utc(2017, 1, 1)) # => 37 (seconds)
|
|
246
246
|
```
|
|
247
247
|
|
|
248
|
+
`at` covers 1961-01-01 onward. From 1972 it returns a whole number of seconds
|
|
249
|
+
as an `Integer`. Between 1961 and 1972, UTC was steered by small rate
|
|
250
|
+
adjustments rather than whole leap seconds, so TAI−UTC was a fraction of a
|
|
251
|
+
second that changed daily. `at` returns those values as exact `Rational`s:
|
|
252
|
+
|
|
253
|
+
```ruby
|
|
254
|
+
IERS::LeapSecond.at(mjd: 38_900) # => (1910137/500000)
|
|
255
|
+
IERS::LeapSecond.at(mjd: 38_900).to_f # => 3.820274 (seconds, 1965-05-20)
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
The coefficients for that era are fixed and will never change, so they are
|
|
259
|
+
bundled in the gem rather than downloaded. Anything before 1961-01-01 has no
|
|
260
|
+
published UTC and raises `OutOfRangeError`.
|
|
261
|
+
|
|
248
262
|
List all leap seconds:
|
|
249
263
|
|
|
250
264
|
```ruby
|
|
251
265
|
IERS::LeapSecond.all
|
|
252
|
-
# => [#<data IERS::LeapSecond::Entry effective_date=#<Date: 1972-01-01>, tai_utc=10
|
|
266
|
+
# => [#<data IERS::LeapSecond::Entry effective_date=#<Date: 1972-01-01>, tai_utc=10>, ...]
|
|
253
267
|
```
|
|
254
268
|
|
|
255
269
|
Check for a future scheduled leap second:
|
|
@@ -258,6 +272,27 @@ Check for a future scheduled leap second:
|
|
|
258
272
|
IERS::LeapSecond.next_scheduled # => #<data IERS::LeapSecond::Entry ...> or nil
|
|
259
273
|
```
|
|
260
274
|
|
|
275
|
+
#### Leap second file validity
|
|
276
|
+
|
|
277
|
+
`Leap_Second.dat` states when it stops being authoritative and which IERS
|
|
278
|
+
bulletin it was updated through. Both are read from the file that is actually
|
|
279
|
+
loaded, so a custom or cached file reports its own header:
|
|
280
|
+
|
|
281
|
+
```ruby
|
|
282
|
+
IERS::LeapSecond.expires_on # => #<Date: 2026-12-28> or nil
|
|
283
|
+
IERS::LeapSecond.expired? # => false
|
|
284
|
+
IERS::LeapSecond.updated_through # => "IERS Bulletin 71 issued in January 2026"
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
The stated date is itself still valid, so a file expiring on 28 December 2026
|
|
288
|
+
is expired on the 29th. An expired file is not wrong: it means the IERS has
|
|
289
|
+
published a newer one and a leap second may have been announced since.
|
|
290
|
+
|
|
291
|
+
This is unrelated to `Data.status.cache_age`, which measures when the file was
|
|
292
|
+
downloaded rather than how long it stays valid. A bundled snapshot can be a year
|
|
293
|
+
old and still valid while a file downloaded this morning can be a week from
|
|
294
|
+
expiry.
|
|
295
|
+
|
|
261
296
|
### TAI
|
|
262
297
|
|
|
263
298
|
Convert between UTC and TAI time scales:
|
|
@@ -295,6 +330,10 @@ end
|
|
|
295
330
|
|
|
296
331
|
Without `coverage_days_ahead`, the check ensures predictions cover today.
|
|
297
332
|
|
|
333
|
+
`ensure_fresh!` is about prediction coverage in `finals2000A.all` only. Leap
|
|
334
|
+
second file validity is a separate question, answered by
|
|
335
|
+
`IERS::LeapSecond.expired?`.
|
|
336
|
+
|
|
298
337
|
### Data status and cache management
|
|
299
338
|
|
|
300
339
|
```ruby
|
|
@@ -358,6 +397,9 @@ release a new version, update the version number in `version.rb`, and then run
|
|
|
358
397
|
`bundle exec rake release`, which will create a git tag for the version, push
|
|
359
398
|
git commits and the created tag, and push the `.gem` file to [rubygems.org].
|
|
360
399
|
|
|
400
|
+
To refresh the bundled snapshot in `data/`, run `bundle exec rake data:update`.
|
|
401
|
+
A monthly workflow runs this and opens a pull request automatically.
|
|
402
|
+
|
|
361
403
|
## License
|
|
362
404
|
|
|
363
405
|
The gem is available as open source under the terms of the [MIT License].
|
data/Rakefile
CHANGED
|
@@ -10,3 +10,31 @@ require "rubocop/rake_task"
|
|
|
10
10
|
RuboCop::RakeTask.new
|
|
11
11
|
|
|
12
12
|
task default: %i[test rubocop]
|
|
13
|
+
|
|
14
|
+
namespace :data do
|
|
15
|
+
desc "Download the latest IERS data"
|
|
16
|
+
task :update do
|
|
17
|
+
require "iers"
|
|
18
|
+
|
|
19
|
+
data_dir = File.expand_path("data", __dir__)
|
|
20
|
+
IERS.configure do |config|
|
|
21
|
+
config.finals_path = File.join(data_dir, "finals2000A.all")
|
|
22
|
+
config.leap_second_path = File.join(data_dir, "Leap_Second.dat")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
result = IERS::Data.update!
|
|
26
|
+
|
|
27
|
+
unless result.success?
|
|
28
|
+
result.errors.each do |source, error|
|
|
29
|
+
warn "#{source}: #{error.class} - #{error.message}"
|
|
30
|
+
end
|
|
31
|
+
abort "IERS data update failed"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
IERS::Data.clear_loaded!
|
|
35
|
+
IERS::Data.ensure_fresh!(coverage_days_ahead: 90)
|
|
36
|
+
IERS::Data.leap_second_entries
|
|
37
|
+
|
|
38
|
+
puts "Updated: #{result.updated_files.join(", ")}"
|
|
39
|
+
end
|
|
40
|
+
end
|