Module: CATimeLiteral
- Defined in:
- lib/carray/time.rb
Overview
Reads a time literal (Time / DateTime / Integer unix-seconds / String) into the pieces the CATime constructors need. All parsing is UTC (an explicit offset is honoured; otherwise UTC) and DateTime-independent (Date._parse + a civil-date kernel). Internal to the time surface: nothing here is part of the public API.
Class Method Summary collapse
-
.epoch_seconds(spec, format = nil) ⇒ Object
Exact Rational seconds since the Unix epoch for a start literal (Time / DateTime / Integer unix-seconds / String).
-
.tick_index(spec, res, format = nil) ⇒ Object
Tick index of
spec's instant on theresgrid (floor toward the past). -
.to_time_array(literal, res, format, on_error) ⇒ Object
Single-literal build for time: a 1-element CATime, honouring the on_error policy (raise, or a masked cell).
-
.year_month(spec, format = nil) ⇒ Object
[year, month] (UTC) of a start literal, for a calendar-resolution grid.
Class Method Details
.epoch_seconds(spec, format = nil) ⇒ Object
Exact Rational seconds since the Unix epoch for a start literal (Time / DateTime / Integer unix-seconds / String). UTC default.
1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 |
# File 'lib/carray/time.rb', line 1637 def epoch_seconds(spec, format = nil) require 'date' require 'time' case spec when Time then spec.to_r when Integer then Rational(spec) when CATime::Element # A time element is already an instant, so it needs no parsing: a # fixed unit counts seconds directly, and a calendar one names the # first midnight of its granule (the same instant convert_instant! # gives it). This is what lets floor / ceil / to_unit output feed # straight back into time_range / time_series / .time. if CATimeUnitAlgebra::FIXED.key?(spec.unit.base) Rational(spec.value) * spec.unit.tick_ratio else Rational(CATimeUnitAlgebra.calendar_days_since_epoch(CA_INT64([spec.value]), spec.unit)[0] * 86400) end when String h = parse_date_fields(spec, format) days = CATimeCivil.days_from_civil(CA_INT64([h[:year]]), CA_INT64([h[:mon] || 1]), CA_INT64([h[:mday] || 1]))[0] sec = Rational(days * 86400 + (h[:hour] || 0) * 3600 + (h[:min] || 0) * 60 + (h[:sec] || 0)) sec += h[:sec_fraction] if h[:sec_fraction] sec -= h[:offset] if h[:offset] # east-of-UTC offset -> UTC sec else if defined?(DateTime) && spec.is_a?(DateTime) spec.to_time.to_r else raise ArgumentError, "cannot parse time #{spec.class}" end end end |
.tick_index(spec, res, format = nil) ⇒ Object
Tick index of spec's instant on the res grid (floor toward the past).
1704 1705 1706 1707 1708 1709 1710 1711 1712 |
# File 'lib/carray/time.rb', line 1704 def tick_index(spec, res, format = nil) if CATimeUnitAlgebra::FIXED.key?(res.base) (epoch_seconds(spec, format) / res.tick_ratio).floor else y, m = year_month(spec, format) months = (y - 1970) * 12 + (m - 1) (Rational(months) / res.tick_ratio).floor end end |
.to_time_array(literal, res, format, on_error) ⇒ Object
Single-literal build for time: a 1-element CATime, honouring the on_error policy (raise, or a masked cell).
1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 |
# File 'lib/carray/time.rb', line 1716 def to_time_array(literal, res, format, on_error) raw = CArray.int64(1) begin raw[0] = tick_index(literal, res, format) rescue ArgumentError, TypeError raise if on_error == :raise raw[0] = UNDEF end raw.time(unit: res) end |
.year_month(spec, format = nil) ⇒ Object
[year, month] (UTC) of a start literal, for a calendar-resolution grid.
1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 |
# File 'lib/carray/time.rb', line 1674 def year_month(spec, format = nil) require 'date' require 'time' case spec when Time then t = spec.utc; [t.year, t.month] when Integer then t = Time.at(spec, in: 'UTC'); [t.year, t.month] when CATime::Element # A calendar element is a month ordinal already, so read it as one # rather than going out through Time (which a :Y / :M element would # have to re-derive). Integer / and % floor, so a pre-epoch value # lands in the right month. case spec.unit.base when :M then mo = spec.value * spec.unit.count + 1970 * 12 [mo / 12, mo % 12 + 1] when :Y then [spec.value * spec.unit.count + 1970, 1] else t = spec.to_time.utc; [t.year, t.month] end when String h = parse_date_fields(spec, format) [h[:year], h[:mon] || 1] else if defined?(DateTime) && spec.is_a?(DateTime) t = spec.to_time.utc; [t.year, t.month] else raise ArgumentError, "cannot parse time #{spec.class}" end end end |