Class: CATime

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

Overview

============================================================================ timestep system (P1/P2 integer path)

Projects an absolute time onto an integer "step index" -- the k-th fixed-width bucket of step counted from origin -- and the inverse / rounding / on-grid operators built on it. All storage-domain int64 and vectorized; the crown jewel is that bucketing, matching, and positional addressing across differently-scaled series all become integer arithmetic.

Integer path covers: fixed-length step on fixed-length storage, and Y/M step on Y/M storage (:M storage already encodes a linear month ordinal, so it floor-divides identically). The calendar path (Y/M step on sub-day storage, via civil-date algebra) is P3 and currently raises.

See devel/PROPOSAL_DATETIME64_STEP_SYSTEM.md.

Defined Under Namespace

Classes: Element, Resolution

Constant Summary collapse

SU_LE_DAY =

Base units that are day-or-finer (a period head is representable exactly; the civil path targets these for a calendar bucket).

%i[D h m s ms us ns ps fs as].freeze

Reductions collapse

Field accessors collapse

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.from_timesteps(k, unit:, origin: nil) ⇒ Element, CATime

Inverse of #timesteps: returns the bucket-head time for timestep k, stored on the unit grid. Use to relabel a group_by(timesteps) result, generate a regular grid, or as a timesteps round-trip oracle. A scalar k returns a Element; a CArray k returns a CATime.

Parameters:

  • k (Integer, CArray)

    timestep / timesteps.

  • unit (String, Symbol, Resolution)

    grid resolution of the result.

  • origin (Time, String, CATime::Element, DateTime, nil) (defaults to: nil)

    grid phase.

Returns:



1938
1939
1940
1941
1942
1943
1944
# File 'lib/carray/time.rb', line 1938

def self.from_timesteps(k, unit:, origin: nil)
  res = Resolution.parse(unit)
  kk  = k.is_a?(CArray) ? k.int64 : CArray.int64(1) { Integer(k) }
  _mul, step_ticks, o = _resolve_grid(res, res, origin)  # step_ticks = 1 (same res)
  raw = o + kk * step_ticks
  k.is_a?(CArray) ? raw.time(unit: res) : Element.new(raw[0], res)
end

.new(*shape, unit: :ns) ⇒ CATime

Allocates a new int64 storage CArray of the given shape and wraps it as a CATime Face with the given unit. The reference epoch is the Unix epoch (1970-01-01 UTC).

Parameters:

  • shape (Array<Integer>)

    shape of the new CATime.

  • unit (Symbol) (defaults to: :ns)

    resolution unit (:Y, :M, :W, :D, :h, :m, :s, :ms, :us, :ns, ...).

Returns:



288
289
290
291
# File 'lib/carray/time.rb', line 288

def self.new(*shape, unit: :ns)
  raw = CArray.int64(*shape)
  wrap(raw, unit: unit)
end

.wrap(raw, unit: :ns) ⇒ CATime

Zero-copy Face wrap of an existing int64 CArray. unit is a Resolution (or a Symbol / String it parses from).

Parameters:

  • raw (CArray)

    int64 storage.

  • unit (Resolution, Symbol, String) (defaults to: :ns)

    tick resolution.

Returns:



299
300
301
# File 'lib/carray/time.rb', line 299

def self.wrap(raw, unit: :ns)
  __wrap__(raw, unit)
end

Instance Method Details

#+(other) ⇒ CATime

Returns self + other for a CATimedelta: the time is the anchor, so the result keeps self's unit and the duration is converted into it (a duration finer than self's unit is truncated to it; a cross-group calendar duration raises). Adding two datetimes is ill-defined.

Parameters:

Returns:

Raises:

  • (TypeError)

    on a non-timedelta operand.



696
697
698
699
700
701
702
703
704
705
# File 'lib/carray/time.rb', line 696

def +(other)
  case other
  when CATimedelta
    (parent + CATimeUnitAlgebra.convert_scale_trunc(other.parent, other.unit, unit)).time(unit: unit)
  when CATime
    raise TypeError, "CATime + CATime is ill-defined"
  else
    raise TypeError, "CATime + #{other.class} is not allowed (use CATimedelta)"
  end
end

#-(other) ⇒ CATime, CATimedelta

Subtracting a CATimedelta yields a CATime at self's unit (the duration is converted into it, truncated when finer); subtracting another CATime yields a CATimedelta at the finer of the two units (cross-group falls to the fixed unit).

Parameters:

Returns:

Raises:

  • (TypeError)

    on an unsupported operand.



715
716
717
718
719
720
721
722
723
724
725
726
727
# File 'lib/carray/time.rb', line 715

def -(other)
  case other
  when CATimedelta
    (parent - CATimeUnitAlgebra.convert_scale_trunc(other.parent, other.unit, unit)).time(unit: unit)
  when CATime
    u = CATimeUnitAlgebra.diff_unit(unit, other.unit)
    a = CATimeUnitAlgebra.convert_instant!(parent, unit, u)
    b = CATimeUnitAlgebra.convert_instant!(other.parent, other.unit, u)
    (a - b).timedelta(unit: u)
  else
    raise TypeError, "CATime - #{other.class} is not allowed"
  end
end

#ajdCArray

Returns the Astronomical Julian Day (float, offset by half a day) for each element.

Returns:



1095
1096
1097
1098
# File 'lib/carray/time.rb', line 1095

def ajd
  require 'date'
  to_time.convert(:double) {|t| t.to_datetime.ajd.to_f}
end

#ceil(unit:, origin: nil) ⇒ CATime

Returns each element raised to its bucket head at or after it (an element already on a boundary maps to itself), as a CATime.

Returns:



1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
# File 'lib/carray/time.rb', line 1879

def ceil(unit:, origin: nil)
  g = _step_grid(unit, origin)
  return _civil(:ceil, g[1], origin) if g[0] == :civil
  su, mul, step_ticks, o = g
  _guard_overflow(su, mul, o, step_ticks, :ceil)
  n  = _num_ticks(mul)
  d  = n - o
  q  = d / step_ticks
  q  = q - (d - q * step_ticks).lt(0)
  fl = o + q * step_ticks
  _head_time(fl + step_ticks * n.ne(fl), mul, su)
end

#dayCArray

Day of the month, 1..31. Every cell is 1 for :Y / :M storage, which does not resolve days.

Returns:



1048
1049
1050
1051
1052
1053
# File 'lib/carray/time.rb', line 1048

def day
  case unit.base
  when :Y, :M then parent * 0 + 1
  else self.class.send(:_civil_from_days, _field_days)[2]
  end
end

#floor(unit:, origin: nil) ⇒ CATime

Returns each element floored to its bucket head (toward the past), as a CATime in the same storage resolution.

Parameters:

  • unit (String, Symbol, Resolution)

    bucket resolution.

  • origin (Time, String, CATime::Element, DateTime, nil) (defaults to: nil)

    grid phase.

Returns:



1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
# File 'lib/carray/time.rb', line 1864

def floor(unit:, origin: nil)
  g = _step_grid(unit, origin)
  return _civil(:floor, g[1], origin) if g[0] == :civil
  su, mul, step_ticks, o = g
  _guard_overflow(su, mul, o, step_ticks, :floor)
  d = _num_ticks(mul) - o
  q = d / step_ticks
  q = q - (d - q * step_ticks).lt(0)
  _head_time(o + q * step_ticks, mul, su)
end

#hourCArray

Hour of the day, 0..23; 0 when the storage unit is coarser than an hour.

Returns:



1057
# File 'lib/carray/time.rb', line 1057

def hour;   _clock_field(:h); end

#is_leapCArray

Returns a boolean CArray flagging elements that fall in a leap year (UTC).

Returns:



1104
1105
1106
1107
# File 'lib/carray/time.rb', line 1104

def is_leap
  y = year
  ((y % 4).eq(0) & (y % 100).ne(0)) | (y % 400).eq(0)
end

#is_righttime(unit:, origin: nil) ⇒ CArray

Returns a boolean CArray flagging elements that land exactly on a bucket head. Use as an assertion before matching to catch off-grid series (a timesteps match is "same bucket", not "same instant").

Parameters:

  • unit (String, Symbol, Resolution)

    bucket resolution.

  • origin (Time, String, CATime::Element, DateTime, nil) (defaults to: nil)

    grid phase.

Returns:



1919
1920
1921
1922
1923
1924
1925
1926
1927
# File 'lib/carray/time.rb', line 1919

def is_righttime(unit:, origin: nil)
  g = _step_grid(unit, origin)
  return _civil(:on, g[1], origin) if g[0] == :civil
  su, mul, step_ticks, o = g
  _guard_overflow(su, mul, o)
  d = _num_ticks(mul) - o
  q = d / step_ticks
  (d - q * step_ticks).eq(0)
end

#jdCArray

Returns the Julian Day Number for each element.

Returns:



1086
1087
1088
1089
# File 'lib/carray/time.rb', line 1086

def jd
  require 'date'
  to_time.convert(:int) {|t| t.to_date.jd}
end

#linear_fetch(addr, axis: nil) ⇒ Element, CATime

Returns the time at the fractional position addr on this array's grid, interpolating between the two bracketing instants. The inverse of linear_section, and the reason for the override: linear_fetch returns a value, so the result is a CATime again, whereas linear_section returns a position and stays a plain index.

The result keeps self's unit -- the array's grid is the output grid, so an instant that lands between two ticks is rounded to the nearest one. Widen the grid first when the interpolation needs finer resolution: t.to_unit(:ms).linear_fetch(addr) interpolates on the millisecond grid. (Unlike #mean / #median, which collapse the axis and therefore have no output grid to preserve, so they refine the resolution instead.)

An out-of-range addr yields UNDEF rather than the NaN that a plain float axis returns -- int64 storage has no NaN to carry a sentinel. A masked addr cell stays UNDEF (the kernel's own rule: an undetermined query gets an undetermined answer).

Parameters:

  • addr (Float, CArray)

    fractional position(s) into self.

  • axis (Integer, nil) (defaults to: nil)

Returns:



957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
# File 'lib/carray/time.rb', line 957

def linear_fetch (addr, **opts)
  r = parent.float64.linear_fetch(addr, **opts)
  case r
  when CArray
    # mask_invalid before the int64 cast: the cast turns a NaN into 0, which
    # would read as the epoch instead of "no answer".
    r.mask_invalid.round.int64.time(unit: unit)
  when Numeric
    # Scalar query.  Out of range -> nil, joining the nil the kernel already
    # returns for a masked scalar query: one "no answer" on this path.
    r.to_f.nan? ? nil : Element.new(r.round, unit)
  else
    r                                   # nil (masked scalar query)
  end
end

#mean(axis: nil, **opts) ⇒ Element, CATime

Returns the centroid time on self's unit (§8), rounded to the nearest tick.

Returns:



780
781
782
# File 'lib/carray/time.rb', line 780

def mean(*args, **opts)
  _reduce_dt(:mean, :time, args, opts)
end

#median(axis: nil, **opts) ⇒ Element, CATime

Returns the median time on self's unit (§8). An odd-count full reduction is an actual element (exact); the even-count / per-axis cases interpolate and round to the nearest tick.

Returns:



789
790
791
# File 'lib/carray/time.rb', line 789

def median(*args, **opts)
  _reduce_dt(:median, :time, args, opts)
end

#minmax(*axes, **opts) ⇒ Array(Element, Element), Array(CATime, CATime)

Returns the earliest and latest time as a [min, max] pair (§8).



755
756
757
758
# File 'lib/carray/time.rb', line 755

def minmax(*args, **opts)
  lo, hi = parent.minmax(*args, **opts)
  [_lift_extremum(lo), _lift_extremum(hi)]
end

#minuteCArray

Minute of the hour, 0..59; 0 when the storage unit is coarser than a minute.

Returns:



1060
# File 'lib/carray/time.rb', line 1060

def minute; _clock_field(:m); end

#monthCArray

Calendar month, 1..12. Every cell is 1 for :Y storage, which does not resolve months.

Returns:



1035
1036
1037
1038
1039
1040
1041
1042
1043
# File 'lib/carray/time.rb', line 1035

def month
  case unit.base
  when :Y then parent * 0 + 1
  when :M
    mo = parent * unit.count + 1970 * 12
    mo - self.class.send(:_floordiv_i, mo, 12) * 12 + 1
  else self.class.send(:_civil_from_days, _field_days)[1]
  end
end

#percentile(*p, axis: nil, **opts) ⇒ Element, ...

Returns the percentile instants on self's unit, in the shapes the plain CArray#percentile uses: one p reduces to a single value (an Element, or a CATime with axis:), two or more p give an Array of those.



799
800
801
# File 'lib/carray/time.rb', line 799

def percentile(*args, **opts)
  _reduce_dt(:percentile, :time, args, opts)
end

#quantile(axis: nil, **opts) ⇒ Array<Element>, Array<CATime>

Returns the five quartile instants [p0, p25, p50, p75, p100] on self's unit (shorthand for percentile(0, 25, 50, 75, 100)).

Returns:



807
808
809
# File 'lib/carray/time.rb', line 807

def quantile(*args, **opts)
  _reduce_dt(:quantile, :time, args, opts)
end

#round(unit:, origin: nil) ⇒ CATime

Returns each element rounded to its nearest bucket head (ties toward the future, matching snap :round), as a CATime. Exact for odd step_ticks (no half-tick loss). For a calendar bucket the nearest head is by absolute tick distance (month lengths vary), ties toward the future.

Returns:



1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
# File 'lib/carray/time.rb', line 1899

def round(unit:, origin: nil)
  g = _step_grid(unit, origin)
  return _civil(:round, g[1], origin) if g[0] == :civil
  su, mul, step_ticks, o = g
  _guard_overflow(su, mul, o, step_ticks, :round)
  d = _num_ticks(mul) - o
  q = d / step_ticks
  q = q - (d - q * step_ticks).lt(0)            # floor bucket
  r = d - q * step_ticks                        # 0 <= r < step_ticks
  q = q + r.ge((step_ticks + 1) / 2)            # ties -> future; no 2*d / 2*r
  _head_time(o + q * step_ticks, mul, su)
end

#scalar_to_storage(surface) ⇒ Integer, Object

Write-direction counterpart of storage_to_scalar (the store hook fired from rb_ca_obj2ptr): brings a surface value object into this Face's int64 storage (count in self's unit since the Unix epoch) so a scalar store round-trips with a fetch. A Element / Time / DateTime is reconciled to self's unit via #to_comparable (same lossless discipline: a cross-group unit or a non-exact finer->coarser cast raises). A bare Integer (the documented .parent raw-storage escape) and a String (parsing is a separate, opposite-direction mechanism) pass through unchanged to the storage cast.

Parameters:

  • surface (Element, Time, DateTime, Integer, String)

Returns:

  • (Integer, Object)

    the storage-domain value, or surface unchanged for a pass-through type.

Raises:

  • (TypeError, ArgumentError)

    on an unreconcilable surface / unit.



917
918
919
920
921
922
923
924
# File 'lib/carray/time.rb', line 917

def scalar_to_storage (surface)
  case surface
  when Integer, String
    surface
  else
    to_comparable(surface).parent[0]
  end
end

#secondCArray

Second of the minute, 0..59; 0 when the storage unit is coarser than a second.

Returns:



1063
# File 'lib/carray/time.rb', line 1063

def second; _clock_field(:s); end

#stddev(axis: nil, **opts) ⇒ CATimedelta::Element, CATimedelta

Returns the spread of the instants as a CATimedelta (a duration) on self's unit. A spread is not a lattice point, so the rounding costs more here than for a centroid: on a coarse unit use t.to_unit(:h).stddev when the precision matters (§8).



817
818
819
# File 'lib/carray/time.rb', line 817

def stddev(*args, **opts)
  _reduce_dt(:stddev, :timedelta, args, opts)
end

#stddevp(axis: nil, **opts) ⇒ CATimedelta::Element, CATimedelta

Returns the population spread as a CATimedelta, in the same shapes as #stddev.



825
826
827
# File 'lib/carray/time.rb', line 825

def stddevp(*args, **opts)
  _reduce_dt(:stddevp, :timedelta, args, opts)
end

#strftime(fmt) ⇒ CAString

Returns a CAString whose elements are the per-cell Time#strftime(fmt) result (UTC). The input mask propagates.

Parameters:

  • fmt (String)

    strftime format string.

Returns:



1114
1115
1116
# File 'lib/carray/time.rb', line 1114

def strftime(fmt)
  CAString.wrap(to_time.convert(:object) {|t| t.strftime(fmt)})
end

#sum(*) ⇒ Object

Not supported; use #mean for a centroid.

Raises:

  • (TypeError)

    always.

Raises:

  • (TypeError)


832
833
834
# File 'lib/carray/time.rb', line 832

def sum(*)
  raise TypeError, "CATime#sum is ill-defined; use mean for centroid"
end

#ticksCArray

Sanctioned external accessor that pairs with the existing unit reader. An interop bridge (carray-xarray, carray-pycall consumers, etc.) can read out the int64 count + unit without reaching into parent (= an internal-contract accessor). The reference epoch is the implicit Unix epoch (1970-01-01 UTC) baked into the convention at the top of this file and into the C layer's Time.at-based decoding; it is not a per-instance state and therefore is not exposed as an accessor.

ca.ticks # => CArray (int64), tick counts since 1970-01-01 UTC ca.unit # => Symbol (:Y :M :W :D :h :m :s :ms :us :ns ...)

Returns the underlying int64 CArray of tick counts since the Unix epoch (1970-01-01 UTC) — the k-th tick of this array's resolution (see §4 of docs/CATime.md).

Returns:



663
664
665
# File 'lib/carray/time.rb', line 663

def ticks
  parent
end

#timesteps(unit: self.unit, origin: nil) ⇒ CArray

Returns the integer timestep of every element: the k-th unit-wide bucket counted from origin (floor toward the past, so pre-origin elements get a negative index -- a normal value, not masked). The result is an int64 CArray; the input mask propagates. With no unit the bucket is the storage resolution itself, so the result is a copy of the raw tick indices since the epoch (the same values as #ticks, but a fresh array rather than the live storage).

Parameters:

  • unit (String, Symbol, Resolution) (defaults to: self.unit)

    bucket resolution (default: this array's own storage resolution).

  • origin (Time, String, CATime::Element, DateTime, nil) (defaults to: nil)

    grid phase (default: the Unix epoch, or ISO Monday for a week bucket).

Returns:

  • (CArray)

    int64 timesteps.

Raises:

  • (ArgumentError)

    on a sub-resolution / unrepresentable (unit, storage-resolution) pair or a lossy origin.



1848
1849
1850
1851
1852
1853
1854
1855
1856
# File 'lib/carray/time.rb', line 1848

def timesteps(unit: self.unit, origin: nil)
  g = _step_grid(unit, origin)
  return _civil(:index, g[1], origin) if g[0] == :civil
  su, mul, step_ticks, o = g
  _guard_overflow(su, mul, o)
  d = _num_ticks(mul) - o
  q = d / step_ticks
  q - (d - q * step_ticks).lt(0)      # floor-div correction (%-independent)
end

#to_comparable(operand) ⇒ CATime

Brings operand into self's unit space for a direct storage comparison (comparison operators / search family / linear_section). self is the reference Face -- always one of our classes -- so it class-dispatches the operand rather than requiring every operand type to know every Face (which a core class like Time could not). CATime is ORDERABLE but not COMPARABLE (an operand may carry a different unit or shape), so the gate routes the operand through here.

Accepted operands: another CATime (unit-rescaled to self), a Element (lifted to a length-1 CATime), a Ruby Time, and a Ruby DateTime (both absolute instants converted to self's unit, Unix epoch, UTC). A String is out of scope (parsing is a separate, opposite-direction mechanism). A bare Integer / other type raises; descend to ca.parent to compare the hidden storage directly.

The rescale is an INSTANT conversion (convert_instant!), lossless: a coarser->finer unit always converts; a finer->coarser unit converts only when every value lands exactly on the coarser grid, else raises. Unlike a duration, a cross-group time cast IS possible via civil-date algebra (a :M value has a well-defined instant): :M/:Y widen exactly to :D and finer, and a fixed operand coarsens to :M/:Y only when it sits on the calendar boundary (:W is the one exception -- month/year starts are not week-aligned, so :Y/:M <-> :W raises).

Parameters:

Returns:

  • (CATime)

    in self's unit.

Raises:

  • (TypeError, ArgumentError)

    on an unreconcilable operand / unit.



881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
# File 'lib/carray/time.rb', line 881

def to_comparable (operand)
  case operand
  when CATime
    return operand if operand.unit == unit
    CATimeUnitAlgebra.convert_instant!(operand.parent, operand.unit, unit)
                         .time(unit: unit)
  when CATime::Element
    lifted = CATime.wrap(CA_INT64([operand.value]), unit: operand.unit)
    to_comparable(lifted)
  when Time
    # Reuse the single-literal builder; it yields a length-1 CATime
    # in the requested (= self's) resolution.
    CArray.time(operand, unit: unit)
  when defined?(DateTime) && DateTime
    to_comparable(operand.to_time.utc)
  else
    raise TypeError,
          "CATime cannot reconcile #{operand.class} " \
          "(use ca.parent to compare the raw int64 storage directly)"
  end
end

#to_dateCArray

Converts every element to a Ruby Date (UTC), returned as an object CArray. A sub-day unit floors to its day. Array-level counterpart to CATime::Element#to_date.

Returns:



1001
1002
1003
1004
1005
# File 'lib/carray/time.rb', line 1001

def to_date
  require 'date'
  # 2440588 = JD of 1970-01-01; proleptic Gregorian to match to_time and the field accessors.
  _field_days.convert(:object) {|d| Date.jd(2440588 + d, Date::GREGORIAN)}
end

#to_datetimeCArray

Converts every element to a Ruby DateTime (UTC offset 0), returned as an object CArray.

Returns:



1011
1012
1013
1014
# File 'lib/carray/time.rb', line 1011

def to_datetime
  require 'date'
  to_time.convert(:object) {|t| t.to_datetime}
end

#to_timeCArray

Converts every element to a Ruby Time (UTC), returned as an object CArray. Array-level counterpart to CATime::Element#to_time.

Returns:



986
987
988
989
990
991
992
993
994
# File 'lib/carray/time.rb', line 986

def to_time
  require 'time'
  if CATimeUnitAlgebra::FIXED.key?(unit.base)
    f = unit.tick_ratio                        # exact seconds / tick (Rational)
    parent.convert(:object) {|v| Time.at(v * f, in: 'UTC')}
  else                                         # calendar: exact granule midnight
    (_field_days * 86400).convert(:object) {|v| Time.at(v, in: 'UTC')}
  end
end

#to_unit(unit) ⇒ CATime

Returns the same instants re-expressed on a finer grid: a new CATime whose storage is self's ticks widened into unit. Accepted only when self's tick is a whole multiple of unit's, so every element lands exactly on the new grid and no instant moves (:D -> :h, "1 hour" -> "10 minutes", :Y -> :M). A coarser or partially-overlapping target raises rather than rounding silently; use #floor / #ceil / #round to move to a coarser grid explicitly.

Parameters:

  • unit (Resolution, Symbol, String)

    target resolution.

Returns:

Raises:

  • (ArgumentError)

    when self's tick is not a whole multiple of unit's (including any calendar / fixed-length pair, where no fixed ratio exists).

  • (RangeError)

    when the widened ticks overflow int64.



681
682
683
684
685
# File 'lib/carray/time.rb', line 681

def to_unit(unit)
  to = CATime::Resolution.parse(unit)
  CATimeUnitAlgebra.widen(parent,
                          CATimeUnitAlgebra.multiple_factor(self.unit, to)).time(unit: to)
end

#variance(*) ⇒ Object

Not supported: the variance of instants has squared-time units, which no type represents (ill-defined, like #sum). Use #stddev for the spread as a duration.

Raises:

  • (TypeError)

    always.

Raises:

  • (TypeError)


841
# File 'lib/carray/time.rb', line 841

def variance(*); raise TypeError, "CATime#variance is ill-defined (squared-time units); use stddev"; end

#variancep(*) ⇒ Object

Not supported, for the same reason as #variance. Use #stddevp.

Raises:

  • (TypeError)

    always.

Raises:

  • (TypeError)


846
# File 'lib/carray/time.rb', line 846

def variancep(*); raise TypeError, "CATime#variancep is ill-defined (squared-time units); use stddevp"; end

#weekdayCArray

Day of the week, Sunday = 0 .. Saturday = 6.

Returns:



1067
1068
1069
1070
1071
# File 'lib/carray/time.rb', line 1067

def weekday
  # 1970-01-01 is a Thursday (wday 4); Sun=0..Sat=6.
  n = _field_days + 4
  n - self.class.send(:_floordiv_i, n, 7) * 7          # floor-mod 7
end

#ydayCArray

Day of the year, 1..366.

Returns:



1075
1076
1077
1078
1079
1080
# File 'lib/carray/time.rb', line 1075

def yday
  d    = _field_days
  y    = self.class.send(:_civil_from_days, d)[0]
  ones = CArray.int64(*shape) { 1 }
  d - self.class.send(:_days_from_civil, y, ones, ones) + 1
end

#yearCArray

Each accessor returns an integer CArray with the requested calendar / clock field extracted from every element (UTC), computed by vectorized civil-date algebra directly on the int64 storage -- no per-cell Time. Exact for every unit, including :M / :Y (where the old Time.at path drifted by using 30.5-day / 365.25-day approximations). Fields finer than the storage unit collapse to their zero point, and the input mask propagates.

Returns:



1024
1025
1026
1027
1028
1029
1030
# File 'lib/carray/time.rb', line 1024

def year
  case unit.base
  when :Y then parent * unit.count + 1970
  when :M then self.class.send(:_floordiv_i, parent * unit.count + 1970 * 12, 12)
  else self.class.send(:_civil_from_days, _field_days)[0]
  end
end