Mixed Temporal Vectors and Operations
Overview
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.
New features
- Added the twelve remaining base relations of Allen's interval algebra as infix operators -
%p%/%pi%(precedes/preceded by),%m%/%mi%(meets/met by),%o%/%oi%(overlaps/overlapped by),%s%/%si%(starts/started by),%d%/%di%(during/contains), and%f%/%fi%(finishes/finished by) - completing the set alongside the existing==. - Added
chronon_glb()andchronon_lub(), which find the *greatest lower bound* (the finest common chronon) and the *least upper bound* (the coarsest chronon that every input chronon evenly aggregates into) of a set of chronons. time_shift()andseq()gain twoon_invalidstrategies."next"resolves an invalid time point to the start of the following granule, sodate("1955-01-31")plus one month is1955-03-01, and a local time skipped by daylight saving moves to the end of the gap (02:30 becomes 03:00)."error"throws an error instead of returningNAlike"reject".
Show all changes in 0.4.0Hide the rest of the changes in 0.4.0
- The new
mixtime.on_invalidoption sets the defaulton_invalidstrategy fortime_shift(),seq(), and the+and-operators, which otherwise clamp.seq()no longer warns about clamping when the option is set.
Deprecated
chronon_common()is deprecated in favour ofchronon_glb(), which names the *greatest lower bound* it finds explicitly and distinguishes it from its dual,chronon_lub().- Converting a discrete time to a chronon it doesn't nest within is deprecated, since the result is temporally indeterminate. For example,
day_of_week(yearmonth(x))(which day of the month?) andyearmonth(yearweek(x))(a week can straddle two months) now warn, and still use the start of each time point. This will become an error in the next release. Continuous time points are instants that are always determinate and convert as before. The internalchronon_convert()gains anallow_indeterminateargument, which still allows it by default. new_time(), deprecated in 0.3.0, is now defunct. Usemt_linear(),mt_duration(), ormt_cyclical()instead.
Breaking changes
- Bare numbers compared with (or cast to) a linear or cyclical time are now read as
mixtime()reads them, counting from the chronon's epoch, soyear(x) == 2026Lcompares with the year 2026. Previously the number was a raw count of chronons since 1970 (2026 was the year 3996). - The
on_invalidstrategy"nearest"is renamed to"previous", the backward counterpart of the new"next". It always resolves to the end of the target granule, rather than whichever valid time point is closest. - Shifting a discrete time point by a duration it doesn't nest within is now an error, since the result is temporally indeterminate, matching the conversions refused by time constructors. For example,
yearweek(x) + years(1L)(a week can straddle two years) previously shifted the start of the week, giving results such as2020 W01plus one year being2020 W53. Shifting by a whole number of chronons is still allowed (a week by 14 days, but not 11), as is shifting continuous times. This applies to+,-,time_shift(), andseq().
Improvements
- Comparing a discrete time (a span) with a continuous time at the start of its chronon (an instant, such as
year(2015)) now warns when reading the instant as a span would change the result:==and!=(never equal), and the orderings that measure against the instant's end (e.g.span > instantandspan <= instant). The warning suggests code for the intended span (e.g.year(2015L),2026L, oras.integer(myvar)). - Performance improvements for temporal operations with time zones.
- Generalised the default parse strings used by
yearweek(),yearmonth(), andyearquarter()to accept strings that are accepted by tsibble equivalents for ease of migration (with the intentional exception of dates and datetimes, which need to be parsed first withdate()ordatetime()). - Parsing named labels (e.g. month and weekday names) is now case-insensitive.
- The chronon of
DateandPOSIXctobjects is now identified from the interval between observations (like tsibble's interval), rather than always being 1 day or 1 second. For example,mixtime()on hourly datetimes now produces 1 hour chronons. A multiple of a unit is used only when every observation is aligned to it, so conversion never loses information.
Bug fixes
chronon_cardinality_fixed()now scales its result by the granule sizes (n) of both arguments, likechronon_cardinality()does (e.g. there are 4minute(15L)inhour(1L), not 60, and 10day(1L)inday(10L), not 1). Methods still return the ratio between unit granules.- Durations of multi-unit chronons now print with the chronon's size, so
duration(2L, hour(3L))shows"6 hours"(not"2 hours") and the chronon of a 3-hourly time vector reads"3 hours"(e.g. intime_chronon()andstr()), not"1 hour". - Time-zone-aware days, weeks, months and years now start at local midnight, so
as.POSIXct(mixtime(x, month(tz = "Australia/Melbourne")))returns 00:00 AEDT instead of 11:00. Previously a conversion to UTC read the local label as a UTC one. - Conversions of time-zone-aware times now account for daylight saving changes: a day that is 23 or 25 hours long is converted by its real length, and the two instants that share a clock reading when daylight saving ends are kept apart, including in hourly data.
- The fraction through a continuous time-zone-aware time (e.g. a week) is now the fraction through that unit in its own time zone, so
floor()of a continuous time always gives the matching discrete time. - Calendar arithmetic on time-zone-aware times (e.g. adding months) now keeps the local clock time. A local time that occurs twice when daylight saving ends resolves to its first occurrence. A local time skipped when daylight saving starts is invalid, and is resolved like other invalid time points (e.g. 31 January plus one month): by default it is clamped back by the size of the gap, keeping its minutes (02:30 becomes 01:30 when clocks go forward from 02:00 to 03:00).
time_shift()andseq()resolve it with theiron_invalidargument:"previous"gives the end of the time before the gap,"next"the start of the time after it (03:00),"overflow"moves it forward by the gap (03:30), and"reject"givesNA. - Shifting or
seq()-ing times with a multi-unit chronon (e.g. half-hourly times) by days, months or years no longer errors with "Cannot determine whether 30 minutes nest within 1 year". - Parsing a local time skipped when daylight saving starts (e.g.
datetime("2025-10-05 02:30:00", tz = "Australia/Melbourne")) now givesNAwith a warning, like other invalid times such as"2026-02-30". - Adding or subtracting hours, minutes or seconds on time-zone-aware times now moves by real time across daylight saving changes, so 02:30 AEDT plus one hour is 02:30 AEST when daylight saving ends (previously 03:30 AEST, two real hours later). Days and longer units keep the local clock time, so
hours(24L)anddays(1L)differ on a 23 or 25 hour day. seq()of time-zone-aware times by days (or weeks) now keeps the local clock time across daylight saving changes, so a daily sequence at 10:00 stays at 10:00 (previously it moved to 09:00 when daylight saving ended). Each element ofseq()now matches adding a duration to the start, so a time adjusted because daylight saving skipped it returns to its clock time on the following day.- Converting solar time to time-zone-aware civil time now accounts for the time zone, and converting solar time between two locations now accounts for the change of location.
tz_abbreviation()(and soformat()) now labels a time-zone-aware time by the zone in effect when it starts, so a day on which daylight saving ends reads as daylight time (e.g."2015-04-05 AEDT"in Melbourne, previously"AEST").format()of a continuous time no longer shows a time just below its true value when floating-point error leaves it a fraction of a second short (e.g."03:29:59 100.0%"instead of"03:30:00 0.0%").as.POSIXct()of a mixtime now keeps its time zone (or uses UTC when it has several), somixtime(as.POSIXct(x))round trips. Previously the result had an empty time zone, whichmixtime()rejected.mixtime()now also reads aPOSIXctwith an empty time zone as the local time zone, like base R does.- A fractional time before 1970 within a second of a time zone transition (e.g. half a second before New York's 1960 change to daylight time) used the offset from after the transition.
From NEWS.md in the release
Install
Health
- OK13 OK2026-08-05
- NOTE12 OK, 1 NOTE2026-08-01
- OK7 OK2026-05-20
Documentation
- Help pages
- 64 (3 internal)includes a package overview page
- Examples that run
- 100%51 run in a plain check
- Exported functions with examples
- 86%
- Documented parameters
- 95%
- Return-value docs
- 98%
- Help pages citing references
- 2%
Downloads
Repository
- PRs merged (all time)
- 67%
- Median days to close, 50 most recently updated closed issues
- 46
- Median days to close, 50 most recently updated closed PRs
- 1
Stars over time
Forks over time
Releases over time
Issues over time
PRs over time
Commits over time
Commit identities over time
8 development-tooling and community-health practices detected across 4 families in the upstream repository
Checks run against github.com/mitchelloharawild/mixtime on 2026-10-11.
The R CMD check workflow runs on Linux
GitHub Pages site last deployed 2026-10-11 · The repository has a site deploy workflow
pkgdown site last built 2026-08-24, before release 0.4.0 (2026-10-13)
Dependencies
Installing mixtime adds 9 packages (7 with compiled code, 3.7 MB of source tarballs). Heaviest: vctrs 1.0 MB, rlang 766 KB, cli 629 KB.
Code & Tests
People & History
Pick two releases to compare their code metrics.
- 0.4.0Latest2026-10-13 · current release · diff ↗ ·
added 15 exports
%d%, %di%, %f%, %fi%, %m%, %mi%, %o%, %oi%, %p%, %pi%, %s%, %si%, chronon_glb, chronon_lub, time_shift - 0.3.02026-06-28 · diff ↗ ·
added 24 exports
chronon_cardinality_fixed, chronon_parse_cyclical, chronon_parse_linear, cyc, cyclical_labels_format, cyclical_labels_parse, label_scheme, lin, linear_labels_format, linear_labels_parse, mt_cyclical, mt_duration, mt_linear, mt_time, parse_format, time_components, time_compose, time_is_complete_at, time_is_cyclical, time_is_determinate_at, time_is_duration, time_is_linear, time_parse, vocab_table - 0.2.02026-06-28 · diff ↗ ·
added 4 exports
cal_time_lunar_synodic, cal_time_solar_transit, chronon_format_duration, time_unit_plural - 0.1.02026-05-19
- RR 4.6.0 released · 2026-04-24
Package metadata
- First published
- 2026-05-19
- Total releases
- 4 / 1 yrs
- License
- MIT + file LICENSE OSI
- Minimum R
- ≥ 3.0.2
- Download size
- 340 KB
Cite
Cite this package
Run in R for the authors' preferred citation:
citation("mixtime")This package has no citation file, so citation() returns this entry built from DESCRIPTION.
Cite the R Observatory
For a number measured here: a download total, a coverage figure, an archival date.
From data release v2026-10-18, which the citation names so these numbers can be found later. More on citing and the projects behind them.