| Title: | Mixed Temporal Vectors and Operations |
|---|---|
| Description: | Flexible time classes for time series analysis and forecasting with mixed temporal granularities. Supports linear and cyclical time representations in discrete and continuous forms, with timezone support, across multiple calendar systems including Gregorian and ISO week date calendars. Time points are stored numerically relative to a chronon; an atomic time granule defined by time units of a calendar. Calendrical arithmetic enables conversion between time granules (e.g. days to months) and calendar systems. Multi-unit arithmetic allows for temporal analysis with other granules of common calendars (e.g. fortnights are 2-week units). Time vectors of different granularities (e.g. monthly and quarterly) can be combined in a single vector, making 'mixtime' ideal for data that changes observation frequency over time or requires temporal reconciliation across scales. The package is extensible, allowing users to define custom calendars that build upon civil and astronomical time systems. |
| Authors: | Mitchell O'Hara-Wild [aut, cre] (ORCID: <https://orcid.org/0000-0001-6729-7695>), Cynthia Huang [ctb] (ORCID: <https://orcid.org/0000-0002-9218-987X>), Rob Hyndman [ctb] (ORCID: <https://orcid.org/0000-0002-2140-5352>) |
| Maintainer: | Mitchell O'Hara-Wild <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.4.0.9000 |
| Built: | 2026-10-13 12:03:52 UTC |
| Source: | https://github.com/mitchelloharawild/mixtime |
Allen's interval algebra has thirteen base relations for time intervals.
== is defined in mt_linear-compare/mt_cyclical-compare; the twelve
operators below define the rest, computed from the same interval endpoints
(start/end) that comparison derives. Together, they cover all thirteen
relations:
| Operator | Relation | e1 %op% e2 holds iff |
%p% |
precedes | e1 ends before e2 begins (a gap) |
%m% |
meets | e1 ends exactly where e2 begins (no gap, no overlap) |
%o% |
overlaps | e1 begins before e2, e1 ends between the start and end of e2 |
%s% |
starts | e1 and e2 begin together, and e1 ends first |
%d% |
during | e1 is strictly within e2's span |
%f% |
finishes | e1 and e2 end together, and e1 begins later |
== |
equals | e1 and e2 share both endpoints |
%pi% |
preceded by | e2 %p% e1 |
%mi% |
met by | e2 %m% e1 |
%oi% |
overlapped by | e2 %o% e1 |
%si% |
started by | e2 %s% e1 |
%di% |
contains | e2 %d% e1 |
%fi% |
finished by | e2 %f% e1
|
mt_linear-compare/mt_cyclical-compare's </> are a deliberate
deviations from their use as 'precedes' in Allen's interval algebra
(%p%/%pi% operators). The important difference is that </> include
'meets' relations, while %p%/%pi% requires gaps, so in the examples
below jan < feb is TRUE in mixtime but the equivalent symbol in Allen's
interval algebra (jan %p% feb) is FALSE because there is no gap.
The implementation here also extends to continuous time instants, which are
treated as degenerate zero-width intervals. This allows testing how a
specific time instant relates to time spans, for example does January 2020
contain 30% through the day 2020-01-24 is
yearmonth("2020-01") %di% date(datetime("2020-01-24 07:12:00"), discrete = FALSE).
This is a technical deviation from Allen's interval algebra, which assumes
that intervals are non-degenerate (i.e. end > start, not end >= start).
e1 %p% e2 e1 %pi% e2 e1 %m% e2 e1 %mi% e2 e1 %o% e2 e1 %oi% e2 e1 %s% e2 e1 %si% e2 e1 %d% e2 e1 %di% e2 e1 %f% e2 e1 %fi% e2e1 %p% e2 e1 %pi% e2 e1 %m% e2 e1 %mi% e2 e1 %o% e2 e1 %oi% e2 e1 %s% e2 e1 %si% e2 e1 %d% e2 e1 %di% e2 e1 %f% e2 e1 %fi% e2
e1, e2
|
|
A logical vector.
Allen, J. F. (1983). Maintaining knowledge about temporal intervals. Communications of the ACM, 26(11), 832-843.
mt_linear-compare and mt_cyclical-compare for ==, <, >,
<=, >= - the three of Allen's relations that also form the package's
ordering (</> in a looser, adjacency-inclusive form than %p%/%pi%).
jan <- yearmonth("2020 Jan") feb <- yearmonth("2020 Feb") mar <- yearmonth("2020 Mar") q1 <- yearquarter("2020 Q1") jan == jan # January equals itself jan %p% mar # January precedes March: February leaves a genuine gap mar %pi% jan # ... equivalently, March is preceded by January jan %m% feb # January meets February: adjacent, no gap feb %mi% jan # ... equivalently, February is met by January jan < feb # `<` also holds for adjacent pairs, unlike `%p%` jan %p% feb # FALSE: no gap between them, so they don't (strictly) precede jan %s% q1 # January and Q1 start together, but January finishes first q1 %si% jan # ... equivalently, Q1 is started by January feb %d% q1 # February is strictly within Q1 q1 %di% feb # ... equivalently, Q1 contains February mar %f% q1 # March and Q1 finish together, but March starts later q1 %fi% mar # ... equivalently, Q1 is finished by Marchjan <- yearmonth("2020 Jan") feb <- yearmonth("2020 Feb") mar <- yearmonth("2020 Mar") q1 <- yearquarter("2020 Q1") jan == jan # January equals itself jan %p% mar # January precedes March: February leaves a genuine gap mar %pi% jan # ... equivalently, March is preceded by January jan %m% feb # January meets February: adjacent, no gap feb %mi% jan # ... equivalently, February is met by January jan < feb # `<` also holds for adjacent pairs, unlike `%p%` jan %p% feb # FALSE: no gap between them, so they don't (strictly) precede jan %s% q1 # January and Q1 start together, but January finishes first q1 %si% jan # ... equivalently, Q1 is started by January feb %d% q1 # February is strictly within Q1 q1 %di% feb # ... equivalently, Q1 contains February mar %f% q1 # March and Q1 finish together, but March starts later q1 %fi% mar # ... equivalently, Q1 is finished by March
Coerces a time object (e.g. Date, POSIXct, yearmonth) to a mixtime
vector using vctrs::vec_cast(). The chronon and cycle are inferred from
x via time_chronon() and time_cycle().
as_mixtime(x, ...)as_mixtime(x, ...)
x |
A time value to convert to a |
... |
Additional arguments passed to the underlying |
A mixtime object corresponding to x.
mixtime() for constructing a mixtime directly from data,
is_mixtime() for testing if an object is a mixtime.
as_mixtime(Sys.Date()) as_mixtime(Sys.time())as_mixtime(Sys.Date()) as_mixtime(Sys.time())
Time unit constructors for the Gregorian calendar system. These units can be
used with linear_time() to create custom time representations.
cal_gregoriancal_gregorian
A civil-based calendar containing Gregorian time units.
The following time units are available in the Gregorian calendar (cal_gregorian$).
year(): Year unit
quarter(): Quarter (3-month period) unit
month(): Month unit
day(): Day unit
hour(): Hour unit
minute(): Minute unit
second(): Second unit
millisecond(): Millisecond unit
These units form a hierarchy where conversions between adjacent units follow the Gregorian calendar rules. For units that don't have a fixed relationship (e.g., months to days), the conversion requires a time context.
An S3 list of class c("cal_gregorian", "mt_calendar") containing
the named time unit classes of the Gregorian calendar. Each unit is
accessible via $ notation and calling it with a step size produces a
time granule (e.g., 1 month granule as cal_gregorian$month(1L)).
linear_time() for creating linear time points.
# Create a custom time representation using Gregorian units linear_time( Sys.time(), chronon = hour(1L) )# Create a custom time representation using Gregorian units linear_time( Sys.time(), chronon = hour(1L) )
Time unit constructors for the ISO 8601 calendar system. These units can be
used with linear_time() to create custom time representations.
cal_isoweekcal_isoweek
A civil-based calendar containing ISO 8601 time units.
The following time units are available in the ISO week date calendar:
year(): ISO year unit (years start on the week containing the first Thursday)
week(): Week unit (7-day periods)
day(): Day unit
hour(): Hour unit
minute(): Minute unit
second(): Second unit
millisecond(): Millisecond unit
ISO 8601 weeks always start on Monday and the first week of a year is the week containing the first Thursday of that year. This means that some days in early January may belong to the last week of the previous ISO year, and some days in late December may belong to the first week of the next ISO year.
An S3 list of class c("cal_isoweek", "mt_calendar") containing
the named time unit classes of the ISO 8601 week calendar. Each unit is
accessible via $ notation and calling it with a step size produces a
time granule (e.g., 1 week granule as cal_isoweek$week(1L)).
linear_time() for creating custom time representations,
yearweek() for a pre-defined ISO 8601 year-week representation
Time unit constructors for the Symmetry454 calendar system. These units can be
used with linear_time() to create custom time representations.
cal_sym454cal_sym454
A civil-based calendar containing Symmetry454 time units.
The Symmetry454 calendar (Sym454) is a perennial solar calendar proposed by Dr. Irv Bromberg. It preserves the traditional 12-month structure and 7-day week, with months arranged in a symmetrical 4-5-4 week pattern per quarter. Every month starts on Monday and has a whole number of weeks, meaning no month ever contains a partial week.
The following time units are available in the Symmetry454 calendar (cal_sym454$).
year(): Year unit
month(): Month unit
week(): Week unit
day(): Day unit
hour(): Hour unit
minute(): Minute unit
second(): Second unit
millisecond(): Millisecond unit
Rather than intercalary days, Symmetry454 uses a leap week appended to
December once every 5 or 6 years, making December a 5-week month in leap
years. A year is a leap year if (52 * year + 146) %% 293 < 52.
This yields a mean year of 365 + 71/293 days (approx 365 days, 5 hours, 48 minutes, 56.5 seconds), intentionally slightly shorter than the mean northward equinoctial year.
An S3 list of class c("cal_sym454", "mt_calendar") containing
the named time unit classes of the Symmetry454 calendar. Each unit is
accessible via $ notation and calling it with a step size produces a
time granule (e.g., 1 week granule as cal_sym454$week(1L)).
linear_time() for creating linear time points, and
https://en.wikipedia.org/wiki/Symmetry454 for more calendar details.
# Create a custom time representation using Symmetry454 units linear_time( Sys.time(), chronon = cal_sym454$week(1L) )# Create a custom time representation using Symmetry454 units linear_time( Sys.time(), chronon = cal_sym454$week(1L) )
Time unit constructors for the civil time system where the boundary of each
day is at midnight on the 24 hour clock. This calendar is intended to be
built on by other calendars (e.g. [cal_time_civil] and [cal_isoweek]) to
add common time components. These units can be
used with linear_time() to create custom time representations.
cal_time_civilcal_time_civil
The following time units are available (cal_time_civil$).
day(): Day unit
hour(): Hour unit
minute(): Minute unit
second(): Second unit
millisecond(): Millisecond unit
microsecond(): Microsecond unit
nanosecond(): Nanosecond unit
A time granule object for the civil time system.
# Create a custom time representation using civil time granules hms <- new_cyclical_time_fn( chronon = second(1L), cycle = hour(1L) )# Create a custom time representation using civil time granules hms <- new_cyclical_time_fn( chronon = second(1L), cycle = hour(1L) )
Time unit constructors for the synodic lunar time system, where the boundary
of each month is at the new moon (lunar conjunction) and the boundary of
each phase is at a lunar octant (each eighth of the synodic cycle). Both
boundaries are location-independent, as the new moon is a geocentric
astronomical event. cal_time_lunar is an alias for
cal_time_lunar_synodic.
cal_time_lunar_synodic cal_time_lunarcal_time_lunar_synodic cal_time_lunar
A calendar containing synodic lunar time units.
The following time units are available in the lunar calendar systems.
month(): Synodic month unit
phase(): Synodic phase unit
An S3 list of class c("cal_time_lunar", "mt_calendar") containing
the named time unit classes of the synodic lunar calendar. Each unit is
accessible via $ notation and calling it with a step size produces a
time granule (e.g., 1 synodic month granule as
cal_time_lunar$month(1L)). Lunar month and phase boundaries are
location-independent.
cal_time_civil, cal_time_solar
# Find the time of the most recent new moon in the Gregorian calendar time_floor(datetime(Sys.time(), tz = "Australia/Melbourne"), cal_time_lunar$month(1L))# Find the time of the most recent new moon in the Gregorian calendar time_floor(datetime(Sys.time(), tz = "Australia/Melbourne"), cal_time_lunar$month(1L))
Time unit constructors for the transit-based solar time system, where the
boundary of each day is at apparent solar midnight. Solar events define the
ampm (midnight and noon) and illumination (dawn, sunrise, sunset, dusk)
units. cal_time_solar is an alias for cal_time_solar_transit.
cal_time_solar_transit cal_time_solarcal_time_solar_transit cal_time_solar
A location-based calendar containing transit-based solar time units.
The following time units are available in the solar calendar systems.
day(): Day unit
ampm(): Half-day units (AM = before solar noon, PM = after solar noon)
hour(): Hour units within the solar day
minute(): Minute units within the solar hour
second(): Second units within the solar minute
degree(): Solar angle units within the day
arcminute(): Arcminute units within the solar degree
arcsecond(): Arcsecond units within the solar arcminute
illumination(): Illumination phases (night, astronomical/nautical/civil dawn, day, civil/nautical/astronomical dusk)
The ampm unit divides each solar day into two halves between solar noon and
solar midnight:
| Half | Period | Description |
| AM | Solar midnight to noon | Morning half; before solar transit |
| PM | Solar noon to midnight | Afternoon half; after solar transit |
Phases describe the illumination state of the sky and correspond to standard twilight definitions used in astronomy and navigation. Each phase is bounded by a pair of solar altitude thresholds:
| Phase | Solar altitude range | Description |
| Night | < -18° | Sky fully dark; from last dusk to first dawn (spans noon) |
| Astronomical dawn | -18° to -12° | Astronomical twilight before sunrise; faint objects obscured |
| Nautical dawn | -12° to -6° | Nautical twilight before sunrise; horizon visible at sea |
| Civil dawn | -6° to -0.833° | Civil twilight before sunrise; sky brightening in the east |
| Day | > -0.833° | Sun above the horizon; spans solar noon |
| Civil dusk | -0.833° to -6° | Civil twilight after sunset; sky fading in the west |
| Nautical dusk | -6° to -12° | Nautical twilight after sunset; horizon visible at sea |
| Astronomical dusk | -12° to -18° | Astronomical twilight after sunset; faint objects obscured |
The -0.833° threshold for sunrise and sunset accounts for the mean angular radius of the solar disc (0.267°) plus the standard atmospheric refraction at the horizon (0.566°). Noon and midnight are derived from the equation of time rather than a fixed altitude. Locations that experience polar day or polar night (civil days where sunrise does not occur) are not currently supported, it is recommended to use an alternative reference location.
An S3 list of class c("cal_time_solar", "mt_calendar") containing
the named time unit classes of the solar transit calendar. Each unit is
accessible via $ notation and calling it with a step size and location
produces a time granule (e.g., 1 solar day granule as
cal_time_solar$day(1L, lat = 0, lon = 0)). Because solar day boundaries
depend on the observer's position, each unit constructor requires lat
and lon arguments.
cal_time_civil, cal_time_lunar
# Find the current solar time in Melbourne datetime(Sys.time(), calendar = cal_time_solar, lat = -37.8136, lon = 144.9631)# Find the current solar time in Melbourne datetime(Sys.time(), calendar = cal_time_solar, lat = -37.8136, lon = 144.9631)
This S7 generic function defines the calendrical relationships between two
chronons, and is one of the building block for defining calendars in mixtime.
It calculates how many x chronons fit into the y chronon. Some chronon
sizes are context-dependent (such as the number of days in a month),
and so an optional time point defined in terms of y chronons can be
provided with at.
chronon_cardinality(x, y, ...)chronon_cardinality(x, y, ...)
x |
The finer time granule (e.g. |
y |
The coarser time granule (e.g. |
... |
Additional arguments for methods. |
The methods are dispatched based on the shortest path along defined methods. This allows for defining only the direct relationships between adjacent time units, and relying on graph traversal to find how to convert between more distant units. For example the number of seconds in an hour can be calculated from the number of seconds in a minute and then number of minutes in an hour.
If a method is defined for converting between time units of different calendar systems (e.g., Gregorian calendar days to Chinese calendar days), then that method can be used to convert times at any granularity between the two systems.
Numeric describing how many x time granules fit into y at time at.
# There are 12 months in a year with(cal_gregorian, chronon_cardinality(month(1L), year(1L))) # There are 7 days in a week with(cal_isoweek, chronon_cardinality(day(1L), week(1L))) # There are 3600 seconds in an hour with(cal_gregorian, chronon_cardinality(second(1L), hour(1L))) # There are 18 "2 months" in 3 years with(cal_gregorian, chronon_cardinality(month(2L), year(3L))) # There are 365 days in 2025 (a common year) chronon_cardinality( cal_gregorian$day(1L), cal_gregorian$year(1L), at = year(as.Date("2025-01-01")) ) # There are 366 days in 2024 (a leap year) chronon_cardinality( cal_gregorian$day(1L), cal_gregorian$year(1L), at = mixtime::year(as.Date("2024-01-01")) ) # There are 29 days in February 2024 (a leap year) chronon_cardinality( cal_gregorian$day(1L), cal_gregorian$month(1L), at = yearmonth(as.Date("2024-02-01")) )# There are 12 months in a year with(cal_gregorian, chronon_cardinality(month(1L), year(1L))) # There are 7 days in a week with(cal_isoweek, chronon_cardinality(day(1L), week(1L))) # There are 3600 seconds in an hour with(cal_gregorian, chronon_cardinality(second(1L), hour(1L))) # There are 18 "2 months" in 3 years with(cal_gregorian, chronon_cardinality(month(2L), year(3L))) # There are 365 days in 2025 (a common year) chronon_cardinality( cal_gregorian$day(1L), cal_gregorian$year(1L), at = year(as.Date("2025-01-01")) ) # There are 366 days in 2024 (a leap year) chronon_cardinality( cal_gregorian$day(1L), cal_gregorian$year(1L), at = mixtime::year(as.Date("2024-01-01")) ) # There are 29 days in February 2024 (a leap year) chronon_cardinality( cal_gregorian$day(1L), cal_gregorian$month(1L), at = yearmonth(as.Date("2024-02-01")) )
This function converts between chronons measured in different time granules.
It is used internally for converting between different continuous time types,
and is particularly useful for efficiently converting between irregular time
granules. The default method uses chronon_cardinality() to cast between
time granules, which is efficient for regular time granules.
chronon_divmod(from, to, ...)chronon_divmod(from, to, ...)
from |
The time granule that |
to |
The time granule to convert |
... |
Additional arguments for methods. |
An list of two elements:
div: integer vector of chronons measured in the to time granule.
mod: integer vector of the remainder (in from time granule) after
converting to the to time granule.
# Convert day 16 after epoch (1970-01-01) into weeks since epoch (and remainder days) with(cal_isoweek, chronon_divmod(day(1L), week(1L), 16L)) # Convert week 4 after epoch (1970-W1) into days since epoch with(cal_isoweek, chronon_divmod(week(1L), day(1L), 4L))# Convert day 16 after epoch (1970-01-01) into weeks since epoch (and remainder days) with(cal_isoweek, chronon_divmod(day(1L), week(1L), 16L)) # Convert week 4 after epoch (1970-W1) into days since epoch with(cal_isoweek, chronon_divmod(week(1L), day(1L), 4L))
Returns the epoch offset for a given chronon (time unit). The epoch defines the starting point of the chronon's linear numbering, used when converting from internal representations to common displays (e.g. applying an epoch of 1970-01-01).
chronon_epoch(x, ...)chronon_epoch(x, ...)
x |
A chronon (time unit) object. |
... |
Additional arguments for methods. |
A numeric value representing the epoch for the chronon.
# The epoch for year linear time displays is 1970 chronon_epoch(cal_gregorian$year(1L))# The epoch for year linear time displays is 1970 chronon_epoch(cal_gregorian$year(1L))
Provides suffixes for default formatting strings for a given chronon (time granule). This provides useful information such as timezones or locations in the string.
chronon_format_attr(x, ...)chronon_format_attr(x, ...)
x |
A chronon (time granule) object. |
... |
Additional arguments for methods. |
A character string containing the default format suffix for the chronon.
Provides default linear time formatting strings for a given chronon (finest
time granule). The format strings use placeholders like {lin(year(1L))},
{cyc(month(1L), year(1L)} and {cyc(day(1L), month(1L)}, which are
evaluated in the context of the data's time_calendar().
chronon_format_linear(x, cal = time_calendar(x), ...) chronon_format_cyclical(x, y, ...) chronon_format_duration(x, ...)chronon_format_linear(x, cal = time_calendar(x), ...) chronon_format_cyclical(x, y, ...) chronon_format_duration(x, ...)
x |
A time granule for the chronon. |
cal |
The calendar of the chronon, used to disambiguate suitable format
strings for time units that are shared across calendars (e.g.
|
... |
Additional arguments for methods. |
y |
A time granule for the cycle |
A character string containing the default format template for the chronon.
chronon_format_linear(cal_gregorian$year(1L)) chronon_format_linear(cal_gregorian$month(1L)) chronon_format_linear(cal_gregorian$day(1L)) chronon_format_linear(cal_isoweek$day(1L)) chronon_format_cyclical(cal_gregorian$month(1L), cal_gregorian$year(1L)) chronon_format_cyclical(cal_gregorian$day(1L), cal_gregorian$month(1L)) chronon_format_cyclical(cal_isoweek$day(1L), cal_isoweek$week(1L)) chronon_format_cyclical(cal_isoweek$week(1L), cal_isoweek$year(1L)) chronon_format_duration(cal_gregorian$year(1L)) chronon_format_duration(cal_gregorian$month(1L)) chronon_format_duration(cal_gregorian$day(1L))chronon_format_linear(cal_gregorian$year(1L)) chronon_format_linear(cal_gregorian$month(1L)) chronon_format_linear(cal_gregorian$day(1L)) chronon_format_linear(cal_isoweek$day(1L)) chronon_format_cyclical(cal_gregorian$month(1L), cal_gregorian$year(1L)) chronon_format_cyclical(cal_gregorian$day(1L), cal_gregorian$month(1L)) chronon_format_cyclical(cal_isoweek$day(1L), cal_isoweek$week(1L)) chronon_format_cyclical(cal_isoweek$week(1L), cal_isoweek$year(1L)) chronon_format_duration(cal_gregorian$year(1L)) chronon_format_duration(cal_gregorian$month(1L)) chronon_format_duration(cal_gregorian$day(1L))
These utility functions take a set of chronons and identify a common
chronon that can represent all input chronons without loss of
information, using the ordered relationships defined by
chronon_cardinality() methods. This is useful for operations that
require a shared time granule, such as combining or comparing different
time measured at different precisions.
chronon_glb() finds the greatest lower bound (GLB): the common chronon
of the finest granularity that can represent all input chronons without
loss of information.
chronon_lub() finds the least upper bound (LUB): the common chronon of
the coarsest granularity that every input chronon evenly aggregates
into - the dual of chronon_glb().
chronon_common() was renamed to chronon_glb() to distinguish it from
its dual, chronon_lub().
chronon_glb(x, ...) chronon_glb.mixtime(x, .ptype = NULL, ...) chronon_lub(x, ...) chronon_lub.mixtime(x, .ptype = NULL, ...) chronon_common(x, .ptype = NULL, ...)chronon_glb(x, ...) chronon_glb.mixtime(x, .ptype = NULL, ...) chronon_lub(x, ...) chronon_lub.mixtime(x, .ptype = NULL, ...) chronon_common(x, .ptype = NULL, ...)
x |
A time object (typically a |
... |
Additional arguments for methods. |
.ptype |
If NULL, the default, the output returns the common chronon
across all chronons of |
A time granule object representing the common chronon.
# The finest common chronon between a year-month and a day is a day chronon_glb(c(yearmonth(Sys.Date()), date(Sys.Date()))) # The finest common chronon between a Gregorian month and an ISO week is a day chronon_glb(c(yearweek(Sys.Date()), yearmonth(Sys.Date()))) # The finest common chronon between a ISO week and an hour is an hour chronon_glb(c(yearweek(Sys.Date()), linear_time(Sys.time(), hour(1L)))) # The coarsest common chronon between a second and a minute is a minute chronon_lub(c(linear_time(Sys.time(), second(1L)), linear_time(Sys.time(), minute(1L))))# The finest common chronon between a year-month and a day is a day chronon_glb(c(yearmonth(Sys.Date()), date(Sys.Date()))) # The finest common chronon between a Gregorian month and an ISO week is a day chronon_glb(c(yearweek(Sys.Date()), yearmonth(Sys.Date()))) # The finest common chronon between a ISO week and an hour is an hour chronon_glb(c(yearweek(Sys.Date()), linear_time(Sys.time(), hour(1L)))) # The coarsest common chronon between a second and a minute is a minute chronon_lub(c(linear_time(Sys.time(), second(1L)), linear_time(Sys.time(), minute(1L))))
Provides candidate format strings for parsing text into a given chronon
(finest time granule), for use as the format argument of
time_parse(). Dispatches the same way as
chronon_format_linear()/chronon_format_cyclical(), but returns every
common format instead of a single default, so time_parse() can try each
in turn and keep whichever parses the most values. Methods should build
their return value with parse_format().
chronon_parse_linear(x, cal = time_calendar(x), ...) chronon_parse_cyclical(x, y, ...)chronon_parse_linear(x, cal = time_calendar(x), ...) chronon_parse_cyclical(x, y, ...)
x |
A time granule for the chronon. |
cal |
The calendar of the chronon, used to disambiguate suitable format
strings for time units that are shared across calendars (e.g.
|
... |
Additional arguments for methods. |
y |
A time granule for the cycle |
A character vector of format templates, ordered from most to
least common, built with parse_format(). The first element typically
matches chronon_format_linear() (for chronon_parse_linear()) or
chronon_format_cyclical() (for chronon_parse_cyclical()) for the
same chronon.
parse_format() for building candidate format strings (what
these methods are built from), time_parse() for using the result as
candidate formats, chronon_format_linear()/chronon_format_cyclical()
for the single default format these are based on.
chronon_parse_linear(cal_gregorian$year(1L)) chronon_parse_linear(cal_gregorian$month(1L)) chronon_parse_linear(cal_gregorian$day(1L)) chronon_parse_linear(cal_isoweek$day(1L)) chronon_parse_cyclical(cal_gregorian$month(1L), cal_gregorian$year(1L)) chronon_parse_cyclical(cal_isoweek$day(1L), cal_isoweek$week(1L))chronon_parse_linear(cal_gregorian$year(1L)) chronon_parse_linear(cal_gregorian$month(1L)) chronon_parse_linear(cal_gregorian$day(1L)) chronon_parse_linear(cal_isoweek$day(1L)) chronon_parse_cyclical(cal_gregorian$month(1L), cal_gregorian$year(1L)) chronon_parse_cyclical(cal_isoweek$day(1L), cal_isoweek$week(1L))
Calculates rolling sums of length k for all contiguous subsequences
around a circular vector. Returns sums for each valid k-element window
that wraps around the vector as if arranged in a circle.
circsum(x, size, step = size)circsum(x, size, step = size)
x |
A numeric vector to compute circular sums over. |
size |
Integer; the window size (number of consecutive elements to sum). A negative size anchors the window at its end, with the window counting backwards. |
step |
Integer; the step size (the increment in starting index for each sum). A negative step walks the windows backwards around the circle. |
A numeric vector containing the sum of each contiguous subsequence
around the circle. The length of the resulting vector is the number of
combinations until the pattern between x and step repeats
# Simple circular sum with window of 2 circsum(c(1, 2, 3, 4), 2) # Returns: 3 7 (1+2, 3+4) # Window of 3 elements circsum(c(1, 2, 3, 4, 5), 3) # Returns: 6 10 9 8 12 (1+2+3, 4+5+1, 2+3+4, 5+1+2, 3+4+5) # Negative step walks the same windows backwards circsum(c(1, 2, 3, 4, 5), 1, -1) # Returns: 1 5 4 3 2 # Negative size anchors each window at its end instead of its start - a # trailing rather than leading rolling sum circsum(c(1, 2, 3, 4, 5), -2, 1) # Returns: 6 3 5 7 9 (5+1, 1+2, 2+3, 3+4, 4+5)# Simple circular sum with window of 2 circsum(c(1, 2, 3, 4), 2) # Returns: 3 7 (1+2, 3+4) # Window of 3 elements circsum(c(1, 2, 3, 4, 5), 3) # Returns: 6 10 9 8 12 (1+2+3, 4+5+1, 2+3+4, 5+1+2, 3+4+5) # Negative step walks the same windows backwards circsum(c(1, 2, 3, 4, 5), 1, -1) # Returns: 1 5 4 3 2 # Negative size anchors each window at its end instead of its start - a # trailing rather than leading rolling sum circsum(c(1, 2, 3, 4, 5), -2, 1) # Returns: 6 3 5 7 9 (5+1, 1+2, 2+3, 3+4, 4+5)
class_mixtime is the base S7 class for all mixtime vector objects,
inheriting from vecvec::class_vecvec. While not intended to be used
directly, this S7 class is suitable to use when defining S7 methods for
mixtime vectors. S3 methods can be defined using the mixtime::mixtime
class.
class_mixtime(x = list(), i = seq_len(sum(lengths(x))))class_mixtime(x = list(), i = seq_len(sum(lengths(x))))
x |
A list of |
i |
A vector of integers specifying the location of each element in |
When used as a class definition (e.g., in S7::method(generic, class_mixtime)), an S7 class object representing the mixtime class,
inheriting from vecvec::class_vecvec. When called as a constructor
(class_mixtime(list(...))), a mixtime vector of S7 class mixtime
(also inheriting the S3 class "mixtime"), containing the supplied list
of time vectors as a vecvec::class_vecvec structure. End users should
prefer mixtime() or new_mixtime() for construction.
mixtime() for creating mixtime vectors, and new_mixtime() for
the low-level constructor function of this S7 class.
lin() and cyc() name the time components addressed by mixtime's
component-aware contexts — a single vocabulary shared across format() (and
parsing) format strings and time_components() expressions. They are only
meaningful inside one of these contexts; calling them directly is an error.
lin(granule) cyc(granule, cycle)lin(granule) cyc(granule, cycle)
granule |
The time granule to address, given as a granule generator (e.g.
|
cycle |
The coarser granule defining the cycle a |
A linear and a cyclical component of the same granule store the same value:
the count of that chronon since the Unix epoch. The reduction to a within-cycle
position happens only when a cyclical vector is formatted. cyc() therefore
behaves like lin() on its finest granule but additionally records the cycle.
A component specification, consumed internally by the component-aware
context (e.g. format() or time_components()).
format() and time_components()
cyclical_time() creates a vector of cyclical time points representing
positions within repeating cycles. This function is useful for creating custom
cyclical time representations that aren't covered by the convenience functions
like day_of_week() or month_of_year().
cyclical_time( data, chronon = time_chronon(data), cycle = time_cycle(data), discrete = TRUE, calendar = time_calendar(data) )cyclical_time( data, chronon = time_chronon(data), cycle = time_cycle(data), discrete = TRUE, calendar = time_calendar(data) )
data |
Input data to convert to cyclical time. Can be:
|
chronon |
A time granule representing the chronon (finest
indivisible time granule), evaluated in the context of |
cycle |
A time granule representing the cycle (coarser time granule
that defines the period), evaluated in the context of |
discrete |
Logical. If |
calendar |
Calendar system used to evaluate |
A mixtime time vector containing an mt_cyclical vector.
new_cyclical_time_fn() for creating reusable cyclical time functions
day_of_week(), day_of_month(), day_of_year() for common cyclical representations
month_of_year(), week_of_year() for other cyclical time helpers
cal_gregorian, cal_isoweek for calendar systems
# Day of week (1-7, Monday = 1) cyclical_time( Sys.Date(), chronon = day(1L), cycle = week(1L), calendar = cal_isoweek ) # Month of year (1-12) cyclical_time( Sys.Date(), chronon = month(1L), cycle = year(1L) ) # Continuous time (discrete = FALSE) for fractional month of year cyclical_time( Sys.Date(), chronon = month(1L), cycle = year(1L), discrete = FALSE ) # Day of month with Gregorian calendar cyclical_time( Sys.Date(), chronon = day(1L), cycle = month(1L), calendar = cal_gregorian ) # Hours, minutes, and seconds cyclical_time( Sys.time(), chronon = second(1L), cycle = day(1L) )# Day of week (1-7, Monday = 1) cyclical_time( Sys.Date(), chronon = day(1L), cycle = week(1L), calendar = cal_isoweek ) # Month of year (1-12) cyclical_time( Sys.Date(), chronon = month(1L), cycle = year(1L) ) # Continuous time (discrete = FALSE) for fractional month of year cyclical_time( Sys.Date(), chronon = month(1L), cycle = year(1L), discrete = FALSE ) # Day of month with Gregorian calendar cyclical_time( Sys.Date(), chronon = day(1L), cycle = month(1L), calendar = cal_gregorian ) # Hours, minutes, and seconds cyclical_time( Sys.time(), chronon = second(1L), cycle = day(1L) )
Helper functions for creating cyclical time representations. These functions create time objects that repeat within a larger time cycle, useful for identifying seasonal patterns or positions within a calendar period.
month_of_year(data, discrete = TRUE, calendar = time_calendar(data), ...) day_of_year(data, discrete = TRUE, calendar = time_calendar(data), ...) day_of_month(data, discrete = TRUE, calendar = time_calendar(data), ...) time_of_day(data, discrete = TRUE, calendar = time_calendar(data), ...) day_of_week(data, discrete = TRUE, calendar = time_calendar(data), ...) week_of_year(data, discrete = TRUE, calendar = time_calendar(data), ...)month_of_year(data, discrete = TRUE, calendar = time_calendar(data), ...) day_of_year(data, discrete = TRUE, calendar = time_calendar(data), ...) day_of_month(data, discrete = TRUE, calendar = time_calendar(data), ...) time_of_day(data, discrete = TRUE, calendar = time_calendar(data), ...) day_of_week(data, discrete = TRUE, calendar = time_calendar(data), ...) week_of_year(data, discrete = TRUE, calendar = time_calendar(data), ...)
data |
Another object to be coerced into the specified cyclical time. |
discrete |
If |
calendar |
A calendar object specifying the calendar system to use. |
... |
Additional arguments for |
A mixtime time vector containing an mt_cyclical vector with chronon and cycle matching the function used.
day_of_week(): Represents the day position within a week (1-7) using
the ISO 8601 standard where weeks start on Monday.
day_of_month(): Represents the day position within a month (1-28, 1-29,
1-30, or 1-31 depending on the month). The chronon is one day, cycling
within a month.
day_of_year(): Represents the day position within a year (1-365 or 1-366
for leap years). The chronon is one day, cycling within a year.
week_of_year(): Represents the week position within a year (1-52 or 1-53)
using the ISO 8601 week numbering system.
month_of_year(): Represents the month position within a year (1-12).
The chronon is one month, cycling within a year.
You can create custom cyclical time representations using cyclical_time()
with any of the supported time units (see calendar_gregorian and calendar_isoweek).
For example, to create a representation for day of the month:
day_of_month <- new_cyclical_time_fn( chronon = day(1L), cycle = month(1L), default_calendar = cal_gregorian )
cyclical_time() for creating cyclical time vectors,
new_cyclical_time_fn() for creating cyclical time helper functions
month_of_year(Sys.Date()) day_of_year(Sys.Date()) day_of_week(Sys.Date()) day_of_week(as.Date("2025-12-15") + 0:6)month_of_year(Sys.Date()) day_of_year(Sys.Date()) day_of_week(Sys.Date()) day_of_week(as.Date("2025-12-15") + 0:6)
duration() creates a vector of durations with a specified chronon.
Durations represent a fixed span of time measured in a given time granule
(e.g., 3 months, 5 days), without reference to a specific point in time.
duration( data, chronon = time_chronon(data), discrete = NULL, calendar = time_calendar(data) )duration( data, chronon = time_chronon(data), discrete = NULL, calendar = time_calendar(data) )
data |
A time vector of duration magnitudes, or an existing
|
chronon |
A time granule expression representing the chronon, evaluated
in the context of |
discrete |
Logical. If |
calendar |
Calendar system used to evaluate |
A mixtime vector containing an mt_duration vector.
new_duration_fn() for creating reusable duration functions
cal_gregorian, cal_isoweek for calendar systems
# A duration of 3 months duration(3L, cal_gregorian$month(1L)) # A vector of durations in days duration(1:7, cal_gregorian$day(1L)) # Convert a duration of 4 days into weeks duration(days(4), cal_isoweek$week(1L), discrete = FALSE) duration(days(4), cal_isoweek$week(1L), discrete = TRUE)# A duration of 3 months duration(3L, cal_gregorian$month(1L)) # A vector of durations in days duration(1:7, cal_gregorian$day(1L)) # Convert a duration of 4 days into weeks duration(days(4), cal_isoweek$week(1L), discrete = FALSE) duration(days(4), cal_isoweek$week(1L), discrete = TRUE)
Convenience functions for creating duration vectors of common time units.
Each function wraps new_duration_fn() for its respective chronon.
years(data, calendar = time_calendar(data), ...) quarters(data, calendar = time_calendar(data), ...) months(data, calendar = time_calendar(data), ...) weeks(data, calendar = time_calendar(data), ...) days(data, calendar = time_calendar(data), ...) hours(data, calendar = time_calendar(data), ...) minutes(data, calendar = time_calendar(data), ...) seconds(data, calendar = time_calendar(data), ...) milliseconds(data, calendar = time_calendar(data), ...)years(data, calendar = time_calendar(data), ...) quarters(data, calendar = time_calendar(data), ...) months(data, calendar = time_calendar(data), ...) weeks(data, calendar = time_calendar(data), ...) days(data, calendar = time_calendar(data), ...) hours(data, calendar = time_calendar(data), ...) minutes(data, calendar = time_calendar(data), ...) seconds(data, calendar = time_calendar(data), ...) milliseconds(data, calendar = time_calendar(data), ...)
data |
A time vector of duration magnitudes, or an existing
|
calendar |
Calendar system used to evaluate |
... |
Additional arguments passed to the chronon (e.g. |
A mixtime vector containing an mt_duration vector.
new_duration_fn() for creating custom duration functions
duration() for creating duration vectors directly
cal_gregorian, cal_isoweek for calendar systems
years(3L) quarters(2L) months(6L) weeks(4L) days(7L) hours(12L) minutes(30L) seconds(45L) milliseconds(500L)years(3L) quarters(2L) months(6L) weeks(4L) days(7L) hours(12L) minutes(30L) seconds(45L) milliseconds(500L)
Formats a mixtime vector as a character vector, using a glue-style format
string of {lin(...)}/{cyc(...)} tokens tailored to the vector's chronon
and cycle. If format is omitted, a sensible default is derived
automatically. See vignette("time-format-strings") for the format string
syntax.
## S4 method for signature 'mt_time' format(x, ..., attr = TRUE)## S4 method for signature 'mt_time' format(x, ..., attr = TRUE)
x |
A mixtime vector. |
... |
Additional arguments for methods, including |
attr |
If |
A character vector the same length as x.
Tests whether x inherits from the mixtime class.
is_mixtime(x)is_mixtime(x)
x |
An object to test. |
A scalar logical: TRUE if x is a mixtime vector, FALSE
otherwise.
as_mixtime() to coerce objects to mixtime,
mixtime() to construct a mixtime.
is_mixtime(Sys.Date()) is_mixtime(mixtime(Sys.Date()))is_mixtime(Sys.Date()) is_mixtime(mixtime(Sys.Date()))
Test whether elements of a mixtime vector are linear, cyclical, or durations.
time_is_linear(x, ...) time_is_cyclical(x, ...) time_is_duration(x, ...) is_time_linear(x, ...) is_time_cyclical(x, ...) is_time_duration(x, ...)time_is_linear(x, ...) time_is_cyclical(x, ...) time_is_duration(x, ...) is_time_linear(x, ...) is_time_cyclical(x, ...) is_time_duration(x, ...)
x |
A time object (typically a |
... |
Additional arguments for methods. |
These helpers return a logical vector the same length as x identifying the
type of time represented by each element.
A logical vector the same length as x.
t <- c(yearmonth(0), month_of_year(0), months(0L)) time_is_linear(t) time_is_cyclical(t) time_is_duration(t)t <- c(yearmonth(0), month_of_year(0), months(0L)) time_is_linear(t) time_is_cyclical(t) time_is_duration(t)
Builds the function a linear_labels()/cyclical_labels() method is:
assign its result directly, e.g. method(cyclical_labels, list(granule, cycle)) <- label_scheme(...). Three levels, from plain to most irregular:
linear_labels() and cyclical_labels() are S7 generics returning a
granule's label scheme: a plain list describing how its internal position
renders as text and parses back (start, vocab, transform, width,
locale; see label_scheme()).
label_scheme( start = 0L, vocab = NULL, transform = NULL, width = NULL, locale = NULL ) linear_labels(granule, ...) cyclical_labels(granule, cycle, ...)label_scheme( start = 0L, vocab = NULL, transform = NULL, width = NULL, locale = NULL ) linear_labels(granule, ...) cyclical_labels(granule, cycle, ...)
start |
Author-fixed. Raw index 0 displays as |
vocab |
|
transform |
|
width, locale
|
Caller-overridable defaults for |
granule |
A time granule instance (e.g. |
... |
Unused; only present for S7 dispatch. |
cycle |
For |
Plain numeric. No vocab: labels are i + start, optionally
zero-padded to width. The default for most granules (minutes,
seconds).
Named, regular. vocab supplies the names (see vocab_table());
start positions raw index 0 in both the numeric and vocab-indexed
rendering. Covers most named calendar units (months, weekdays).
Named, irregular. transform overrides the plain start shift with
hand-written encode/decode, for cycles where raw index and name
aren't a constant offset apart (e.g. a leap month splitting one name
into two). See "Irregular cycles" below.
A scheme is only consulted for named (label = TRUE) rendering and its
inverse; numeric rendering is always the plain i + start shift (see
linear_labels_format()). Labels that aren't index-shaped at all (e.g.
"1BC") override the generics directly, documented in linear_labels()
instead.
linear_labels_format()/linear_labels_parse() (and their cyclical
counterparts) do the actual rendering/parsing, with the default method
looking up the scheme and applying it. A granule with labels that are
incompatible with label schemes (e.g. 2BC, 1BC, 1, 2, ...) registers a method
directly on those generics instead, skipping the scheme system. See
"Overriding the generics directly" below.
A function function(granule, cycle) list(start =, vocab =, transform =, width =, locale =), assignable directly as a
linear_labels()/cyclical_labels() method. granule/cycle are only
used for dispatch: a scheme describes a granule class, not the instance
a method happens to be called with.
A plain list, as constructed by label_scheme().
vocab is a plain closure, not a shared registry, so two calendar
packages can't collide on it. To add locale support to an existing
granule, redefine the linear_labels()/cyclical_labels() method and
call the previous one for anything you're not changing: the normal S7
rule that the last method(...) <- wins. That needs a hand-written
wrapper rather than assigning label_scheme()'s result directly, since
overriding one field means fetching the old scheme and changing it:
scheme <- cyclical_labels(cal_gregorian$month(1L), cal_gregorian$year(1L))
method(cyclical_labels, list(cal_gregorian$month, cal_gregorian$year)) <-
function(granule, cycle) {
scheme$vocab <- function(type = NULL, locale = NULL) {
if (identical(locale %||% "en-GB", "fr-FR")) {
fr <- list(
wide = c("janvier", "février", "mars", "avril", "mai", "juin",
"juillet", "août", "septembre", "octobre", "novembre", "décembre"),
abbreviated = c("janv.", "févr.", "mars", "avr.", "mai", "juin",
"juil.", "août", "sept.", "oct.", "nov.", "déc.")
)
return(if (is.null(type)) fr else fr[[type]])
}
scheme$vocab(type, locale)
}
scheme
}
Locale tags follow BCP 47 ("en-GB", "fr-FR"), like ICU, stringi and
clock. Type names follow CLDR's wide/abbreviated/narrow, so CLDR data
(e.g. stringi::stri_datetime_symbols()) works with vocab_table()
unchanged. Other type values are allowed too, e.g. "emoji" for lunar
phases, picked at render time via cyclical_labels_format()'s type
argument.
at (in transform's encode/decode, and in
cyclical_labels_format()/cyclical_labels_parse()) is the coarser
granule instance's raw position, not epoch-shifted, with n = 1. It
follows the same convention as chronon_cardinality(). It lets
transform pick the right name when that name depends on which cycle
instance a raw index falls in, e.g. the Hebrew calendar's leap year
splitting "Adar" into "Adar I"/"Adar II":
month_names <- c("Tishrei", "Cheshvan", "Kislev", "Tevet", "Shevat",
"Adar", "Adar I", "Adar II",
"Nisan", "Iyar", "Sivan", "Tammuz", "Av", "Elul")
method(cyclical_labels, list(cal_hebrew$month, cal_hebrew$year)) <- label_scheme(
start = 1L,
vocab = vocab_table(`en-GB` = list(wide = month_names, abbreviated = month_names)),
transform = list(
encode = function(i, at) {
leap <- is_hebrew_leap_year(at)
if (i <= 4L) return(i + 1L)
if (!leap) return(if (i == 5L) 6L else i + 3L)
if (i == 5L) return(7L)
if (i == 6L) return(8L)
i + 2L
},
decode = function(d, at) {
leap <- is_hebrew_leap_year(at)
if (d <= 5L) return(d - 1L)
if (!leap) {
if (d == 6L) return(5L)
if (d %in% c(7L, 8L)) cli::cli_abort("'Adar I'/'Adar II' are not valid outside a leap year.")
return(d - 3L)
}
if (d == 6L) cli::cli_abort("'Adar' is ambiguous in a leap year, use 'Adar I' or 'Adar II'.")
if (d == 7L) return(5L)
if (d == 8L) return(6L)
d - 2L
}
)
)
The aborts in decode() matter: without them, "Adar II" typed in a
common year would fall through to the same offset as plain "Adar" and
silently parse to the wrong month. Only the label layer, which knows
both the text and at, can catch that. transform's leap predicate must
also be the same one chronon_cardinality() uses for this pair; put it
in one shared helper.
linear_labels_format()/linear_labels_parse() are ordinary S7
generics with a default method, not the only place formatting logic can
live. So escaping the scheme system for one granule is just registering
a method directly:
method(linear_labels_format, cal_gregorian$year) <- function(granule, i, ...) {
ifelse(i <= 0L, paste0(-i + 1L, "BC"), i)
}
method(linear_labels_parse, cal_gregorian$year) <- function(granule, ...) {
list(
pattern = "\\d+(?:BC)?",
decode = function(text, at = NULL) {
bc <- grepl("BC$", text)
n <- as.integer(sub("BC$", "", text))
ifelse(bc, 1L - n, n) - chronon_epoch(granule)
}
)
}
decode() needs - chronon_epoch(granule) because this method bypasses
the default, which normally does that step (see linear_labels_format()'s
"Epoch shift" section).
The ... on _format() is not just style: format() forwards whatever
component_helpers' lin()/cyc() were called with (label,
abbreviate, type, width, locale, ...) as named arguments. A
method without ... errors with "unused argument" as soon as a caller
passes something it doesn't declare.
Registering only linear_labels_format() is fine: that's the same "no
parsing yet" state a fresh granule starts in. But registering it without
linear_labels_parse() leaves parsing silently wrong instead of just
missing: text like "1BC" falls through to whatever the granule's
scheme says, usually plain numeric decoding, which doesn't understand
"BC" at all.
linear_labels()/cyclical_labels(), the generics a scheme is
returned from; vocab_table() for the common hand-listed name table
case.
label_scheme() for the fields a method returns;
linear_labels_format()/cyclical_labels_format() for the generics
that interpret it; vocab_table() for the common hand-listed name
table case.
# A scheme for months of the year, using R's localised month names. S7::method(cyclical_labels, list(cal_gregorian$month, cal_gregorian$year)) <- label_scheme( start = 1L, width = 2L, vocab = vocab_table(`en-GB` = list(wide = month.name, abbreviated = month.abb)) )# A scheme for months of the year, using R's localised month names. S7::method(cyclical_labels, list(cal_gregorian$month, cal_gregorian$year)) <- label_scheme( start = 1L, width = 2L, vocab = vocab_table(`en-GB` = list(wide = month.name, abbreviated = month.abb)) )
The generics turning a granule's internal position into display text
(linear_labels_format() for a non-repeating position, e.g. the year;
cyclical_labels_format() for a position within a larger cycle, e.g. the
month within the year) and back (linear_labels_parse()/
cyclical_labels_parse()).
linear_labels_format(granule, ...) cyclical_labels_format(granule, cycle, ...) linear_labels_parse(granule, ...) cyclical_labels_parse(granule, cycle, ...)linear_labels_format(granule, ...) cyclical_labels_format(granule, cycle, ...) linear_labels_parse(granule, ...) cyclical_labels_parse(granule, cycle, ...)
granule |
A time granule object representing the granule (e.g.
|
... |
Passed on to the method. The default method (see below) takes:
|
cycle |
A time granule object representing the cycle (e.g.
|
Each has one default method (on the base mt_unit class) that looks up
the granule's scheme via linear_labels()/cyclical_labels() and
applies it (see label_scheme() for the fields). Calendar authors
usually declare a scheme instead of writing a method here directly.
Writing one directly overrides the generics for labels that aren't
index-shaped at all, see linear_labels()'s "Overriding the generics
directly" section.
Character vector of labels for the time point.
linear_labels_format()'s i arrives already epoch-shifted for display
(chronon_parts() adds chronon_epoch() before calling it, e.g. a
Gregorian year's i is 2024, not 54). The default
linear_labels_parse() method shifts decode()'s output back, by
subtracting chronon_epoch() after the scheme's own decode runs. A
hand-written override method skips this and must do the same
subtraction itself if the granule has a non-zero epoch; see the example
in linear_labels().
linear_labels()/cyclical_labels() for the authoring
interface these generics' default methods interpret.
# Labels for years on a linear axis with(cal_gregorian, linear_labels_format(year(1L), 2020:2025)) # Labels for months in a year with(cal_gregorian, cyclical_labels_format(month(1L), year(1L), 0:11))# Labels for years on a linear axis with(cal_gregorian, linear_labels_format(year(1L), 2020:2025)) # Labels for months in a year with(cal_gregorian, cyclical_labels_format(month(1L), year(1L), 0:11))
linear_time() creates a vector of linear time points with a specified
chronon (smallest time granule). This function is useful for creating custom
time representations that aren't covered by the convenience functions like
yearmonth() or yearweek().
linear_time( data, chronon = time_chronon(data), discrete = TRUE, calendar = time_calendar(data) )linear_time( data, chronon = time_chronon(data), discrete = TRUE, calendar = time_calendar(data) )
data |
Input data to convert to linear time. Can be:
|
chronon |
A time granule expression representing the chronon (smallest
indivisible time granule), evaluated in the context of |
discrete |
Logical. If |
calendar |
Calendar system used to evaluate |
A mixtime time vector containing an mt_linear vector.
new_linear_time_fn() for creating reusable linear time functions
yearmonth(), yearquarter(), year() for Gregorian time representations
yearweek() for ISO 8601 week-based time
cal_gregorian, cal_isoweek for calendar systems
# Hourly time linear_time( Sys.time(), chronon = hour(1L) ) # Monthly time linear_time( Sys.Date(), chronon = month(1L) ) # Discrete vs continuous time linear_time(Sys.time(), chronon = day(1L), discrete = TRUE) linear_time(Sys.time(), chronon = day(1L), discrete = FALSE) # ISO week calendar with week-day structure linear_time( Sys.Date(), chronon = day(1L), calendar = cal_isoweek )# Hourly time linear_time( Sys.time(), chronon = hour(1L) ) # Monthly time linear_time( Sys.Date(), chronon = month(1L) ) # Discrete vs continuous time linear_time(Sys.time(), chronon = day(1L), discrete = TRUE) linear_time(Sys.time(), chronon = day(1L), discrete = FALSE) # ISO week calendar with week-day structure linear_time( Sys.Date(), chronon = day(1L), calendar = cal_isoweek )
Convenience functions for creating common linear time representations. These functions work with different calendar systems and adapt based on the input data's calendar.
year(data, discrete = TRUE, calendar = time_calendar(data), ...) yearquarter(data, discrete = TRUE, calendar = time_calendar(data), ...) yearmonth(data, discrete = TRUE, calendar = time_calendar(data), ...) yearweek(data, discrete = TRUE, calendar = time_calendar(data), ...) date(data, discrete = TRUE, calendar = time_calendar(data), ...) datetime(data, discrete = TRUE, calendar = time_calendar(data), ...)year(data, discrete = TRUE, calendar = time_calendar(data), ...) yearquarter(data, discrete = TRUE, calendar = time_calendar(data), ...) yearmonth(data, discrete = TRUE, calendar = time_calendar(data), ...) yearweek(data, discrete = TRUE, calendar = time_calendar(data), ...) date(data, discrete = TRUE, calendar = time_calendar(data), ...) datetime(data, discrete = TRUE, calendar = time_calendar(data), ...)
data |
A vector of time points (e.g. base::Date, base::POSIXt) |
discrete |
If |
calendar |
A calendar used to evaluate the time units. Defaults to the calendar of the input data. Common options include cal_gregorian and cal_isoweek. |
... |
Additional arguments for |
These functions create linear time representations with different chronons and granules:
year(): Represents time in whole years. The chronon is one year.
yearquarter(): Represents time in quarters, grouped by year. The chronon
is one quarter, with years as the granule.
yearmonth(): Represents time in months, grouped by year. The chronon is
one month, with years as the granule.
yearweek(): Represents time in weeks, grouped by year. The chronon is
one week, with years as the granule. Defaults to ISO 8601 week calendar.
A mixtime time vector containing an mt_linear vector with chronons matching the function used.
These functions adapt to the calendar system of the input data. For example:
year(date("2025-12-29")) returns a Gregorian year
year(yearweek(date("2025-12-29"))) returns an ISO week-based year
You can also explicitly specify a calendar using the calendar argument:
year(date("2025-12-29"), calendar = cal_isoweek)
For more complex time structures, use linear_time() or new_linear_time_fn()
to create custom representations with any combination of chronons and granules.
linear_time() for creating custom linear time representations
new_linear_time_fn() for creating reusable linear time functions
cal_gregorian, cal_isoweek for calendar systems
# Gregorian year year(Sys.Date()) year(Sys.Date(), discrete = FALSE) # ISO week-based year year(yearweek(Sys.Date())) # Year-quarter yearquarter(Sys.Date()) yearquarter(Sys.Date(), discrete = FALSE) # Year-month yearmonth(Sys.Date()) yearmonth(Sys.Date(), discrete = FALSE) # Year-week (ISO 8601) yearweek(Sys.Date()) yearweek(0:52)# Gregorian year year(Sys.Date()) year(Sys.Date(), discrete = FALSE) # ISO week-based year year(yearweek(Sys.Date())) # Year-quarter yearquarter(Sys.Date()) yearquarter(Sys.Date(), discrete = FALSE) # Year-month yearmonth(Sys.Date()) yearmonth(Sys.Date(), discrete = FALSE) # Year-week (ISO 8601) yearweek(Sys.Date()) yearweek(0:52)
A mixtime is a vector which describes a point in time. It uses a calendar definition to translate a vector of numbers into a point in time.
mixtime( data, chronon = time_chronon(data), cycle = time_cycle(data), discrete = TRUE )mixtime( data, chronon = time_chronon(data), cycle = time_cycle(data), discrete = TRUE )
data |
A vector of time values. This can be a character vector (e.g. "2024-01-01"), a numeric vector (e.g. seconds since epoch), or a time class (e.g. Date, POSIXct, yearmonth, etc.). |
chronon |
A time granule object representing the smallest indivisible time granule (chronon) for the mixtime. This is used to interpret the numeric values in |
cycle |
An optional time granule object representing the cycle for cyclical time. This is used to define the repeating cycle for cyclical time representations (e.g. day-of-week, month-of-year). If not provided, the mixtime will be treated as linear time. |
discrete |
A logical indicating whether the time values should be treated as discrete (integer) or continuous (fractional). This affects how numeric values are interpreted and how time arithmetic is performed. The default is |
A mixtime object representing the time values in data according to the specified chronon and cycle.
# Create a mixtime for today mixtime(Sys.Date()) # Create a mixtime for the current date and time mixtime(Sys.time()) # Convert time from tsibble classes to mixtime mixtime(tsibble::yearmonth("2024 Jan")) # Create a mixtime for the time of day (cyclical time) mixtime(Sys.time(), cycle = cal_gregorian$day(1L)) # Specify a timezone for the chronon mixtime(Sys.time(), chronon = cal_gregorian$second(1L, tz = Sys.timezone())) mixtime(Sys.time(), chronon = cal_gregorian$second(1L, tz = "Pacific/Honolulu")) mixtime(Sys.time(), chronon = cal_gregorian$second(1L, tz = "Australia/Melbourne")) # Dates (and all granularities) can have timezones mixtime(Sys.time(), chronon = cal_gregorian$day(1L, tz = Sys.timezone())) mixtime(Sys.time(), chronon = cal_gregorian$day(1L, tz = "Pacific/Honolulu")) mixtime(Sys.time(), chronon = cal_gregorian$day(1L, tz = "Australia/Melbourne")) # Continuous time tracks progress within the chronon mixtime(Sys.time(), chronon = cal_gregorian$day(1L, tz = Sys.timezone()), discrete = FALSE) # Mixtime can combine different granularities and timezones in a vector now <- Sys.time() c( # Datetime (second chronon) in UTC mixtime(now), # Date (minute chronon) in local timezone mixtime(now, chronon = cal_gregorian$minute(1L, tz = Sys.timezone())), # Month (month chronon) in UTC mixtime(now, chronon = cal_gregorian$month(1L)) )# Create a mixtime for today mixtime(Sys.Date()) # Create a mixtime for the current date and time mixtime(Sys.time()) # Convert time from tsibble classes to mixtime mixtime(tsibble::yearmonth("2024 Jan")) # Create a mixtime for the time of day (cyclical time) mixtime(Sys.time(), cycle = cal_gregorian$day(1L)) # Specify a timezone for the chronon mixtime(Sys.time(), chronon = cal_gregorian$second(1L, tz = Sys.timezone())) mixtime(Sys.time(), chronon = cal_gregorian$second(1L, tz = "Pacific/Honolulu")) mixtime(Sys.time(), chronon = cal_gregorian$second(1L, tz = "Australia/Melbourne")) # Dates (and all granularities) can have timezones mixtime(Sys.time(), chronon = cal_gregorian$day(1L, tz = Sys.timezone())) mixtime(Sys.time(), chronon = cal_gregorian$day(1L, tz = "Pacific/Honolulu")) mixtime(Sys.time(), chronon = cal_gregorian$day(1L, tz = "Australia/Melbourne")) # Continuous time tracks progress within the chronon mixtime(Sys.time(), chronon = cal_gregorian$day(1L, tz = Sys.timezone()), discrete = FALSE) # Mixtime can combine different granularities and timezones in a vector now <- Sys.time() c( # Datetime (second chronon) in UTC mixtime(now), # Date (minute chronon) in local timezone mixtime(now, chronon = cal_gregorian$minute(1L, tz = Sys.timezone())), # Month (month chronon) in UTC mixtime(now, chronon = cal_gregorian$month(1L)) )
Generic function to extract the location from objects that have location information.
loc_latitude(x, ...) loc_longitude(x, ...) loc_altitude(x, ...)loc_latitude(x, ...) loc_longitude(x, ...) loc_altitude(x, ...)
x |
An object with location information. |
... |
Additional arguments passed to methods. |
A numeric value representing the location (e.g., longitude, latitude, etc.).
t <- linear_time( 1:3, cal_time_solar$day(1L, lat = -37.8136, lon = 144.9631) ) loc_longitude(t) loc_latitude(t) loc_altitude(t)t <- linear_time( 1:3, cal_time_solar$day(1L, lat = -37.8136, lon = 144.9631) ) loc_longitude(t) loc_latitude(t) loc_altitude(t)
mt_cyclical)A cyclical time value stores an absolute chronon count but means a position
within its cycle (e.g. day_of_week() means a weekday, not a particular
Wednesday). Comparison therefore reduces both operands to their position
within the cycle - the same reduction format() displays - and compares
those:
day_of_week(date("2020-01-15")) == day_of_week(date("2020-01-22")) is
TRUE, since both are a Wednesday.
day_of_year(date("2020-01-15")) == day_of_year(date("2021-01-15")) is
TRUE, since both are the 15th day of their year.
Both operands must share a cycle: a cycle is a modulus rather than a unit,
so there is no meaningful common cycle between (say) a weekday and a
day-of-year, and comparing them is an error. Differing chronons within a
shared cycle are reconciled as they are for mt_linear:
both positions are expressed in the finest common chronon, and a discrete
value spans the closed interval of its chronon, so
a == b iff start(a) == start(b) and end(a) == end(b)
a < b/a > b iff a/b ends at or before the other begins (a gap, or
just adjacency - see mt_linear-compare for why this includes adjacency)
a <= b iff end(a) <= end(b), a >= b iff start(a) >= start(b)
As for mt_linear, this is not a total order when chronons differ. Ordering
follows the position within the cycle (so Mon < Wed); the cycle's wrap-around
is not treated as circular.
## S4 method for signature 'mt_cyclical' e1 == e2 ## S4 method for signature 'mt_cyclical' e1 != e2 ## S4 method for signature 'mt_cyclical' e1 < e2 ## S4 method for signature 'mt_cyclical' e1 <= e2 ## S4 method for signature 'mt_cyclical' e1 > e2 ## S4 method for signature 'mt_cyclical' e1 >= e2## S4 method for signature 'mt_cyclical' e1 == e2 ## S4 method for signature 'mt_cyclical' e1 != e2 ## S4 method for signature 'mt_cyclical' e1 < e2 ## S4 method for signature 'mt_cyclical' e1 <= e2 ## S4 method for signature 'mt_cyclical' e1 > e2 ## S4 method for signature 'mt_cyclical' e1 >= e2
e1, e2
|
|
A logical vector.
mt_duration)A duration is a scalar magnitude of time measured in a given chronon (e.g.
days(3)), with no reference to a point in time. Comparing two durations is
therefore a plain magnitude comparison, once both operands have been
expressed in a common chronon:
a == b iff the two magnitudes are equal in their common chronon
a < b, a <= b, a > b, a >= b compare the magnitudes directly
Unlike mt_linear comparison there is no interval/span to consider, so this
is a total order. When both operands already share a chronon the magnitudes
are compared as-is; otherwise both are scaled to their finest common chronon
(the same scaling used when combining durations arithmetically, see
duration_combine()).
## S4 method for signature 'mt_duration' e1 == e2 ## S4 method for signature 'mt_duration' e1 != e2 ## S4 method for signature 'mt_duration' e1 < e2 ## S4 method for signature 'mt_duration' e1 <= e2 ## S4 method for signature 'mt_duration' e1 > e2 ## S4 method for signature 'mt_duration' e1 >= e2## S4 method for signature 'mt_duration' e1 == e2 ## S4 method for signature 'mt_duration' e1 != e2 ## S4 method for signature 'mt_duration' e1 < e2 ## S4 method for signature 'mt_duration' e1 <= e2 ## S4 method for signature 'mt_duration' e1 > e2 ## S4 method for signature 'mt_duration' e1 >= e2
e1, e2
|
|
A logical vector.
mt_linear)Discrete linear time values represent a closed interval spanning their
chronon (e.g. year(2020) spans every instant from the start of 2020 to
the end of 2020), while continuous linear time values represent a single
instant. Comparing two mt_linear vectors therefore compares the
start/end instants of the (possibly zero-width) interval each value
represents:
a == b iff start(a) == start(b) and end(a) == end(b)
a < b iff end(a) <= start(b) (i.e. before with or without a gap)
a > b iff start(a) >= end(b) (i.e. after with or without a gap)
a <= b iff end(a) <= end(b) (right-bound comparison)
a >= b iff start(a) >= start(b) (left-bound comparison)
This is not a total order for comparisons between time points at different
granularities: <=/>= are not shorthand for (< or ==)/(> or ==).
For example, yearquarter("2020 Q3") <= year("2020") is TRUE despite
yearquarter("2020 Q3") < year("2020") and
yearquarter("2020 Q3") == year("2020") being FALSE.
The inequality operators </> and <=/>= are useful conjugations of
Allen's interval algebra for common data manipulation needs. The complete set
of Allen's 13 base relations are documented in allen-interval-algebra.
## S4 method for signature 'mt_linear' e1 == e2 ## S4 method for signature 'mt_linear' e1 != e2 ## S4 method for signature 'mt_linear' e1 < e2 ## S4 method for signature 'mt_linear' e1 <= e2 ## S4 method for signature 'mt_linear' e1 > e2 ## S4 method for signature 'mt_linear' e1 >= e2## S4 method for signature 'mt_linear' e1 == e2 ## S4 method for signature 'mt_linear' e1 != e2 ## S4 method for signature 'mt_linear' e1 < e2 ## S4 method for signature 'mt_linear' e1 <= e2 ## S4 method for signature 'mt_linear' e1 > e2 ## S4 method for signature 'mt_linear' e1 >= e2
e1, e2
|
|
A logical vector.
The mt_time family are the S7 vector classes that store time points as a
numeric count of chronons. mt_time is the (internal) base class carrying
the chronon property; the common modes of time are:
mt_linear - linear time points, typically produced with linear_time().
mt_cyclical - cyclical time points with additional cycle granule,
typically produced with cyclical_time().
mt_duration - time durations, typically produced with duration().
The underlying data can be either integer (discrete time) or double
(continuous time). The chronon (and, for mt_cyclical, the cycle) are
time granules, the result from a mt_unit object.
mt_linear(.data = integer(), chronon = mt_unit(1L)) mt_duration(.data = integer(), chronon = mt_unit(1L)) mt_cyclical(.data = integer(), chronon = mt_unit(1L), cycle = mt_unit(1L))mt_linear(.data = integer(), chronon = mt_unit(1L)) mt_duration(.data = integer(), chronon = mt_unit(1L)) mt_cyclical(.data = integer(), chronon = mt_unit(1L), cycle = mt_unit(1L))
.data |
A numeric vector of chronon counts (integer or double). |
chronon, cycle
|
Time granules (mt_unit objects) giving the unit of the
chronon counts and, for |
An S7 class object (used for method dispatch), or a time vector when called as a constructor.
mt_linear(), mt_duration(), and mt_cyclical() to construct
time vectors, and mt_unit for the granule type stored in chronon/cycle.
This class is the primitive class for time units, and should
be extended from when creating new time units. A new class
is typically created with S7 using:
S7::new_class("tu_***", parent = mt_tz_unit)
mt_unit(n = 1L) mt_loc_unit(n = 1L, lat = naive_loc, lon = naive_loc, alt = naive(0)) mt_tz_unit(n = 1L, tz = naive_tz)mt_unit(n = 1L) mt_loc_unit(n = 1L, lat = naive_loc, lon = naive_loc, alt = naive(0)) mt_tz_unit(n = 1L, tz = naive_tz)
n |
The step size of time granule. For example, |
lat |
Numeric. Latitude in decimal degrees. Range: -90 to 90.
Default: naive location (astronomical calculations require |
lon |
Numeric. Longitude in decimal degrees. Range: -180 to 180.
Default: naive location (astronomical calculations require |
alt |
Numeric. Altitude in meters above sea level. Default: 0 (sea level). |
tz |
The timezone name for the unit (valid units can be found with |
Time units are the building blocks of calendars in mixtime. Each unit
represents a specific temporal component (e.g., day, month, year) and
can be combined using new_calendar() to create a calendar system.
When creating custom calendars, define time unit classes that inherit
from either mt_unit (for standard units) or mt_tz_unit (for
timezone-aware units), then pass them as named arguments to
new_calendar(). The calendar will use these names to create
constructor functions accessible via $ notation (e.g., calendar$day(1L)).
A time granule object of class mt_unit
Time units enable calendar arithmetic through key generic methods that should be implemented for custom time units:
chronon_cardinality_fixed(x, y) - Returns the number of unit x
granules that fit within one unit y granule, for relationships that are
a constant, context-independent number (e.g., 7 days per week, 24 hours
per day). Prefer this over chronon_cardinality() whenever the
relationship does not depend on at, since it is also used to determine
which relationships are safe to use for chronon_divmod()'s graph
traversal.
chronon_cardinality(x, y, at) - Returns the number of x granule
that fit within one y granule. This is variable based on at (e.g.,
28-31 days per month). Only implement this directly (rather than
chronon_cardinality_fixed()) when the relationship genuinely depends on
at, and pair it with a direct chronon_divmod() method so that the
relationship remains reachable during graph traversal.
chronon_divmod(x, from, to) - Converts time point x from granules of
from to granules of to, returning a list with div (the quotient)
and mod. This enables conversions between granules that have
variable cardinality (e.g., the date 2020-03-23 to the month 2020-03).
All conversions should be based on chronons since epoch (1970-01-01),
in the UTC time zone.
These methods work together to enable mixtime to perform calendar-aware arithmetic, understanding that months have variable lengths and handling timezone-aware conversions.
new_calendar() for creating calendars from time units
# Create a timezone-aware unit class # Use these units to create a calendar my_calendar <- new_calendar( day = S7::new_class("tu_my_day", parent = mt_unit), month = S7::new_class("tu_my_month", parent = mt_tz_unit), class = "my_calendar" ) # Access unit constructors from the calendar my_calendar$day(1L) my_calendar$month(3L, tz = "America/New_York")# Create a timezone-aware unit class # Use these units to create a calendar my_calendar <- new_calendar( day = S7::new_class("tu_my_day", parent = mt_unit), month = S7::new_class("tu_my_month", parent = mt_tz_unit), class = "my_calendar" ) # Access unit constructors from the calendar my_calendar$day(1L) my_calendar$month(3L, tz = "America/New_York")
Define a new calendar as a collection of time units. Calendars are the foundation for representing dates and times in terms of human-readable components like years, months, days, hours, minutes, and seconds. Each calendar is defined by specifying the time units it contains, which determine how time values can be interpreted and manipulated.
new_calendar(..., inherit = NULL, class = character())new_calendar(..., inherit = NULL, class = character())
... |
Named time unit class definitions. Each argument should be a
time unit class (typically created with |
inherit |
Optional calendar to inherit time units from. Units
defined in |
class |
Character vector of additional classes for the calendar object. |
Time units are typically S7 class definitions that inherit from mt_unit
for standard units, mt_tz_unit for timezone-aware units (civil time), or
mt_loc_unit for location-aware units (astronomical time). The calendar
object provides a namespace for accessing these unit constructors and
defines the relationships between them for calendar arithmetic.
A calendar object of class c(class, "mt_calendar"), consisting of a
named list containing the specified time unit classes.
linear_time(), cyclical_time()
# Create a simple calendar with year and month units # (inheriting from civil time units for day, hour, minute, second, ...) cal_simple <- new_calendar( year = new_time_unit("tu_year", parent = mt_tz_unit), month = new_time_unit("tu_month", parent = mt_tz_unit), inherit = cal_time_civil, class = "cal_simple" ) # Create time granules from the calendar cal_simple$year(1L) cal_simple$month(1L)# Create a simple calendar with year and month units # (inheriting from civil time units for day, hour, minute, second, ...) cal_simple <- new_calendar( year = new_time_unit("tu_year", parent = mt_tz_unit), month = new_time_unit("tu_month", parent = mt_tz_unit), inherit = cal_time_civil, class = "cal_simple" ) # Create time granules from the calendar cal_simple$year(1L) cal_simple$month(1L)
new_cyclical_time_fn() creates a cyclical time function for a specified
chronon and cycle. The cycle is the larger time granule that defines the time
period over which the chronon loops (e.g., a week). The chronon is the smaller
time granule that iterates within each cycle (e.g., a day). Combined, these two
granules form a cyclical time relationship (e.g., day of the week).
new_cyclical_time_fn(chronon, cycle, default_calendar = cal_gregorian)new_cyclical_time_fn(chronon, cycle, default_calendar = cal_gregorian)
chronon |
A time granule object representing the chronon (e.g., |
cycle |
A time granule object representing the cycle (e.g., |
default_calendar |
A default calendar used to find the time units for
conversion if they don't exist in the calendar of the input data (e.g., |
A function used to create cyclical time points with a specific chronon and cycle.
day_of_week <- new_cyclical_time_fn(day(1L), week(1L), default_calendar = cal_isoweek) day_of_week(Sys.Date()) month_of_year <- new_cyclical_time_fn(month(1L), year(1L)) month_of_year(Sys.Date())day_of_week <- new_cyclical_time_fn(day(1L), week(1L), default_calendar = cal_isoweek) day_of_week(Sys.Date()) month_of_year <- new_cyclical_time_fn(month(1L), year(1L)) month_of_year(Sys.Date())
new_duration_fn() creates a duration function for a specified chronon. A
chronon is the smallest indivisible time unit (e.g., days, months) that
defines what the numeric magnitudes in the resulting duration vector
represent.
new_duration_fn(chronon, default_calendar = cal_gregorian)new_duration_fn(chronon, default_calendar = cal_gregorian)
chronon |
A bare call for a time unit object representing the chronon
(e.g., |
default_calendar |
A default calendar used to resolve the time units
if they don't exist in the calendar of the input data (e.g.,
|
A function used to create duration vectors with a specific chronon. The returned function accepts:
dataA numeric vector of duration magnitudes.
calendarA calendar system used to evaluate chronon. Defaults
to time_calendar(data).
...Additional arguments passed to the chronon (e.g., tz for
timezones).
duration() for creating duration vectors directly
cal_gregorian, cal_isoweek for calendar systems
# Create a months duration function months <- new_duration_fn(month(1L), default_calendar = cal_gregorian) months(1:6) # Create a days duration function days <- new_duration_fn(day(1L), default_calendar = cal_gregorian) days(1:7)# Create a months duration function months <- new_duration_fn(month(1L), default_calendar = cal_gregorian) months(1:6) # Create a days duration function days <- new_duration_fn(day(1L), default_calendar = cal_gregorian) days(1:7)
new_linear_time_fn() creates a linear time function for a specified
chronon. A chronon is the smallest indivisible time granule (e.g., days,
hours).
new_linear_time_fn(chronon, default_calendar = cal_gregorian)new_linear_time_fn(chronon, default_calendar = cal_gregorian)
chronon |
A bare call for a time granule object representing the chronon
(e.g., |
default_calendar |
A default calendar used to find the time units for
conversion if they don't exist in the calendar of the input data (e.g.,
|
A function used to create linear time points with a specific chronon.
# Linear time with 1 month granules as the chronon ym <- new_linear_time_fn(month(1L)) ym(Sys.Date()) # Linear time with 1 day granules as the chronon yd <- new_linear_time_fn(day(1L)) yd(Sys.Date()) # Linear time with 1 week granules as the chronon, using the ISO week calendar yw <- new_linear_time_fn(week(1L), default_calendar = cal_isoweek) yw(Sys.Date()) # Linear time with 1 hour granules as the chronon ymd_h <- new_linear_time_fn(hour(1L)) ymd_h(Sys.time())# Linear time with 1 month granules as the chronon ym <- new_linear_time_fn(month(1L)) ym(Sys.Date()) # Linear time with 1 day granules as the chronon yd <- new_linear_time_fn(day(1L)) yd(Sys.Date()) # Linear time with 1 week granules as the chronon, using the ISO week calendar yw <- new_linear_time_fn(week(1L), default_calendar = cal_isoweek) yw(Sys.Date()) # Linear time with 1 hour granules as the chronon ymd_h <- new_linear_time_fn(hour(1L)) ymd_h(Sys.time())
Creates a mixtime vector, which can contain time points of different
granularities (e.g. monthly and quarterly) in a single vector via vecvec.
new_mixtime(x = mt_linear())new_mixtime(x = mt_linear())
x |
A mixtime time vector (e.g. created with |
A mixtime object, which allows mixed-type time vectors to coexist in a single vector.
new_time() was the low-level constructor for mt_time vectors. It is now
defunct; call the concrete time class constructors directly instead:
mt_linear() for linear time, mt_duration() for durations, and
mt_cyclical() for cyclical time.
new_time(x = integer(), chronon = mt_unit(1L), cycle = NULL, class = NULL)new_time(x = integer(), chronon = mt_unit(1L), cycle = NULL, class = NULL)
x, chronon, cycle, class
|
Ignored. |
Define a new S7 class representing a time unit for use in a mixtime calendar.
Time units are the building blocks of calendars: each unit represents a
specific temporal component (e.g., day, month, year) and carries a step size
n. Units are combined via new_calendar() to form a complete calendar
system.
new_time_unit( name, parent = mt_unit, package = topNamespaceName(parent.frame()), properties = list(), abstract = FALSE, constructor = NULL, validator = NULL )new_time_unit( name, parent = mt_unit, package = topNamespaceName(parent.frame()), properties = list(), abstract = FALSE, constructor = NULL, validator = NULL )
name |
A string naming the new S7 class (e.g., |
parent |
The parent S7 class. Should be one of |
package |
A string giving the package name that owns the class. Defaults to the name of the calling namespace, so typically does not need to be set explicitly. |
properties |
A named list of additional |
abstract |
Logical. If |
constructor |
A function to use as the class constructor, or |
validator |
A function of one argument ( |
Choose the parent class based on the type of time the unit represents:
mt_unit — abstract or calendar-only time (no timezone or location
context; e.g., Gregorian year or ISO week).
mt_tz_unit — civil time with a timezone (e.g., a clock hour that
needs tz to resolve wall-clock ambiguity).
mt_loc_unit — astronomical time with a geographic location (e.g., a
solar day tied to observer longitude/latitude).
An S7 class object, as returned by S7::new_class().
mt_unit, mt_tz_unit, mt_loc_unit for the base classes to
inherit from.
new_calendar() for assembling time units into a calendar.
S7::new_class() for the underlying S7 class constructor.
# An abstract unit with no properties tu_my_seq <- new_time_unit("tu_my_seq", parent = mt_unit) # A civil-time unit with an extra property tu_my_quarter <- new_time_unit( "tu_my_quarter", parent = mt_tz_unit, properties = list( fiscal = S7::new_property(S7::class_logical, default = FALSE) ) )# An abstract unit with no properties tu_my_seq <- new_time_unit("tu_my_seq", parent = mt_unit) # A civil-time unit with an extra property tu_my_quarter <- new_time_unit( "tu_my_quarter", parent = mt_tz_unit, properties = list( fiscal = S7::new_property(S7::class_logical, default = FALSE) ) )
Combines one or more format strings into a character vector for use as
the format argument of time_parse(). When multiple format strings are
given, time_parse() tries each in turn and keeps whichever parses the
most values, so parse_format() is the usual way to build up a set of
candidates to try (it's also how chronon_parse_linear()/
chronon_parse_cyclical() methods build theirs). It can optionally mark
its candidates as using regex syntax rather than literal text; see the
regex argument below.
parse_format(..., regex = FALSE)parse_format(..., regex = FALSE)
... |
Format strings, as for the |
regex |
Whether the literal (non-token) text in |
A character vector of format strings suitable for time_parse(),
with a "regex" attribute for the regex argument the parser.
time_parse() for using the result as format,
chronon_parse_linear()/chronon_parse_cyclical() for calendar-specific
candidates built this way.
parse_format("{lin(year)}-{cyc(month, year)}-{cyc(day, month)}") # Multiple candidates are tried in turn, keeping whichever parses most values parse_format( "{lin(year)}-{cyc(month, year)}-{cyc(day, month)}", "{lin(year)}/{cyc(month, year)}/{cyc(day, month)}" ) # regex = TRUE treats the surrounding text as regular expression syntax parse_format( "{lin(year)}[/-]{cyc(month, year)}[/-]{cyc(day, month)}", regex = TRUE )parse_format("{lin(year)}-{cyc(month, year)}-{cyc(day, month)}") # Multiple candidates are tried in turn, keeping whichever parses most values parse_format( "{lin(year)}-{cyc(month, year)}-{cyc(day, month)}", "{lin(year)}/{cyc(month, year)}/{cyc(day, month)}" ) # regex = TRUE treats the surrounding text as regular expression syntax parse_format( "{lin(year)}[/-]{cyc(month, year)}[/-]{cyc(day, month)}", regex = TRUE )
Create regular sequences of time values. This method handles both linear time sequences (dates, date-times) and cyclical time sequences (day of week, month of year).
## S3 method for class ''mixtime::mixtime'' seq(...) ## S3 method for class ''mixtime::mt_time'' seq( from, to, by, length.out = NULL, along.with = NULL, on_invalid = getOption("mixtime.on_invalid", "clamp"), ... )## S3 method for class ''mixtime::mixtime'' seq(...) ## S3 method for class ''mixtime::mt_time'' seq( from, to, by, length.out = NULL, along.with = NULL, on_invalid = getOption("mixtime.on_invalid", "clamp"), ... )
... |
Additional arguments passed to the underlying sequence method. |
from |
Starting value of the sequence. |
to |
End value of the sequence (if provided). |
by |
Increment of the sequence. Can be:
|
length.out |
Desired length of the sequence (alternative to |
along.with |
Take the length from this argument (alternative to |
on_invalid |
How to handle time points that don't exist, either
because they overflow the cycle when using a
This is relevant when the starting time point has an offset that doesn't
exist in all cycles. For example, starting on day 31 with If neither |
For linear time types (Date, POSIXct, yearmonth, etc.), sequences progress forward or backward in time. For cyclical time types (month_of_year, day_of_week, etc.), sequences wrap around cyclically.
Each time point is from (or to, if from is missing) shifted by a whole
number of by steps, matching from + duration(k, by). For time-zone-aware times, steps of a day or
longer keep the local clock time, while shorter steps (e.g. hours) are real
time across daylight saving changes.
A mixtime vector containing the sequence.
# Linear time sequences with integer by seq(yearmonth("2020 Jan"), yearmonth("2020 Dec")) seq(yearquarter("2020 Q1"), length.out = 5, by = 3) # Linear time sequences with string intervals seq(date("2020-01-01"), date("2020-12-31"), by = "1 month") seq(yearmonth("2020 Jan"), yearmonth("2025 Jan"), by = "1 year") seq(date("2020-01-01"), length.out = 10, by = "2 weeks") # Linear time sequences incrementing by time granules seq(yearmonth("2020 Jan"), yearmonth(("2020 Dec")), by = cal_gregorian$month(2L)) seq(date("2020-01-01"), length.out = 5, by = cal_gregorian$year(1L)) seq(date("2020-01-01"), date("2020-01-31"), by = cal_gregorian$day(7L)) # Handling invalid dates with on_invalid seq(date("2020-01-31"), length.out = 3, by = "1 month") # warns, uses clamp seq(date("2020-01-31"), length.out = 3, by = "1 month", on_invalid = "clamp") seq(date("2020-01-31"), length.out = 3, by = "1 month", on_invalid = "next") seq(date("2020-01-31"), length.out = 3, by = "1 month", on_invalid = "overflow") # Cyclical time sequences seq(month_of_year(0L), month_of_year(11L)) seq(day_of_week(0L), day_of_week(6L), by = 1)# Linear time sequences with integer by seq(yearmonth("2020 Jan"), yearmonth("2020 Dec")) seq(yearquarter("2020 Q1"), length.out = 5, by = 3) # Linear time sequences with string intervals seq(date("2020-01-01"), date("2020-12-31"), by = "1 month") seq(yearmonth("2020 Jan"), yearmonth("2025 Jan"), by = "1 year") seq(date("2020-01-01"), length.out = 10, by = "2 weeks") # Linear time sequences incrementing by time granules seq(yearmonth("2020 Jan"), yearmonth(("2020 Dec")), by = cal_gregorian$month(2L)) seq(date("2020-01-01"), length.out = 5, by = cal_gregorian$year(1L)) seq(date("2020-01-01"), date("2020-01-31"), by = cal_gregorian$day(7L)) # Handling invalid dates with on_invalid seq(date("2020-01-31"), length.out = 3, by = "1 month") # warns, uses clamp seq(date("2020-01-31"), length.out = 3, by = "1 month", on_invalid = "clamp") seq(date("2020-01-31"), length.out = 3, by = "1 month", on_invalid = "next") seq(date("2020-01-31"), length.out = 3, by = "1 month", on_invalid = "overflow") # Cyclical time sequences seq(month_of_year(0L), month_of_year(11L)) seq(day_of_week(0L), day_of_week(6L), by = 1)
This S7 generic function extracts the calendar system from a time object. The calendar defines the collection of time units (years, months, days, etc.) used to interpret the time representation.
time_calendar(x, ...)time_calendar(x, ...)
x |
A time object (e.g., base::Date, base::POSIXct, |
... |
Additional arguments for methods. |
A calendar object (e.g., cal_gregorian, cal_isoweek)
# The calendar of a Date object is the Gregorian calendar time_calendar(Sys.Date()) # The calendar of a POSIXct object is also Gregorian time_calendar(Sys.time()) # The calendar of a yearweek object is the ISO week calendar time_calendar(yearweek(Sys.Date())) # A mixed time object returns a list of calendars time_calendar(c(yearmonth(Sys.Date()), Sys.Date()))# The calendar of a Date object is the Gregorian calendar time_calendar(Sys.Date()) # The calendar of a POSIXct object is also Gregorian time_calendar(Sys.time()) # The calendar of a yearweek object is the ISO week calendar time_calendar(yearweek(Sys.Date())) # A mixed time object returns a list of calendars time_calendar(c(yearmonth(Sys.Date()), Sys.Date()))
This S7 generic function extracts the chronon (the smallest time granule) from a time object, such as continuous time or cyclical time representations.
time_chronon(x, ...)time_chronon(x, ...)
x |
A time object (e.g., base::Date, base::POSIXct, |
... |
Additional arguments for methods. |
For base::Date and base::POSIXct objects the chronon is identified from the greatest common divisor of the intervals between observations, in the same way as a tsibble's interval. For example, hourly datetimes have a 1 hour chronon rather than 1 second. A multiple of a unit (e.g. 3 hours) is only used if every observation falls on a boundary of that chronon; otherwise a single unit is used so that no information is lost when converting.
A time duration() vector representing the chronon of each
value (e.g., days(1L)).
# The chronon of a Date or POSIXct object is identified from the interval # between observations (as with tsibble's interval) time_chronon(Sys.Date() + 0:2) time_chronon(as.POSIXct("2024-01-01", tz = "UTC") + 3600 * 0:2) # Without an interval, the chronon of a Date is 1 day and a POSIXct is 1 second time_chronon(Sys.Date()) time_chronon(Sys.time()) # The chronon of a continuous time year and month is 1 month time_chronon(yearmonth(Sys.Date())) # The common chronon of a mixed time object is the finest chronon time_chronon(c(yearmonth(Sys.Date()), Sys.Date()))# The chronon of a Date or POSIXct object is identified from the interval # between observations (as with tsibble's interval) time_chronon(Sys.Date() + 0:2) time_chronon(as.POSIXct("2024-01-01", tz = "UTC") + 3600 * 0:2) # Without an interval, the chronon of a Date is 1 day and a POSIXct is 1 second time_chronon(Sys.Date()) time_chronon(Sys.time()) # The chronon of a continuous time year and month is 1 month time_chronon(yearmonth(Sys.Date())) # The common chronon of a mixed time object is the finest chronon time_chronon(c(yearmonth(Sys.Date()), Sys.Date()))
time_components() decomposes a time vector into its constituent parts using
dplyr::mutate()-like semantics. Each named expression is built from the
lin() and cyc() helpers (the same vocabulary used in format() strings)
and produces a component time vector:
time_components(x, ..., calendar = time_calendar(x))time_components(x, ..., calendar = time_calendar(x))
x |
A |
... |
Named expressions using |
calendar |
Calendar system used to resolve granule names, overlaid on the
calendar of |
lin(<granule>) extracts a linear component (a non-repeating count,
e.g. the year), returning a linear time vector.
cyc(<granule>, <cycle>) extracts a cyclical component (a repeating
position within a larger cycle, e.g. the month within the year), returning a
cyclical time vector.
All requested components are computed together in a single decomposition of
the underlying time vector (via chronon_parts()), reusing the shared
recursive chronon_divmod() results rather than converting each component
independently.
A data frame with one column per requested component. lin() columns
are linear (mt_linear) time vectors and cyc() columns are cyclical
(mt_cyclical) time vectors.
lin() and cyc() for the component helpers, linear_time() and
cyclical_time() for constructing individual component vectors, and
format() for the string counterpart of this interface.
t <- yearmonth(as.Date("2026-02-14") + c(0, 40, 400)) # Extract the year (linear) and month-of-year (cyclical) time_components(t, yr = lin(year), mth = cyc(month, year)) # Components can be named automatically from the expression time_components(as.Date("2025-12-15") + 0:3, cyc(day, cal_isoweek$week))t <- yearmonth(as.Date("2026-02-14") + c(0, 40, 400)) # Extract the year (linear) and month-of-year (cyclical) time_components(t, yr = lin(year), mth = cyc(month, year)) # Components can be named automatically from the expression time_components(as.Date("2025-12-15") + 0:3, cyc(day, cal_isoweek$week))
time_compose() is the inverse of time_components(): given a set of
lin()/cyc() components it reconstructs the corresponding time points.
Each component is either a two-sided formula pairing a spec with its value,
or an already-tagged linear/cyclical time vector (e.g. produced by
linear_time(), cyclical_time(), or a time_components() column).
time_compose(..., discrete = TRUE, calendar = cal_gregorian)time_compose(..., discrete = TRUE, calendar = cal_gregorian)
... |
Components used to build the time point. Each element is either: |
discrete |
Logical. If |
calendar |
Calendar used to resolve bare granule names in |
A lin() component (the anchor), when supplied, fixes the absolute
position at some granule (e.g. the year). Every other component must be
cyc(), chaining without gaps or branches from the anchor down to the
target chronon: each cycle must equal another component's chronon exactly.
With no lin() anchor, every component must be cyc(), chained the same
way but rooted at whichever component's cycle isn't itself another
component's chronon. The result is cyclical time tagged with that root's
cycle: cyc(month, year) ~ 3 alone matches month_of_year() for any
March; chaining cyc(day, month) ~ 15 onto it collapses to one (day,
year) pair, day-of-year 74, matching day_of_year() for 15 March.
Values of linear and cyclical components are specified on the right-hand-side
of the formula. A lin() value is the real-world count (e.g. the literal
year 1980); a cyc() value is the 1-indexed position within the cycle
(e.g. cyc(month, year) ~ 3 is the 3rd month, March), matching everyday
counting rather than the raw 0-indexed position time_components() uses
internally.
A mixtime time vector, at the finest chronon reached by the
chain (or the root's own chronon, if only one component is given).
Linear with a lin() anchor, cyclical otherwise.
time_components() for the inverse operation, lin()/cyc() for
the component vocabulary shared with time_components() and format().
# cyc() values are 1-indexed positions: month 3 is March, day 15 is the 15th time_compose(lin(year) ~ 1980, cyc(month, year) ~ 3, cyc(day, month) ~ 15) # A lin() anchor alone is a valid (coarser) time point time_compose(lin(year) ~ 1980) # No lin() anchor: composes cyclical time time_compose(cyc(month, year) ~ 3) # Chaining collapses to one (chronon, cycle) pair: day 15 of month 3 # becomes day-of-year 74 time_compose(cyc(day, month) ~ 15, cyc(month, year) ~ 3) # Round-tripping through time_components() parts <- time_components(as.Date("2024-03-15"), yr = lin(year), mth = cyc(month, year)) with(parts, time_compose(yr, mth)) # Multi-unit (self-referencing) cycles: the 3rd month (1-indexed) of the # 4th 3-month block since epoch (block 3 = months 9-11 -> December 1970) time_compose(lin(month(3L)) ~ 3, cyc(month(1L), month(3L)) ~ 3)# cyc() values are 1-indexed positions: month 3 is March, day 15 is the 15th time_compose(lin(year) ~ 1980, cyc(month, year) ~ 3, cyc(day, month) ~ 15) # A lin() anchor alone is a valid (coarser) time point time_compose(lin(year) ~ 1980) # No lin() anchor: composes cyclical time time_compose(cyc(month, year) ~ 3) # Chaining collapses to one (chronon, cycle) pair: day 15 of month 3 # becomes day-of-year 74 time_compose(cyc(day, month) ~ 15, cyc(month, year) ~ 3) # Round-tripping through time_components() parts <- time_components(as.Date("2024-03-15"), yr = lin(year), mth = cyc(month, year)) with(parts, time_compose(yr, mth)) # Multi-unit (self-referencing) cycles: the 3rd month (1-indexed) of the # 4th 3-month block since epoch (block 3 = months 9-11 -> December 1970) time_compose(lin(month(3L)) ~ 3, cyc(month(1L), month(3L)) ~ 3)
This S7 generic function extracts the cycle (the cyclical time granule) from a time object, such as cyclical time representations.
time_cycle(x, ...)time_cycle(x, ...)
x |
A time object (e.g., base::Date, base::POSIXct, |
... |
Additional arguments for methods. |
A time duration() object representing the cycle of each value
(e.g. weeks(1L)), or NA if the object has no cyclical component.
# Non-cyclical objects return NA time_cycle(Sys.Date()) # The cycle of a cyclical time object time_cycle(month_of_year(Sys.Date()))# Non-cyclical objects return NA time_cycle(Sys.Date()) # The cycle of a cyclical time object time_cycle(month_of_year(Sys.Date()))
time_is_complete_at() tests, for each element of a mixtime vector, whether
the coarser granule that element falls into is fully observed by the vector
as a whole – that is, whether every finer chronon making up that granule is
present somewhere in x.
time_is_complete_at(x, granule, ...)time_is_complete_at(x, granule, ...)
x |
A time object (typically a |
granule |
The time granule whose precision to test, given as a granule
generator (e.g. |
... |
Additional arguments for methods. |
Unlike time_is_determinate_at(), completeness is a collective property: an
element is TRUE only when the other elements needed to fill its granule are
also present. For example, in year(1L) the months of 2020 Jan : 2020 Oct
are all FALSE (November and December are missing, so 2020 is incomplete),
whereas in 2020 Jan : 2021 Mar the twelve months of 2020 are TRUE (they
complete 2020) while the three months of 2021 remain FALSE.
A granule equal to x's own chronon is completed by each point on its own
(TRUE). A granule finer than x cannot be completed by coarser points
(FALSE). Missing (NA) and infinite times give NA.
Completeness is only defined within a single time granularity. Mixed-type
mixtime vectors (e.g. months alongside days) are not yet supported and
raise an error.
A logical vector the same length as x.
# 2020 Jan : 2020 Oct does not complete the year -> all FALSE time_is_complete_at(yearmonth(as.Date("2020-01-01")) + 0:9, cal_gregorian$year(1L)) # 2020 Jan : 2021 Mar completes 2020 (TRUE) but not 2021 (FALSE) time_is_complete_at(yearmonth(as.Date("2020-01-01")) + 0:14, cal_gregorian$year(1L))# 2020 Jan : 2020 Oct does not complete the year -> all FALSE time_is_complete_at(yearmonth(as.Date("2020-01-01")) + 0:9, cal_gregorian$year(1L)) # 2020 Jan : 2021 Mar completes 2020 (TRUE) but not 2021 (FALSE) time_is_complete_at(yearmonth(as.Date("2020-01-01")) + 0:14, cal_gregorian$year(1L))
time_is_determinate_at() tests, for each element of a mixtime vector, whether
the time point is well-defined at the precision of granule.
time_is_determinate_at(x, granule, ...)time_is_determinate_at(x, granule, ...)
x |
A time object (typically a |
granule |
The time granule whose precision to test, given as a granule
generator (e.g. |
... |
Additional arguments for methods. |
Discrete (integer) time cannot resolve a granule finer than its own chronon (a
year() has no determinate month), so those elements are FALSE. Continuous
(fractional) time tracks progress within its chronon and so resolves finer
granules exactly (0% through 2020 is 0% through January), giving TRUE.
Coarser-or-equal granules are always determinate. Missing (NA) and infinite
times give NA.
A logical vector the same length as x.
# Discrete: a year has no determinate month time_is_determinate_at(year(2020L), cal_gregorian$month(1L)) # Continuous: 0% through 2020 is 0% through January time_is_determinate_at(year(2020), cal_gregorian$month(1L)) # A coarser granule is always determinate time_is_determinate_at(yearmonth(as.Date("2020-02-01")), cal_gregorian$year(1L))# Discrete: a year has no determinate month time_is_determinate_at(year(2020L), cal_gregorian$month(1L)) # Continuous: 0% through 2020 is 0% through January time_is_determinate_at(year(2020), cal_gregorian$month(1L)) # A coarser granule is always determinate time_is_determinate_at(yearmonth(as.Date("2020-02-01")), cal_gregorian$year(1L))
time_parse() is the inverse of format(): given text and the same
{lin(...)}/{cyc(...)} template format uses, it reconstructs the time
points that would have produced that text, via time_compose().
time_parse( x, chronon = NULL, cycle = NULL, format = NULL, regex = FALSE, na = c("", "NA"), calendar = NULL, locale = NULL, discrete = TRUE )time_parse( x, chronon = NULL, cycle = NULL, format = NULL, regex = FALSE, na = c("", "NA"), calendar = NULL, locale = NULL, discrete = TRUE )
x |
A character vector to parse. |
chronon |
Target time granule for the result, and (with |
cycle |
Target cycle granule, pairing with |
format |
A glue-style format string of |
regex |
If |
na |
Strings to treat as missing ( |
calendar |
Calendar used to resolve granule names in |
locale |
Default locale for named ( |
discrete |
Whether the result is discrete (integer chronon counts)
or continuous (fractional). See |
A format with a {lin(...)} token parses to linear time; one of only
{cyc(...)} tokens parses to cyclical time, e.g. time_parse("Feb", format = "{cyc(month, year, label = TRUE)}") recovers the same kind of
value as month_of_year().
Granule-specific extraction and decoding labels for each token is done by
linear_labels_parse()/cyclical_labels_parse().
A mixtime time vector, the same length as x. Linear if
format includes a {lin(...)} token (or cycle is NULL),
cyclical otherwise.
format() for the inverse direction, time_compose() for
composing a time point from already-decoded components,
label_scheme() for declaring how a granule's labels parse,
chronon_parse_linear()/chronon_parse_cyclical() for the candidate
formats derived from chronon/cycle, and vignette("time-format-strings")
for the format string syntax.
time_parse("2024-02-15", format = "{lin(year)}-{cyc(month, year)}-{cyc(day, month)}") time_parse( "15 Feb 2024", format = "{cyc(day, month)} {cyc(month, year, label = TRUE)} {lin(year)}" ) # One bad value becomes NA (with a warning) instead of aborting the batch time_parse( c("2024-02-15", "not a date"), format = "{lin(year)}-{cyc(month, year)}-{cyc(day, month)}" ) # No {lin(...)} token: parses to cyclical time time_parse("Feb", format = "{cyc(month, year, label = TRUE)}") # Several formats: whichever parses the most values is used for the whole # vector; here none of the "Y-M-D" format's values match, so the "D/M/Y" # format (which matches both) is used instead time_parse( c("15/02/2024", "20/03/2024"), format = c( "{lin(year)}-{cyc(month, year)}-{cyc(day, month)}", "{cyc(day, month)}/{cyc(month, year)}/{lin(year)}" ) ) # regex = TRUE: match "/" or "-" as the separator, # and tolerate a trailing comment after the date. time_parse( c("2024-02-15", "2024/02/15 (approx)"), format = "{lin(year)}[/-]{cyc(month, year)}[/-]{cyc(day, month)}( .*)?", regex = TRUE ) # Default format strings from the target chronon, and results with `tz`. time_parse("2024-02-15 09:00:00", chronon = cal_gregorian$second(1L, tz = "America/Los_Angeles"))time_parse("2024-02-15", format = "{lin(year)}-{cyc(month, year)}-{cyc(day, month)}") time_parse( "15 Feb 2024", format = "{cyc(day, month)} {cyc(month, year, label = TRUE)} {lin(year)}" ) # One bad value becomes NA (with a warning) instead of aborting the batch time_parse( c("2024-02-15", "not a date"), format = "{lin(year)}-{cyc(month, year)}-{cyc(day, month)}" ) # No {lin(...)} token: parses to cyclical time time_parse("Feb", format = "{cyc(month, year, label = TRUE)}") # Several formats: whichever parses the most values is used for the whole # vector; here none of the "Y-M-D" format's values match, so the "D/M/Y" # format (which matches both) is used instead time_parse( c("15/02/2024", "20/03/2024"), format = c( "{lin(year)}-{cyc(month, year)}-{cyc(day, month)}", "{cyc(day, month)}/{cyc(month, year)}/{lin(year)}" ) ) # regex = TRUE: match "/" or "-" as the separator, # and tolerate a trailing comment after the date. time_parse( c("2024-02-15", "2024/02/15 (approx)"), format = "{lin(year)}[/-]{cyc(month, year)}[/-]{cyc(day, month)}( .*)?", regex = TRUE ) # Default format strings from the target chronon, and results with `tz`. time_parse("2024-02-15 09:00:00", chronon = cal_gregorian$second(1L, tz = "America/Los_Angeles"))
A family of helpers to round date/time objects to a specified time granule
such as second, minute, hour, or day. These functions preserve the input
time class, as rounded by the attributes of the granule.
time_round(x, granule, ...) time_ceiling(x, granule, ...) time_floor(x, granule, ...)time_round(x, granule, ...) time_ceiling(x, granule, ...) time_floor(x, granule, ...)
x |
A date/time object to be rounded. Accepted types include Date, POSIXct, POSIXlt and other objects that inherit from POSIXt. The returned object will be of the same class as the input. |
granule |
A time granule (or object coercible to a time granule, e.g. "day"). |
... |
Additional arguments passed to specific implementations. |
An object of the same class as x with its time components adjusted to the requested granule.
base::round, lubridate::round_date
# Round POSIXct to the nearest minute (preserving tz) t <- as.POSIXct("2020-01-01 12:34:56", tz = "UTC") time_round(t, granule = cal_gregorian$minute(1L)) # Floor to the nearest hour time_floor(t, granule = cal_gregorian$hour(1L)) # Ceiling a Date (treated as midnight-of-day rounding) d <- as.Date("2020-01-01") time_ceiling(d, granule = cal_gregorian$month(1L))# Round POSIXct to the nearest minute (preserving tz) t <- as.POSIXct("2020-01-01 12:34:56", tz = "UTC") time_round(t, granule = cal_gregorian$minute(1L)) # Floor to the nearest hour time_floor(t, granule = cal_gregorian$hour(1L)) # Ceiling a Date (treated as midnight-of-day rounding) d <- as.Date("2020-01-01") time_ceiling(d, granule = cal_gregorian$month(1L))
Shifts time points by a duration, like x + by, with control over how time
points that don't exist in the target granule are resolved. Shifting by a
duration with an irregular relationship to the time points' chronon (e.g.
days within months) can produce time points that don't exist, such as
shifting 31 January by one month. In a time zone, shifting by days or
longer keeps the local clock time, which may have been skipped when daylight
saving starts (e.g. 02:30 on the day clocks go forward from 02:00 to 03:00).
The + and - operators use the default strategy, set by the
mixtime.on_invalid option ("clamp" unless set).
time_shift(x, by, on_invalid = getOption("mixtime.on_invalid", "clamp"))time_shift(x, by, on_invalid = getOption("mixtime.on_invalid", "clamp"))
x |
A time point vector. |
by |
A time |
on_invalid |
How to resolve time points that don't exist in the target
granule. Defaults to the
|
A time point vector of the same type as x.
x <- datetime("2021-01-30 09:30:00") time_shift(x, months(1L)) time_shift(x, months(1L), on_invalid = "previous") time_shift(x, months(1L), on_invalid = "next") time_shift(x, months(1L), on_invalid = "overflow") time_shift(x, months(1L), on_invalid = "reject") try(time_shift(x, months(1L), on_invalid = "error")) # Shifting backwards time_shift(date("2021-03-31"), months(-1L), on_invalid = "overflow") # 02:30 doesn't exist on 2025-10-05 in Melbourne (clocks go forward at 02:00) x <- datetime(as.POSIXct("2025-10-04 02:30", tz = "Australia/Melbourne")) time_shift(x, days(1L)) time_shift(x, days(1L), on_invalid = "previous") time_shift(x, days(1L), on_invalid = "next") time_shift(x, days(1L), on_invalid = "overflow")x <- datetime("2021-01-30 09:30:00") time_shift(x, months(1L)) time_shift(x, months(1L), on_invalid = "previous") time_shift(x, months(1L), on_invalid = "next") time_shift(x, months(1L), on_invalid = "overflow") time_shift(x, months(1L), on_invalid = "reject") try(time_shift(x, months(1L), on_invalid = "error")) # Shifting backwards time_shift(date("2021-03-31"), months(-1L), on_invalid = "overflow") # 02:30 doesn't exist on 2025-10-05 in Melbourne (clocks go forward at 02:00) x <- datetime(as.POSIXct("2025-10-04 02:30", tz = "Australia/Melbourne")) time_shift(x, days(1L)) time_shift(x, days(1L), on_invalid = "previous") time_shift(x, days(1L), on_invalid = "next") time_shift(x, days(1L), on_invalid = "overflow")
These S7 generic functions provide the full and abbreviated names for time
units. time_unit_full() is used in messages and durations (e.g., "2 months").
time_unit_abbr() is used for tsibble index interval displays (e.g., "1M").
time_unit_plural() pluralises the full unit name for a given quantity using
cli-style pluralisation (e.g., "year{?/s}" becomes "year" or "years").
time_unit_full(x, ...) time_unit_plural(x, n = 2L) time_unit_abbr(x, ...)time_unit_full(x, ...) time_unit_plural(x, n = 2L) time_unit_abbr(x, ...)
x |
A time granule object (e.g., |
... |
Additional arguments for methods. |
n |
Numeric quantity used to select singular or plural form. |
A string representing the time unit
time_unit_full(cal_gregorian$year(1L)) time_unit_plural(cal_gregorian$year(1L), 1L) time_unit_plural(cal_gregorian$year(1L), 2L) time_unit_abbr(cal_gregorian$year(1L))time_unit_full(cal_gregorian$year(1L)) time_unit_plural(cal_gregorian$year(1L), 1L) time_unit_plural(cal_gregorian$year(1L), 2L) time_unit_abbr(cal_gregorian$year(1L))
Returns the timezone abbreviation (e.g., "EST", "PDT") for a given datetime in its specified timezone.
tz_abbreviation(x, tz = tz_name(x))tz_abbreviation(x, tz = tz_name(x))
x |
A POSIXct datetime object or something coercible to POSIXct. The timezone is extracted from this object. |
tz |
A character vector of timezones to abbreviate at time point |
A character vector of timezone abbreviations.
tz_abbreviation(Sys.time()) tz_abbreviation(as.POSIXct("2024-01-15 12:00:00", tz = "America/New_York"))tz_abbreviation(Sys.time()) tz_abbreviation(as.POSIXct("2024-01-15 12:00:00", tz = "America/New_York"))
Generic function to extract the timezone from objects that have timezone information.
tz_name(x, ...)tz_name(x, ...)
x |
An object with timezone information. |
... |
Additional arguments passed to methods. |
A character vector representing the timezone of each time point (e.g., "America/New_York", "UTC").
tz_name(Sys.time()) tz_name(as.POSIXct("2024-06-15 12:00:00", tz = "America/New_York"))tz_name(Sys.time()) tz_name(as.POSIXct("2024-06-15 12:00:00", tz = "America/New_York"))
Returns the UTC offset for a given datetime in its specified timezone.
tz_offset(x, ...)tz_offset(x, ...)
x |
A time class coercible to POSIXt with an associated time zone. |
... |
Additional arguments passed to methods. |
A mixtime duration vector of offsets from UTC in the same chronon
(e.g. seconds for POSIXt, days for dates, etc.)
tz_offset(as.POSIXct(Sys.time(), tz = Sys.timezone())) tz_offset(as.POSIXct("2024-06-15 12:00:00", tz = "America/New_York"))tz_offset(as.POSIXct(Sys.time(), tz = Sys.timezone())) tz_offset(as.POSIXct("2024-06-15 12:00:00", tz = "America/New_York"))
Returns all timezone transitions (e.g., daylight saving time changes) that occur between two datetimes. The timezone is taken from the start datetime.
tz_transitions(start, end)tz_transitions(start, end)
start |
A POSIXct datetime object or something coercible to POSIXct, representing the start of the time range. The timezone is extracted from this object. |
end |
A POSIXct datetime object or something coercible to POSIXct, representing the end of the time range. |
A data frame with columns:
time: A mixtime linear time point (continuous, UTC seconds) giving
the instant of the transition.
offset_before, offset_after: mixtime durations (UTC seconds)
giving the UTC offset immediately before and after the transition.
# Get all DST transitions in 2024 for New York tz_transitions( as.POSIXct("2024-01-01", tz = "America/New_York"), as.POSIXct("2024-12-31", tz = "America/New_York") )# Get all DST transitions in 2024 for New York tz_transitions( as.POSIXct("2024-01-01", tz = "America/New_York"), as.POSIXct("2024-12-31", tz = "America/New_York") )
vocab function from a plain name tableThe common case for a label_scheme() vocab argument: a hand-listed
table of names, one entry per locale, each a named list of renderings. By
convention these follow CLDR's wide/abbreviated/narrow, but type can be
anything. vocab_table() wraps it in the function(type = NULL, locale = NULL) shape vocab requires.
vocab_table(..., default_locale = "en-GB")vocab_table(..., default_locale = "en-GB")
... |
Named entries, one per locale (e.g. |
default_locale |
The locale returned when |
For vocab backed by an external i18n source instead of a hand-listed
table, write that function(type, locale) directly instead. Same shape,
no list needed.
A function function(type = NULL, locale = NULL), suitable as
the vocab field of a label_scheme().
month_vocab <- vocab_table(`en-GB` = list(wide = month.name, abbreviated = month.abb)) month_vocab("abbreviated") month_vocab(locale = "en-GB")month_vocab <- vocab_table(`en-GB` = list(wide = month.name, abbreviated = month.abb)) month_vocab("abbreviated") month_vocab(locale = "en-GB")