Skip to content

mixtime

0.4.0Package record

Mixed Temporal Vectors and Operations

1packages depend
19.1Kdownloads / year
80.3%test coverage
13/13flavors OK

Overview

About

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.

Changes in 0.4.0

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() and chronon_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() and seq() gain two on_invalid strategies. "next" resolves an invalid time point to the start of the following granule, so date("1955-01-31") plus one month is 1955-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 returning NA like "reject".
Show all changes in 0.4.0Hide the rest of the changes in 0.4.0
  • The new mixtime.on_invalid option sets the default on_invalid strategy for time_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 of chronon_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?) and yearmonth(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 internal chronon_convert() gains an allow_indeterminate argument, which still allows it by default.
  • new_time(), deprecated in 0.3.0, is now defunct. Use mt_linear(), mt_duration(), or mt_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, so year(x) == 2026L compares with the year 2026. Previously the number was a raw count of chronons since 1970 (2026 was the year 3996).
  • The on_invalid strategy "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 as 2020 W01 plus one year being 2020 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(), and seq().

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 > instant and span <= instant). The warning suggests code for the intended span (e.g. year(2015L), 2026L, or as.integer(myvar)).
  • Performance improvements for temporal operations with time zones.
  • Generalised the default parse strings used by yearweek(), yearmonth(), and yearquarter() 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 with date() or datetime()).
  • Parsing named labels (e.g. month and weekday names) is now case-insensitive.
  • The chronon of Date and POSIXct objects 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, like chronon_cardinality() does (e.g. there are 4 minute(15L) in hour(1L), not 60, and 10 day(1L) in day(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. in time_chronon() and str()), 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() and seq() resolve it with their on_invalid argument: "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" gives NA.
  • 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 gives NA with 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) and days(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 of seq() 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 so format()) 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), so mixtime(as.POSIXct(x)) round trips. Previously the result had an empty time zone, which mixtime() rejected. mixtime() now also reads a POSIXct with 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

CRAN checks
13OK
Slowest check: 5.6 min · r-devel-windows-x86_64
Status changes
  • OK13 OK2026-08-05
  • NOTE12 OK, 1 NOTE2026-08-01
  • OK7 OK2026-05-20
Advisories

none known

Documentation

In release 0.4.0
READMEYes · 511 wordsVignettesYes · 3 · dynamicNEWSYes · 100% structured · mentions 0.4.0Citation fileNoWebsiteYes · pkgdown
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

19.1K
CRAN downloads in the past year
Rank #1,450 · ~52/day · ~1.6K/mo
Daily download trend is not available in this view yet.
11.2K30 days
17.9K90 days
19.1K1 year
Compare downloads with other packages →
Also on355 r2u3 autocran

Repository

12Stars
4Forks
24Open issues
0Open PRs
4Releases
787Commits
3Commit identities
787 commits · Last activity 2026-10-17 · +20% stars, 30d
Responsiveness
How these are sampled
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

2025-08-23 · 72026-10-17 · 12
PracticesBeta

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.

Continuous integration (2)
GitHub ActionsR CMD check workflow

The R CMD check workflow runs on Linux

Docs source (4)
README.Rmdpkgdown

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)

CRAN release process (1)
cran-comments.md
Lint, format, editor (1)
RStudio project
How this is detected·Detection ruleset v3 (2026-09-26)

Dependencies

Declared dependencies
16 external dependencies (excludes base and recommended)

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.

Depends (1)
R >= 3.0.2
LinkingTo (2)
Enhances (0)
none
Reverse dependencies
1direct
12indirect
Imports 1
Depends, Imports or LinkingTo, most downloaded first

People & History

People (3)
Author, Maintainer since 0.1.0 (2026)
Contributor · added in 0.4.0
Contributor · added in 0.4.0
Releases (4)

Pick two releases to compare their code metrics.

  • 0.4.0Latest
    record
    2026-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.0
    record
    2026-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.0
    record
    2026-06-28 · diff ↗ ·
    added 4 exports
    cal_time_lunar_synodic, cal_time_solar_transit, chronon_format_duration, time_unit_plural
  • 0.1.0
    record
    2026-05-19
  • R
    R 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
Appears in task views

Cite

Cite this package

Run in R for the authors' preferred citation:

citation("mixtime")
O'Hara-Wild, M., Huang, C., & Hyndman, R. (2026). mixtime: Mixed Temporal Vectors and Operations (Version 0.4.0) [Computer software]. https://doi.org/10.32614/CRAN.package.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.

APA

Balamuta, J. J. (2026). R Observatory: Metrics for mixtime version 0.4.0 [Data set]. HJJB, LLC. Data release v2026-10-18. https://doi.org/10.5281/zenodo.21843040

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.

Report a problem with this page →

Privacy choices

These apply to this browser and are stored on this device only. Nothing about your choice is sent to us.

Read the privacy policy