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.
mixtime provides flexible time classes for time series analysis and forecasting with mixed temporal granularities. It is designed for handling temporal data at different frequencies, making it ideal for:
📈 Linear Time - Create linear time vectors with linear_time() or
with helpers:
year(), yearquarter(), yearmonth(), yearweek(), date(),
datetime()🔄 Cyclical Time - Create cyclical time vectors with
cyclical_time() or with helpers:
month_of_year(), day_of_year(), day_of_month(), time_of_day(),
day_of_week(), week_of_year()⏳ Time durations - Create time duration vectors with duration()
or with helpers:
years(), quarters(), months(), weeks(), days(), hours(),
minutes(), seconds(), milliseconds()🕰️ Temporal semantics
week(2L) for fortnights)📅 Calendar Systems - Support for several calendars:
cal_gregorian - Gregorian dates (e.g. 2026-02-17)cal_isoweek - ISO week dates (e.g. 2026-W8-Tue)cal_sym454 - Symmetry454 dates (e.g. 2026-Feb-W4-Tue)🧮 Temporal Operations
time_floor(), time_round(), time_ceiling()seq() for linear and cyclical time pointsThe mixtime package can be installed from CRAN with:
install.packages("mixtime")
The development version can be installed from GitHub with:
# install.packages("remotes")
remotes::install_github("mitchelloharawild/mixtime")
library(mixtime)
#>
#> Attaching package: 'mixtime'
#> The following objects are masked from 'package:base':
#>
#> date, months, quarters
demo_time <- as.POSIXct("2026-02-22 18:30:42", tz = "UTC")
demo_date <- as.Date("2026-02-22")
The mixtime package is designed around the time units of calendars. These time units are used to create and manipulate time vectors.
Calendars have a cal_* prefix, which contain a set of time units that
can be accessed with <cal>$<unit>. Using time units as functions
produces time granules.
# The Gregorian calendar
cal_gregorian
#> <cal_gregorian>
#> Time units:
#> - year
#> - quarter
#> - month
#> - day
#> - ampm
#> - hour
#> - minute
#> - second
#> - millisecond
#> - microsecond
#> - nanosecond
# A 1-month time granule
cal_gregorian$month(1L) # (1L is integer 1)
#> <mixtime::tu_month>
#> @ n : int 1
#> @ tz: 'mt_naive' chr NA
# A 2-week time granule (fortnights)
cal_isoweek$week(2L)
#> <mixtime::tu_week>
#> @ n : int 2
#> @ tz: 'mt_naive' chr NA
A linear time vector uses time granules to define the resolution of time
points, known as a chronon (the smallest granules of time). When the
input time has a different resolution than the chronon, it will be
automatically converted.
linear_time(demo_date, chronon = cal_gregorian$month(1L))
#> <mixtime[1]>
#> [1] 2026 Feb
Discrete time models (integer-based values) are used by default, however
continuous time models (double-based values) can be used with
discrete = FALSE to allow fractional chronons.
# February 22nd is 75% through the month (in non-leap years)
linear_time(demo_date, chronon = cal_gregorian$month(1L), discrete = FALSE)
#> <mixtime[1]>
#> [1] 2026 Feb 75.0%
Linear time helper functions are available to quickly create common time points.
# Create time vectors at different granularities
yearquarter(demo_date) + 0:7
#> <mixtime[8]>
#> [1] 2026 Q1 2026 Q2 2026 Q3 2026 Q4 2027 Q1 2027 Q2 2027 Q3 2027 Q4
yearmonth(demo_date) + 0:11
#> <mixtime[12]>
#> [1] 2026 Feb 2026 Mar 2026 Apr 2026 May 2026 Jun 2026 Jul 2026 Aug 2026 Sep
#> [9] 2026 Oct 2026 Nov 2026 Dec 2027 Jan
yearweek(demo_date) + 0:10
#> <mixtime[11]>
#> [1] 2026 W08 2026 W09 2026 W10 2026 W11 2026 W12 2026 W13 2026 W14 2026 W15
#> [9] 2026 W16 2026 W17 2026 W18
date(demo_date) + 0:6
#> <mixtime[7]>
#> [1] 2026-02-22 2026-02-23 2026-02-24 2026-02-25 2026-02-26 2026-02-27 2026-02-28
The mixtime package allows time of different granularities to be combined in a single vector.
c(
year(demo_date), yearquarter(demo_date),
yearmonth(demo_date), yearweek(demo_date)
)
#> <mixtime[4]>
#> [1] 2026 2026 Q1 2026 Feb 2026 W08
A cyclical time vector is defined by two time granules: a chronon (the
smaller granule of time) and a cycle (the larger granule that the
chronon loops over).
# The `calendar` argument provides a masking scope to `chronon` and `cycle`
cyclical_time(demo_date, chronon = day(1L), cycle = week(1L), calendar = cal_isoweek)
#> <mixtime[1]>
#> [1] Sun
There are several cyclical time helper functions for convenience.
# Extract cyclical components
month_of_year(demo_date)
#> <mixtime[1]>
#> [1] Feb
week_of_year(demo_date)
#> <mixtime[1]>
#> [1] W08
day_of_week(demo_date)
#> <mixtime[1]>
#> [1] Sun
# Continuous cyclical time shows progress through chronons
day_of_week(demo_time, discrete = FALSE)
#> <mixtime[1]>
#> [1] Sun 77.1%
All linear and cyclical time vectors support timezones via the tz
argument.
demo_time
#> [1] "2026-02-22 18:30:42 UTC"
# Same day (Sunday) in LA
date(demo_time, tz = "America/Los_Angeles")
#> <mixtime[1]>
#> [1] 2026-02-22 PST
date(demo_time, tz = "America/Los_Angeles", discrete = FALSE)
#> <mixtime[1]>
#> [1] 2026-02-22 43.8% PST
day_of_week(demo_time, tz = "America/Los_Angeles")
#> <mixtime[1]>
#> [1] Sun PST
# Next day (Monday) in Melbourne (23% through the 23rd)
date(demo_time, tz = "Australia/Melbourne")
#> <mixtime[1]>
#> [1] 2026-02-23 AEDT
date(demo_time, tz = "Australia/Melbourne", discrete = FALSE)
#> <mixtime[1]>
#> [1] 2026-02-23 23.0% AEDT
day_of_week(demo_time, tz = "Australia/Melbourne")
#> <mixtime[1]>
#> [1] Mon AEDT
Linear time points can be adjusted to the floor, ceiling, or rounded to a specified time granule.
# Round dates to different granularities
time_floor(demo_date, cal_gregorian$month(1L))
#> [1] "2026-02-01"
time_round(demo_date, cal_isoweek$week(1L))
#> [1] "2026-02-23"
time_ceiling(demo_date, cal_gregorian$month(1L))
#> [1] "2026-03-01"
The seq() function creates sequences of time points iterating by a
given time granule.
# Integer increments (advances by chronon's natural granule)
seq(yearmonth(demo_date), by = 1L, length.out = 10)
#> <mixtime[10]>
#> [1] 2026 Feb 2026 Mar 2026 Apr 2026 May 2026 Jun 2026 Jul 2026 Aug 2026 Sep
#> [9] 2026 Oct 2026 Nov
# Time can be sequenced by different granules than the chronon
seq(date(demo_date), by = cal_gregorian$month(1L), length.out = 8)
#> <mixtime[8]>
#> [1] 2026-02-22 2026-03-22 2026-04-22 2026-05-22 2026-06-22 2026-07-22 2026-08-22
#> [8] 2026-09-22