Class: Horologium::Instant
- Inherits:
-
Object
- Object
- Horologium::Instant
- Includes:
- PreciseValue
- Defined in:
- lib/horologium/instant.rb,
sig/horologium/instant.rbs
Overview
A single point on the timeline, independent of any scale. It is stored as a TAI Julian Date, in days, at a fixed precision.
An Instant is built from a Julian Date read in a scale, and can be read back in any scale the library knows: a scale is what turns a number into a point, and the point itself has none.
An Instant is frozen. Its precision is set when it is built, from the
precision in effect unless you pass one. At :standard the Julian Date is
a Numeric::TwoPartFloat, at :exact a Numeric::Exact.
You can add or subtract a Duration, and subtract another Instant to get
the Duration between them. Adding two instants raises DimensionalError.
Mixing a :standard and an :exact operand gives an :exact result.
Instance Attribute Summary
Attributes included from PreciseValue
Class Method Summary collapse
-
.from_civil(year, month = nil, day = nil, hour = 0, minute = 0, second = 0, scale:, precision: Horologium.current_precision) ⇒ Horologium::Instant
Builds an instant from a calendar date and a time of day read in a scale.
-
.from_iso8601(value, scale:, precision: Horologium.current_precision) ⇒ Horologium::Instant
Builds an instant from an ISO 8601 date and time read in a scale.
-
.from_julian_date(value, low = nil, scale:, precision: Horologium.current_precision) ⇒ Horologium::Instant
Builds an instant from a Julian Date read in a scale.
-
.from_modified_julian_date(value, low = nil, scale:, precision: Horologium.current_precision) ⇒ Horologium::Instant
Builds an instant from a Modified Julian Date read in a scale.
-
.from_tai(year, month = nil, day = nil, hour = 0, minute = 0, second = 0, precision: Horologium.current_precision) ⇒ Horologium::Instant
Builds an instant from a TAI calendar date and time.
-
.from_tdb(year, month = nil, day = nil, hour = 0, minute = 0, second = 0, precision: Horologium.current_precision) ⇒ Horologium::Instant
Builds an instant from a TDB calendar date and time.
-
.from_tt(year, month = nil, day = nil, hour = 0, minute = 0, second = 0, precision: Horologium.current_precision) ⇒ Horologium::Instant
Builds an instant from a TT calendar date and time.
-
.from_utc(year, month = nil, day = nil, hour = 0, minute = 0, second = 0, precision: Horologium.current_precision) ⇒ Horologium::Instant
Builds an instant from a UTC calendar date and time.
Instance Method Summary collapse
-
#+(duration) ⇒ Horologium::Instant
Adds a duration and returns a later instant.
-
#-(other) ⇒ Horologium::Instant, Horologium::Duration
Subtracts a duration to get an earlier instant, or another instant to get the Duration between them.
-
#as(representation, scale:, as: :float) ⇒ Object
The instant in a representation, read in a scale.
-
#equal_within?(other, tolerance) ⇒ Boolean
Whether two instants fall within a tolerance of each other.
-
#inspect ⇒ String
The stored TAI Julian Date, so inspecting an instant needs no scale and no date the calendar conversion has to reach.
-
#seconds_to_days(duration, precision) ⇒ Horologium::Numeric::TwoPartFloat, Horologium::Numeric::Exact
The duration's seconds counted in days, at the given precision.
-
#to(scale) ⇒ Horologium::ScaleReading
The instant read in a time scale.
Methods included from PreciseValue
#<=>, #eql?, #hash, #initialize
Class Method Details
.from_civil(civil, scale:, precision:) ⇒ Instant .from_civil(year, month, day, hour, minute, second, scale:, precision:) ⇒ Instant
Builds an instant from a calendar date and a time of day read in a scale. Nothing is lost: the date becomes a whole number of days and the time of day an exact fraction of one, so this is an exact way to build an instant where a Julian Date given as a single Float is not.
The second may carry a fraction under it. Give that fraction as a Rational to say it exactly; a Float second says only what a Float holds, which at this magnitude is far more than a clock reads.
A Representations::CivilTime may be passed on its own, which is what
a reading taken with as(:civil) returns, so a civil time reads back
into the instant it came from.
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/horologium/instant.rb', line 148 def from_civil( year, month = nil, day = nil, hour = 0, minute = 0, second = 0, scale:, precision: Horologium.current_precision ) from_representation( Representations::Civil, civil_time(year, month, day, hour, minute, second), nil, scale, precision ) end |
.from_iso8601(value, scale:, precision: Horologium.current_precision) ⇒ Horologium::Instant
Builds an instant from an ISO 8601 date and time read in a scale. The
string is read in the strict subset Representations::Iso8601 parses:
a calendar date, an optional time of day after a T down to a fraction
of a second, and an optional Z or numeric offset. A date on its own
is midnight in the scale.
The string names no scale of its own, so scale says which one it is
read in. A numeric offset is subtracted as plain arithmetic, not a time
zone: it consults no zone data, and Z is a zero offset.
320 321 322 323 324 325 326 327 328 |
# File 'lib/horologium/instant.rb', line 320 def from_iso8601(value, scale:, precision: Horologium.current_precision) from_representation( Representations::Iso8601, value, nil, scale, precision ) end |
.from_julian_date(value, low = nil, scale:, precision: Horologium.current_precision) ⇒ Horologium::Instant
Builds an instant from a Julian Date read in a scale. The Julian Date is read back in TAI, the scale an instant is stored in, so a point given in one scale can be read in another.
The lossless shapes come first: a String and a Rational say the Julian Date exactly, and a high and a low Float say it to about twice what one Float holds. A single Float is the lossy one, worth about 40 microseconds at a modern date, and the loss is already in the literal by the time the library sees it. See Representations::JulianDate.parse.
65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/horologium/instant.rb', line 65 def from_julian_date( value, low = nil, scale:, precision: Horologium.current_precision ) from_representation( Representations::JulianDate, value, low, scale, precision ) end |
.from_modified_julian_date(value, low = nil, scale:, precision: Horologium.current_precision) ⇒ Horologium::Instant
Builds an instant from a Modified Julian Date read in a scale. It is the Julian Date counted from a later origin, and it is given in the same shapes as from_julian_date.
96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/horologium/instant.rb', line 96 def from_modified_julian_date( value, low = nil, scale:, precision: Horologium.current_precision ) from_representation( Representations::ModifiedJulianDate, value, low, scale, precision ) end |
.from_tai(civil, precision:) ⇒ Instant .from_tai(year, month, day, hour, minute, second, precision:) ⇒ Instant
Builds an instant from a TAI calendar date and time. It is from_civil read in TAI, the continuous scale the library stores instants in.
The fields are from_civil's, and a Representations::CivilTime may be passed on its own.
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
# File 'lib/horologium/instant.rb', line 179 def from_tai( year, month = nil, day = nil, hour = 0, minute = 0, second = 0, precision: Horologium.current_precision ) from_representation( Representations::Civil, civil_time(year, month, day, hour, minute, second), nil, :tai, precision ) end |
.from_tdb(civil, precision:) ⇒ Instant .from_tdb(year, month, day, hour, minute, second, precision:) ⇒ Instant
Builds an instant from a TDB calendar date and time. It is from_civil read in TDB, the scale the planetary ephemerides are written in.
The fields are from_civil's, and a Representations::CivilTime may be passed on its own.
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 |
# File 'lib/horologium/instant.rb', line 239 def from_tdb( year, month = nil, day = nil, hour = 0, minute = 0, second = 0, precision: Horologium.current_precision ) from_representation( Representations::Civil, civil_time(year, month, day, hour, minute, second), nil, :tdb, precision ) end |
.from_tt(civil, precision:) ⇒ Instant .from_tt(year, month, day, hour, minute, second, precision:) ⇒ Instant
Builds an instant from a TT calendar date and time. It is from_civil read in TT, the scale the theories of the solar system motion are written in.
The fields are from_civil's, and a Representations::CivilTime may be passed on its own.
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
# File 'lib/horologium/instant.rb', line 209 def from_tt( year, month = nil, day = nil, hour = 0, minute = 0, second = 0, precision: Horologium.current_precision ) from_representation( Representations::Civil, civil_time(year, month, day, hour, minute, second), nil, :tt, precision ) end |
.from_utc(civil, precision:) ⇒ Instant .from_utc(year, month, day, hour, minute, second, precision:) ⇒ Instant
Builds an instant from a UTC calendar date and time. It is from_civil read in UTC, the scale of civil clocks, so a leap second is a legal reading: the second may be 60 on a day that holds one.
UTC runs from 1961-01-01, whole leap seconds from 1972 and the earlier rate-adjustment drift before that. An earlier date raises OutOfRangeError and names the continuous constructors, which reach any date.
The fields are from_civil's.
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 |
# File 'lib/horologium/instant.rb', line 276 def from_utc( year, month = nil, day = nil, hour = 0, minute = 0, second = 0, precision: Horologium.current_precision ) from_representation( Representations::Civil, civil_time(year, month, day, hour, minute, second), nil, :utc, precision ) end |
Instance Method Details
#+(duration) ⇒ Horologium::Instant
Adds a duration and returns a later instant.
386 387 388 389 390 391 392 393 394 395 396 |
# File 'lib/horologium/instant.rb', line 386 def +(duration) # rubocop:disable Naming/BinaryOperatorParameterName unless duration.is_a?(Duration) raise DimensionalError, "cannot add a #{duration.class} to an Instant; " \ "only a Duration shifts an Instant" end precision = Numeric::Precision.resolve(self.precision, duration.precision) days = seconds_to_days(duration, precision) self.class.new(Numeric::Precision.add(value, days), precision) end |
#-(arg0) ⇒ Instant #-(arg0) ⇒ Duration
Subtracts a duration to get an earlier instant, or another instant to get the Duration between them.
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 |
# File 'lib/horologium/instant.rb', line 408 def -(other) case other when Duration precision = Numeric::Precision.resolve(self.precision, other.precision) days = seconds_to_days(other, precision) self.class.new( Numeric::Precision.subtract(value, days), precision ) when Instant precision = Numeric::Precision.resolve(self.precision, other.precision) gap = Numeric::Precision.subtract(value, other.value) Duration.new(gap * Duration::SECONDS_PER_DAY, precision) else raise DimensionalError, "cannot subtract a #{other.class} from an Instant; " \ "subtract a Duration or another Instant" end end |
#as(representation, scale:, as: :float) ⇒ Object
The instant in a representation, read in a scale. This is the shorthand
for to(scale).as(representation).
461 462 463 |
# File 'lib/horologium/instant.rb', line 461 def as(representation, scale:, as: :float) to(scale).as(representation, as: as) end |
#equal_within?(other, tolerance) ⇒ Boolean
Whether two instants fall within a tolerance of each other. Use this
rather than == in scientific code.
471 472 473 474 475 476 477 478 479 480 481 482 |
# File 'lib/horologium/instant.rb', line 471 def equal_within?(other, tolerance) unless other.is_a?(Instant) raise DimensionalError, "cannot compare an Instant with a #{other.class}" end unless tolerance.is_a?(Duration) raise DimensionalError, "a tolerance must be a Duration, got a #{tolerance.class}" end (self - other).abs <= tolerance end |
#inspect ⇒ String
The stored TAI Julian Date, so inspecting an instant needs no scale and no date the calendar conversion has to reach.
488 489 490 |
# File 'lib/horologium/instant.rb', line 488 def inspect format("#<%s %s TAI JD (%s)>", self.class, value.to_f, precision) end |
#seconds_to_days(duration, precision) ⇒ Horologium::Numeric::TwoPartFloat, Horologium::Numeric::Exact
The duration's seconds counted in days, at the given precision. A Julian Date counts days, so a duration is scaled before it is added.
500 501 502 503 |
# File 'lib/horologium/instant.rb', line 500 def seconds_to_days(duration, precision) Numeric::Precision.coerce(duration.value, to: precision) / Duration::SECONDS_PER_DAY end |
#to(scale) ⇒ Horologium::ScaleReading
The instant read in a time scale. An instant has no scale of its own, so the scale is chosen here. Take the representation from the reading it returns.
439 440 441 442 443 444 445 446 447 448 449 |
# File 'lib/horologium/instant.rb', line 439 def to(scale) time_scale = Horologium.configuration.scale(scale) reading = time_scale.from_reference(value, precision) ScaleReading.new( scale, reading, precision, time_scale.provenance(reading) ) end |