Class: CATime::Element

Inherits:
Object
  • Object
show all
Includes:
Comparable
Defined in:
lib/carray/time.rb

Overview

Element-return class: a single time element carries both its int64 count and its resolution, so scalar access (ca[i,j]) round-trips through this rather than a bare Integer.

Constant Summary collapse

EPOCH_JD =

storage + value/unit accessors + initialize are C-implemented in ext/ca_obj_datetime.c (= TypedData_Make_Struct fast path). Methods below are Ruby-side; they call value/unit which are C accessors.

Calendar breakdown is delegated to Ruby Date / Time (the scalar pays one object's cost, unlike the vectorized array accessors), but exactly: a :M / :Y value decodes through Date#next_month / #next_year (NOT the 30.5-day UNIT_TO_SECONDS approximation, which drifts), and a fixed-unit value through an exact Rational-second Time.at. All UTC.

2440588

Instance Method Summary collapse

Instance Method Details

#+(td) ⇒ CATime::Element

Returns this instant advanced by a CATimedelta::Element. The unit promotes to the finer of the two (numpy-style: :D + :h -> :h). Only a duration in the SAME group (both calendar or both fixed) is accepted -- a cross-group step (a :s time + a :M duration) is calendar arithmetic; use to_date + Date#next_month / #next_year for that.

Parameters:

Returns:

Raises:

  • (TypeError, ArgumentError)

    on a non-timedelta / cross-group operand.



420
421
422
# File 'lib/carray/time.rb', line 420

def +(td)
  _combine(td, 1)
end

#-(other) ⇒ CATime::Element, CATimedelta::Element

Subtracting a CATimedelta::Element yields a CATime::Element (same rule as +); subtracting another CATime::Element yields the elapsed duration as a CATimedelta::Element, in the diff_unit of the two (same group -> finer unit; cross-group -> the fixed unit).



431
432
433
434
435
436
437
438
439
440
441
# File 'lib/carray/time.rb', line 431

def -(other)
  case other
  when Element
    u = CATimeUnitAlgebra.diff_unit(unit, other.unit)
    CATimedelta::Element.new(_instant_in(u) - other.send(:_instant_in, u), u)
  when CATimedelta::Element
    _combine(other, -1)
  else
    raise TypeError, "CATime::Element - #{other.class} is not allowed"
  end
end

#<=>(other) ⇒ Object

Three-way compare by INSTANT, reconciling a different unit (both are brought to a common unit both reach exactly, via diff_unit), so two datetimes are always ordered regardless of unit. Returns nil for a non-time operand (Time / DateTime are accepted); per the Comparable contract that makes == false and < raise, so no explicit == is defined (Comparable derives it: same instant -> equal, even cross-unit).



385
386
387
388
389
390
391
392
393
394
395
396
397
# File 'lib/carray/time.rb', line 385

def <=>(other)
  case other
  when Element
    u = CATimeUnitAlgebra.diff_unit(unit, other.unit)
    _instant_in(u) <=> other._instant_in(u)
  when Time
    to_time <=> other.getutc
  when (defined?(DateTime) ? DateTime : nil)
    to_time <=> other.to_time.getutc
  end
rescue ArgumentError
  nil
end

#eql?(other) ⇒ Boolean

Hash-key identity is unit-strict (mirrors Ruby: 1 == 1.0 but not 1.eql?(1.0)), so a :s and a :ms scalar at the same instant compare == yet key a Hash separately.

Returns:

  • (Boolean)


402
403
404
# File 'lib/carray/time.rb', line 402

def eql?(other)
  other.is_a?(Element) && other.unit == unit && other.value == value
end

#hashInteger

Returns a hash consistent with #eql? (unit-strict).

Returns:

  • (Integer)

    a hash consistent with #eql? (unit-strict).



407
408
409
# File 'lib/carray/time.rb', line 407

def hash
  [value, unit].hash
end

#inspectString

Returns the instant plus its storage unit.

Returns:

  • (String)

    the instant plus its storage unit.



374
375
376
377
# File 'lib/carray/time.rb', line 374

def inspect
  tag = unit.count == 1 ? "#{value}#{unit.base}" : "#{value} @ #{unit}"
  "#<CATime::Element #{to_s} (#{tag})>"
end

#to_dateDate

Returns the date this scalar denotes (UTC). A sub-day unit is floored to its day.

Returns:

  • (Date)

    the date this scalar denotes (UTC). A sub-day unit is floored to its day.



344
345
346
347
348
349
350
351
352
353
# File 'lib/carray/time.rb', line 344

def to_date
  require 'date'
  case unit.base
  when :Y then _epoch_date.next_year(value * unit.count)
  when :M then _epoch_date.next_month(value * unit.count)
  when :W then Date.jd(EPOCH_JD + value * unit.count * 7, Date::GREGORIAN)
  when :D then Date.jd(EPOCH_JD + value * unit.count, Date::GREGORIAN)
  else         Date.jd(EPOCH_JD + _floor_days, Date::GREGORIAN)  # sub-day: floor to day
  end
end

#to_datetimeDateTime

Returns the instant this scalar denotes (UTC).

Returns:

  • (DateTime)

    the instant this scalar denotes (UTC).



356
357
358
# File 'lib/carray/time.rb', line 356

def to_datetime
  to_time.to_datetime
end

#to_sString

Unit-aware string: coarse units print at their own granularity so the (value, unit) pair stays recoverable (a :M scalar is "2024-03", not "2024-03-01T00:00:00Z", which is indistinguishable from a :D).

Returns:

  • (String)


364
365
366
367
368
369
370
371
# File 'lib/carray/time.rb', line 364

def to_s
  case unit.base
  when :Y      then format("%04d", to_date.year)
  when :M      then to_date.strftime("%Y-%m")
  when :W, :D  then to_date.strftime("%Y-%m-%d")
  else              to_time.iso8601(_precision_digits)  # :h .. :as (time shown)
  end
end

#to_timeTime

Returns the instant this scalar denotes (UTC). For a calendar unit this is the first instant (midnight of day 1) of the granule.

Returns:

  • (Time)

    the instant this scalar denotes (UTC). For a calendar unit this is the first instant (midnight of day 1) of the granule.



331
332
333
334
335
336
337
338
339
340
# File 'lib/carray/time.rb', line 331

def to_time
  require 'time'
  require 'date'
  case unit.base
  when :Y then d = _epoch_date.next_year(value * unit.count);  Time.utc(d.year, d.month, d.day)
  when :M then d = _epoch_date.next_month(value * unit.count); Time.utc(d.year, d.month, d.day)
  else
    Time.at(Rational(value) * unit.tick_ratio, in: 'UTC')  # exact seconds
  end
end