Working with Different Types of Time Indices Using tind Class

Grzegorz Klima

tind class is designed to represent time indices of different types and perform computations with them. Indices are represented as vectors of integers or doubles. The following types of time indices are supported:

Time indices can be constructed via calls to tind constructor, using as.tind methods, or by calling parse_t and strptind functions for parsing arbitrary time index formats.

Before proceeding, let us load the package.

library("tind")

Years

The internal code for years is y.

The simplest way to construct year indices is to invoke tind constructor with a single argument y.

(ys <- tind(y = 2010:2020))
## year [tind]
##  [1] 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020

In as.tind method, integers in range 1800–2199 are automatically interpreted as years. For instance:

(ys <- as.tind(2010:2020))
## year [tind]
##  [1] 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020

To let as.tind know that numbers outside 1800–2199 range should be interpreted as years, type argument has to be provided as in:

(ys <- as.tind(c(1700, 1800, 1900, 2000, 2100), type = "y"))
## year [tind]
## [1] 1700 1800 1900 2000 2100

Convenience function as.year is a shortcut for as.tind(*, type = "y"):

(ys <- as.year(c(1700, 1800, 1900, 2000, 2100)))
## year [tind]
## [1] 1700 1800 1900 2000 2100

Four-digit character strings in the format YYYY are also automatically interpreted as year indices:

(ys <- as.tind(c("1700", "1800")))
## year [tind]
## [1] 1700 1800

Years as four-digit strings are indicated by %Y format specifier. The last examples could also be written as:

(ys <- as.tind(c("1700", "1800", "1900", "2000", "2100"), format = "%Y"))
## year [tind]
## [1] 1700 1800 1900 2000 2100

Two-digit year indices are indicated by %y format specifier. By default, numbers in range 69–99 are interpreted as years 1969–1999 and numbers 00–68 as years 2000–2068:

(ys <- as.tind(c("98", "99", "00", "01", "02"), format = "%y"))
## year [tind]
## [1] 1998 1999 2000 2001 2002
format(ys, "%Y")
## [1] "1998" "1999" "2000" "2001" "2002"
format(ys, "%y")
## [1] "98" "99" "00" "01" "02"

as.year guesses short year format:

(ys <- as.year(c("98", "99", "00", "01", "02")))
## year [tind]
## [1] 1998 1999 2000 2001 2002

Treatment of two-digit years is controlled by tind.abbr.year.start option.

options("tind.abbr.year.start")
## $tind.abbr.year.start
## [1] 69

Quarters

The internal code for quarters is q.

Quarters can be constructed using tind constructor with arguments y and q. Arguments of tind constructor are recycled if necessary.

(qs <- tind(y = rep(2020:2023, each = 4), q = 1:4))
## quarter [tind]
##  [1] 2020Q1 2020Q2 2020Q3 2020Q4 2021Q1 2021Q2 2021Q3 2021Q4 2022Q1 2022Q2
## [11] 2022Q3 2022Q4 2023Q1 2023Q2 2023Q3 2023Q4

The default format for quarters is "%YQ%q", where %q format specifier is a tind extension giving quarter number. This will be automatically recognized:

(qs <- as.tind(c("2020Q1", "2020Q2", "2020Q3", "2020Q4")))
## quarter [tind]
## [1] 2020Q1 2020Q2 2020Q3 2020Q4
format(qs)
## [1] "2020Q1" "2020Q2" "2020Q3" "2020Q4"
format(qs, "%YQ%q")
## [1] "2020Q1" "2020Q2" "2020Q3" "2020Q4"

Less popular formats can be parsed using combinations of %Y (or %y) and%q specifiers. Consider YYYY.Q format:

as.tind("2023.2", format = "%Y.%q")
## quarter [tind]
## [1] 2023Q2

One can also specify the order of index components using order argument:

as.tind("2023.2", order = "yq")
## quarter [tind]
## [1] 2023Q2

If order is yq, quarters will be automatically parsed if type = "q" is set:

as.tind(c("2020 1", "2020 2", "2020 3", "2020 4"), type = "q")
## quarter [tind]
## [1] 2020Q1 2020Q2 2020Q3 2020Q4

Convenience function as.quarter is a shortcut for as.tind(*, type = "q"):

as.quarter(c("2020 1", "2020 2", "2020 3", "2020 4"))
## quarter [tind]
## [1] 2020Q1 2020Q2 2020Q3 2020Q4

Packages stats and zoo (class yearqrt) represent quarters as year fractions with e.g., 2020.0, 2020.25, 2020.5, 2020.75 representing 2020Q1, 2020Q2, 2020Q3, 2020Q4 respectively. Conversion from this format can be done using yf2tind function.

yf2tind(2020 + (0:3) / 4, "q")
## quarter [tind]
## [1] 2020Q1 2020Q2 2020Q3 2020Q4

Months

The internal code for months is m.

Months can be constructed using tind constructor with arguments y and m. Arguments of tind constructor are recycled if necessary.

(ms <- tind(y = 2023, m = 1:12))
## month [tind]
##  [1] 2023-01 2023-02 2023-03 2023-04 2023-05 2023-06 2023-07 2023-08 2023-09
## [10] 2023-10 2023-11 2023-12

The default format for months is "%Y-%m", where %m format specifier represents month as a two-digit number.

format(ms)
##  [1] "2023-01" "2023-02" "2023-03" "2023-04" "2023-05" "2023-06" "2023-07"
##  [8] "2023-08" "2023-09" "2023-10" "2023-11" "2023-12"
format(ms, "%Y-%m")
##  [1] "2023-01" "2023-02" "2023-03" "2023-04" "2023-05" "2023-06" "2023-07"
##  [8] "2023-08" "2023-09" "2023-10" "2023-11" "2023-12"

If order is ym, months will be automatically parsed if type = "m" is set:

as.tind("2023-11", type = "m")
## month [tind]
## [1] 2023-11

Convenience function as.month is a shortcut for as.tind(*, type = "m"):

as.month("2023-11")
## month [tind]
## [1] 2023-11

Format specifier %b denotes abbreviated month name as in the following example. See documentation of month_names for discussion of locale settings.

(shrtms <- format(ms, "%b %y", locale = "C"))
##  [1] "Jan 23" "Feb 23" "Mar 23" "Apr 23" "May 23" "Jun 23" "Jul 23" "Aug 23"
##  [9] "Sep 23" "Oct 23" "Nov 23" "Dec 23"

The above can be parsed using format specification or using order specification (with month first).

as.tind(shrtms, format = "%b %y", locale = "C")
## month [tind]
##  [1] 2023-01 2023-02 2023-03 2023-04 2023-05 2023-06 2023-07 2023-08 2023-09
## [10] 2023-10 2023-11 2023-12
as.tind(shrtms, order = "my", locale = "C")
## month [tind]
##  [1] 2023-01 2023-02 2023-03 2023-04 2023-05 2023-06 2023-07 2023-08 2023-09
## [10] 2023-10 2023-11 2023-12

Packages stats and zoo (class yearmon) represent months as year fractions with e.g., 2020.0, 2020.0833, 2020.1667, 2020.25 representing 2020-01, 2020-01, 2020-03, 2020-04 respectively. Conversion from this format can be done using yf2tind function.

yf2tind(2020 + (0:11) / 12, "m")
## month [tind]
##  [1] 2020-01 2020-02 2020-03 2020-04 2020-05 2020-06 2020-07 2020-08 2020-09
## [10] 2020-10 2020-11 2020-12

Weeks (ISO 8601)

tind supports ISO 8610 weeks i.e. weeks starting on Monday with the first week in a year being the week with the first Thursday in a year. See https://en.wikipedia.org/wiki/ISO_week_date.

The internal code for weeks is w.

Weeks can be constructed using tind constructor with arguments y and w. Arguments of tind constructor are recycled if necessary.

(ws <- tind(y = 2024, w = 1:52))
## week [tind]
##  [1] 2024-W01 2024-W02 2024-W03 2024-W04 2024-W05 2024-W06 2024-W07 2024-W08
##  [9] 2024-W09 2024-W10 2024-W11 2024-W12 2024-W13 2024-W14 2024-W15 2024-W16
## [17] 2024-W17 2024-W18 2024-W19 2024-W20 2024-W21 2024-W22 2024-W23 2024-W24
## [25] 2024-W25 2024-W26 2024-W27 2024-W28 2024-W29 2024-W30 2024-W31 2024-W32
## [33] 2024-W33 2024-W34 2024-W35 2024-W36 2024-W37 2024-W38 2024-W39 2024-W40
## [41] 2024-W41 2024-W42 2024-W43 2024-W44 2024-W45 2024-W46 2024-W47 2024-W48
## [49] 2024-W49 2024-W50 2024-W51 2024-W52

The default format for weeks is %G-W%V, where %G is the week-based year (ISO week-numbering year, ISO year) and %V ISO week number.

format(ws)
##  [1] "2024-W01" "2024-W02" "2024-W03" "2024-W04" "2024-W05" "2024-W06"
##  [7] "2024-W07" "2024-W08" "2024-W09" "2024-W10" "2024-W11" "2024-W12"
## [13] "2024-W13" "2024-W14" "2024-W15" "2024-W16" "2024-W17" "2024-W18"
## [19] "2024-W19" "2024-W20" "2024-W21" "2024-W22" "2024-W23" "2024-W24"
## [25] "2024-W25" "2024-W26" "2024-W27" "2024-W28" "2024-W29" "2024-W30"
## [31] "2024-W31" "2024-W32" "2024-W33" "2024-W34" "2024-W35" "2024-W36"
## [37] "2024-W37" "2024-W38" "2024-W39" "2024-W40" "2024-W41" "2024-W42"
## [43] "2024-W43" "2024-W44" "2024-W45" "2024-W46" "2024-W47" "2024-W48"
## [49] "2024-W49" "2024-W50" "2024-W51" "2024-W52"
format(ws, format = "%G-W%V")
##  [1] "2024-W01" "2024-W02" "2024-W03" "2024-W04" "2024-W05" "2024-W06"
##  [7] "2024-W07" "2024-W08" "2024-W09" "2024-W10" "2024-W11" "2024-W12"
## [13] "2024-W13" "2024-W14" "2024-W15" "2024-W16" "2024-W17" "2024-W18"
## [19] "2024-W19" "2024-W20" "2024-W21" "2024-W22" "2024-W23" "2024-W24"
## [25] "2024-W25" "2024-W26" "2024-W27" "2024-W28" "2024-W29" "2024-W30"
## [31] "2024-W31" "2024-W32" "2024-W33" "2024-W34" "2024-W35" "2024-W36"
## [37] "2024-W37" "2024-W38" "2024-W39" "2024-W40" "2024-W41" "2024-W42"
## [43] "2024-W43" "2024-W44" "2024-W45" "2024-W46" "2024-W47" "2024-W48"
## [49] "2024-W49" "2024-W50" "2024-W51" "2024-W52"

Note that you cannot use %Y, %W, and %U specifiers with weeks. ISO week-numbering year may differ from Gregorian (i.e. calendar) year %Y. %W and %U formats refer to non-ISO weeks and are not supported.

as.week (a shortcut for as.tind(*, type = "w")) automatically recognizes this format.

as.week("2024-W51")
## week [tind]
## [1] 2024-W51

Dates

Dates (code d) can be most easily constructed from y, m, and d components passed to tind constructor. Order of arguments is irrelevant.

tind(m = 3, d = 15, y = 2024)
## date [tind]
## [1] 2024-03-15
(ds <- tind(y = 2024, m = rep(1:3, each = 2), d = c(1, 16)))
## date [tind]
## [1] 2024-01-01 2024-01-16 2024-02-01 2024-02-16 2024-03-01 2024-03-16

The default format for dates is %Y-%m-%d (ISO format, shortcut %F).

format(ds)
## [1] "2024-01-01" "2024-01-16" "2024-02-01" "2024-02-16" "2024-03-01"
## [6] "2024-03-16"
format(ds, format = "%Y-%m-%d")
## [1] "2024-01-01" "2024-01-16" "2024-02-01" "2024-02-16" "2024-03-01"
## [6] "2024-03-16"
format(ds, format = "%F")
## [1] "2024-01-01" "2024-01-16" "2024-02-01" "2024-02-16" "2024-03-01"
## [6] "2024-03-16"

as.date (a shortcut for as.tind(*, type = "d")) automatically recognizes this format.

as.date("2024-12-31")
## date [tind]
## [1] 2024-12-31

US format %m/%d/%y (shortcut %D) is also automatically recognized.

as.date("12/31/24")
## date [tind]
## [1] 2024-12-31
format(as.date("12/31/24"), "%m/%d/%y")
## [1] "12/31/24"
format(as.date("12/31/24"), "%D")
## [1] "12/31/24"

Month names can also be used. See documentation of month_names for discussion of locale settings.

(chds <- format(ds, "%b %d, %y", locale = "C"))
## [1] "Jan 01, 24" "Jan 16, 24" "Feb 01, 24" "Feb 16, 24" "Mar 01, 24"
## [6] "Mar 16, 24"
as.tind(chds, order = "mdy", locale = "C")
## date [tind]
## [1] 2024-01-01 2024-01-16 2024-02-01 2024-02-16 2024-03-01 2024-03-16

Time of Day

Type h (as in hour) represents times between midnight (00:00) and midnight of the next day (24:00).

Time of day can be constructed from H, M, and S arguments passed to tind constructor.

tind(H = 0:23)
## time of day [tind]
##  [1] 00:00 01:00 02:00 03:00 04:00 05:00 06:00 07:00 08:00 09:00 10:00 11:00
## [13] 12:00 13:00 14:00 15:00 16:00 17:00 18:00 19:00 20:00 21:00 22:00 23:00
tind(H = 13, M = (0:3) * 15)
## time of day [tind]
## [1] 13:00 13:15 13:30 13:45
(tod1 <- tind(H = 13, M = 30, S = (0:11) * 5))
## time of day [tind]
##  [1] 13:30:00 13:30:05 13:30:10 13:30:15 13:30:20 13:30:25 13:30:30 13:30:35
##  [9] 13:30:40 13:30:45 13:30:50 13:30:55

Sub-second accuracy is also supported.

(tod2 <- tind(H = 13, M = 30, S = 17 + (0:9) / 10))
## time of day [tind]
##  [1] 13:30:17.0 13:30:17.1 13:30:17.2 13:30:17.3 13:30:17.4 13:30:17.5
##  [7] 13:30:17.6 13:30:17.7 13:30:17.8 13:30:17.9

As seen above, tind automatically determines whether seconds should be shown or sub-second accuracy is required.

Format specifiers %H, %M, and %S can be used with time of day.

format(tod1, "%H:%M")
##  [1] "13:30" "13:30" "13:30" "13:30" "13:30" "13:30" "13:30" "13:30" "13:30"
## [10] "13:30" "13:30" "13:30"
format(tod1, "%H:%M:%S")
##  [1] "13:30:00" "13:30:05" "13:30:10" "13:30:15" "13:30:20" "13:30:25"
##  [7] "13:30:30" "13:30:35" "13:30:40" "13:30:45" "13:30:50" "13:30:55"
as.tind("13:47", format = "%H:%M")
## time of day [tind]
## [1] 13:47
as.tind("13:47:39", format = "%H:%M:%S")
## time of day [tind]
## [1] 13:47:39

Sub-second accuracy can be explicitly requested via %OS[0-6] format specifier.

format(tod2, "%H:%M:%S")
##  [1] "13:30:17" "13:30:17" "13:30:17" "13:30:17" "13:30:17" "13:30:17"
##  [7] "13:30:17" "13:30:17" "13:30:17" "13:30:17"
format(tod2, "%H:%M:%OS1")
##  [1] "13:30:17.0" "13:30:17.1" "13:30:17.2" "13:30:17.3" "13:30:17.4"
##  [6] "13:30:17.5" "13:30:17.6" "13:30:17.7" "13:30:17.8" "13:30:17.9"
format(tod2, "%H:%M:%OS2")
##  [1] "13:30:17.00" "13:30:17.10" "13:30:17.20" "13:30:17.30" "13:30:17.40"
##  [6] "13:30:17.50" "13:30:17.60" "13:30:17.70" "13:30:17.80" "13:30:17.90"
format(tod2, "%H:%M:%OS3")
##  [1] "13:30:17.000" "13:30:17.100" "13:30:17.200" "13:30:17.300" "13:30:17.400"
##  [6] "13:30:17.500" "13:30:17.600" "13:30:17.700" "13:30:17.800" "13:30:17.900"

For parsing, %OS (without digits) should be used.

as.tind("13:47:39.89", format = "%H:%M:%OS")
## time of day [tind]
## [1] 13:47:39.89

H, M, and S can be used for order specification. With order specifier S sub-second accuracy is automatically determined.

as.tind("13", order = "H")
## time of day [tind]
## [1] 13:00
as.tind("13:47", order = "HM")
## time of day [tind]
## [1] 13:47
as.tind("13:47:39", order = "HMS")
## time of day [tind]
## [1] 13:47:39
as.tind("13:47:39.9", order = "HMS")
## time of day [tind]
## [1] 13:47:39.9
as.tind("13:47:39.89", order = "HMS")
## time of day [tind]
## [1] 13:47:39.89

12-hour clock can be used with the help of %I (hour in 12-hour clock) and %p (ante meridiem, post meridiem) specifiers.

format(tind(H = 0:23), "%I %p")
##  [1] "12 am" "01 am" "02 am" "03 am" "04 am" "05 am" "06 am" "07 am" "08 am"
## [10] "09 am" "10 am" "11 am" "12 pm" "01 pm" "02 pm" "03 pm" "04 pm" "05 pm"
## [19] "06 pm" "07 pm" "08 pm" "09 pm" "10 pm" "11 pm"
as.tind("9:30am", format = "%I:%M%p")
## time of day [tind]
## [1] 09:30

Alternatively, I and p order specifiers can be used.

as.tind("9:30am", order = "IMp")
## time of day [tind]
## [1] 09:30

Date-time

Date-time indices (code t) can be constructed from components required for date and at least hour (H) component.

tind(y = 2024, m = 8, d = 2, H = 16)
## date-time, time zone: Europe/Warsaw [tind]
## [1]  2024-08-02 16:00 CEST
tind(y = 2024, m = 8, d = 2, H = 16, M = (0:3) * 15)
## date-time, time zone: Europe/Warsaw [tind]
## [1]  2024-08-02 16:00 CEST  2024-08-02 16:15 CEST  2024-08-02 16:30 CEST
## [4]  2024-08-02 16:45 CEST
tind(y = 2024, m = 8, d = 2, H = 16, M = 0, S = 10 * (0:5))
## date-time, time zone: Europe/Warsaw [tind]
## [1]  2024-08-02 16:00:00 CEST  2024-08-02 16:00:10 CEST
## [3]  2024-08-02 16:00:20 CEST  2024-08-02 16:00:30 CEST
## [5]  2024-08-02 16:00:40 CEST  2024-08-02 16:00:50 CEST

All date-time indices always have time zone attribute set. For more information, see documentation of tzone function. By default, time zone is set to system time zone but can be explicitly set using tz argument.

tind(y = 2024, m = 8, d = 2, H = 16, M = (0:3) * 15, tz = "UTC")
## date-time, time zone: UTC [tind]
## [1]  2024-08-02 16:00 UTC  2024-08-02 16:15 UTC  2024-08-02 16:30 UTC
## [4]  2024-08-02 16:45 UTC

Date-time indices can also be constructed from date and time of day indices using date_time function.

(dt1 <- date_time(tind(y = 2024, m = 8, d = 2),
                  tind(H = 16, M = (0:3) * 15)))
## date-time, time zone: Europe/Warsaw [tind]
## [1]  2024-08-02 16:00 CEST  2024-08-02 16:15 CEST  2024-08-02 16:30 CEST
## [4]  2024-08-02 16:45 CEST
(dt2 <- date_time(tind(y = 2024, m = 8, d = 2),
                  tind(H = 16, M = (0:3) * 15), tz = "UTC"))
## date-time, time zone: UTC [tind]
## [1]  2024-08-02 16:00 UTC  2024-08-02 16:15 UTC  2024-08-02 16:30 UTC
## [4]  2024-08-02 16:45 UTC

Reverse operation can be performed using date_time_split function.

date_time_split(dt1)
## $date
## date [tind]
## [1] 2024-08-02 2024-08-02 2024-08-02 2024-08-02
## 
## $time
## time of day [tind]
## [1] 16:00 16:15 16:30 16:45

As lists can be trivially converted to data frames, if a data frame is desired, date_time_split only has to be wrapped by as.data.frame.

as.data.frame(date_time_split(dt1))
##         date  time
## 1 2024-08-02 16:00
## 2 2024-08-02 16:15
## 3 2024-08-02 16:30
## 4 2024-08-02 16:45

As seen, formatting of date-time indices depends on actual indices (need for seconds or for subsecond accuracy). Moreover, as.character and format methods differ. The former returns UTC offset (or Z for UTC), the latter time zone abbreviation.

as.character(dt1)
## [1] "2024-08-02 16:00+0200" "2024-08-02 16:15+0200" "2024-08-02 16:30+0200"
## [4] "2024-08-02 16:45+0200"
as.character(dt2)
## [1] "2024-08-02 16:00Z" "2024-08-02 16:15Z" "2024-08-02 16:30Z"
## [4] "2024-08-02 16:45Z"
format(dt1)
## [1] "2024-08-02 16:00 CEST" "2024-08-02 16:15 CEST" "2024-08-02 16:30 CEST"
## [4] "2024-08-02 16:45 CEST"
format(dt2)
## [1] "2024-08-02 16:00 UTC" "2024-08-02 16:15 UTC" "2024-08-02 16:30 UTC"
## [4] "2024-08-02 16:45 UTC"

All format specifiers that can be used with dates and time of day can also be used with date-time. %z specifier represents UTC offset, %Z returns time zone abbreviation.

format(dt1, "%F %H:%M")
## [1] "2024-08-02 16:00" "2024-08-02 16:15" "2024-08-02 16:30" "2024-08-02 16:45"
format(dt1, "%F %H:%M%z")
## [1] "2024-08-02 16:00+0200" "2024-08-02 16:15+0200" "2024-08-02 16:30+0200"
## [4] "2024-08-02 16:45+0200"
format(dt1, "%F %H:%M %Z")
## [1] "2024-08-02 16:00 CEST" "2024-08-02 16:15 CEST" "2024-08-02 16:30 CEST"
## [4] "2024-08-02 16:45 CEST"
format(dt1, "%D %I:%M%p")
## [1] "08/02/24 04:00pm" "08/02/24 04:15pm" "08/02/24 04:30pm" "08/02/24 04:45pm"

Standard formats are automatically recognized during parsing.

as.tind("2025-02-01 13:03")
## date-time, time zone: Europe/Warsaw [tind]
## [1]  2025-02-01 13:03 CET
as.tind("2025-02-01 13:03:34")
## date-time, time zone: Europe/Warsaw [tind]
## [1]  2025-02-01 13:03:34 CET
as.tind("2025-02-01 13:03:34.534")
## date-time, time zone: Europe/Warsaw [tind]
## [1]  2025-02-01 13:03:34.534 CET

When converting to tind, either format or order arguments can be provided.

as.tind("2025-02-01 13:03:34.534", format = "%F %H:%M:%OS")
## date-time, time zone: Europe/Warsaw [tind]
## [1]  2025-02-01 13:03:34.534 CET
as.tind("02/01/25 01:03:34pm", format = "%D %I:%M:%OS%p")
## date-time, time zone: Europe/Warsaw [tind]
## [1]  2025-02-01 13:03:34 CET
as.tind("2025-02-01 13:03:34.534", order = "ymdHMS")
## date-time, time zone: Europe/Warsaw [tind]
## [1]  2025-02-01 13:03:34.534 CET
as.tind("2025-02-01 13:03:34.534", order = "ymdHMS", tz = "UTC")
## date-time, time zone: UTC [tind]
## [1]  2025-02-01 13:03:34.534 UTC
as.tind("02/01/25 01:03:34pm", order = "mdyIMSp")
## date-time, time zone: Europe/Warsaw [tind]
## [1]  2025-02-01 13:03:34 CET
as.tind("02/01/25 01:03:34pm", order = "mdyIMSp", tz = "UTC")
## date-time, time zone: UTC [tind]
## [1]  2025-02-01 13:03:34 UTC

The parser recognizes time zone abbreviations:

as.tind("2025-02-22 09:54:04 CET", tz = "Europe/Warsaw")
## date-time, time zone: Europe/Warsaw [tind]
## [1]  2025-02-22 09:54:04 CET
as.tind("2025-08-23 09:54:04 CEST", tz = "Europe/Warsaw")
## date-time, time zone: Europe/Warsaw [tind]
## [1]  2025-08-23 09:54:04 CEST
as.tind("2/22/25 9:54 a.m. EST", order = "mdyIMpz", tz = "America/New_York")
## date-time, time zone: America/New_York [tind]
## [1]  2025-02-22 09:54 EST
as.tind("8/23/25 9:54 a.m. EDT", order = "mdyIMpz", tz = "America/New_York")
## date-time, time zone: America/New_York [tind]
## [1]  2025-08-23 09:54 EDT

When time zone is not provided, the parser tries to guess the time zone:

as.tind("2025-02-22 09:54:04 CET")
## date-time, time zone: Europe/Warsaw [tind]
## [1]  2025-02-22 09:54:04 CET
as.tind("2025-08-23 09:54:04 CEST")
## date-time, time zone: Europe/Warsaw [tind]
## [1]  2025-08-23 09:54:04 CEST
as.tind("2/22/25 9:54 a.m. EST", order = "mdyIMpz")
## date-time, time zone: America/New_York [tind]
## [1]  2025-02-22 09:54 EST
as.tind("8/23/25 9:54 a.m. EDT", order = "mdyIMpz")
## date-time, time zone: America/New_York [tind]
## [1]  2025-08-23 09:54 EDT

When time zone abbreviation can denote different UTC offsets (unfortunately, this can be the case) NAs are introduced with a warning.

Arbitrary Numeric Indices

For completeness, tind supports arbitrary integer indices (code i) and arbitrary numeric indices (code n).

as.tind(0:9, type = "i")
## integer index [tind]
##  [1] 0 1 2 3 4 5 6 7 8 9
as.tind(0:9 / 10, type = "n")
## numeric index [tind]
##  [1] 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9

Index Conversion

Time index conversion is extremely easy with tind class. as.tind method as well as as.year, as.date, etc. convenience functions can be used for this.

ms
## month [tind]
##  [1] 2023-01 2023-02 2023-03 2023-04 2023-05 2023-06 2023-07 2023-08 2023-09
## [10] 2023-10 2023-11 2023-12
as.quarter(ms)
## quarter [tind]
##  [1] 2023Q1 2023Q1 2023Q1 2023Q2 2023Q2 2023Q2 2023Q3 2023Q3 2023Q3 2023Q4
## [11] 2023Q4 2023Q4
as.year(ms)
## year [tind]
##  [1] 2023 2023 2023 2023 2023 2023 2023 2023 2023 2023 2023 2023
as.date(ms)
## date [tind]
##  [1] 2023-01-01 2023-02-01 2023-03-01 2023-04-01 2023-05-01 2023-06-01
##  [7] 2023-07-01 2023-08-01 2023-09-01 2023-10-01 2023-11-01 2023-12-01
as.date_time(ms)
## date-time, time zone: Europe/Warsaw [tind]
##  [1]  2023-01-01 00:00 CET   2023-02-01 00:00 CET   2023-03-01 00:00 CET 
##  [4]  2023-04-01 00:00 CEST  2023-05-01 00:00 CEST  2023-06-01 00:00 CEST
##  [7]  2023-07-01 00:00 CEST  2023-08-01 00:00 CEST  2023-09-01 00:00 CEST
## [10]  2023-10-01 00:00 CEST  2023-11-01 00:00 CET   2023-12-01 00:00 CET
as.date_time(ms, tz = "UTC")
## date-time, time zone: UTC [tind]
##  [1]  2023-01-01 00:00 UTC  2023-02-01 00:00 UTC  2023-03-01 00:00 UTC
##  [4]  2023-04-01 00:00 UTC  2023-05-01 00:00 UTC  2023-06-01 00:00 UTC
##  [7]  2023-07-01 00:00 UTC  2023-08-01 00:00 UTC  2023-09-01 00:00 UTC
## [10]  2023-10-01 00:00 UTC  2023-11-01 00:00 UTC  2023-12-01 00:00 UTC

Coercion to Base R Types

as.Date, as.POSIXct, and as.POSIXlt can be used to convert time indices to base R date and date-time classes.

ds
## date [tind]
## [1] 2024-01-01 2024-01-16 2024-02-01 2024-02-16 2024-03-01 2024-03-16
as.Date(ds)
## [1] "2024-01-01" "2024-01-16" "2024-02-01" "2024-02-16" "2024-03-01"
## [6] "2024-03-16"
dt1
## date-time, time zone: Europe/Warsaw [tind]
## [1]  2024-08-02 16:00 CEST  2024-08-02 16:15 CEST  2024-08-02 16:30 CEST
## [4]  2024-08-02 16:45 CEST
as.POSIXct(dt1)
## [1] "2024-08-02 16:00:00 CEST" "2024-08-02 16:15:00 CEST"
## [3] "2024-08-02 16:30:00 CEST" "2024-08-02 16:45:00 CEST"
dt2
## date-time, time zone: UTC [tind]
## [1]  2024-08-02 16:00 UTC  2024-08-02 16:15 UTC  2024-08-02 16:30 UTC
## [4]  2024-08-02 16:45 UTC
as.POSIXlt(dt2)
## [1] "2024-08-02 16:00:00 UTC" "2024-08-02 16:15:00 UTC"
## [3] "2024-08-02 16:30:00 UTC" "2024-08-02 16:45:00 UTC"

Matching Periods, Comparisons, cut Method

match_t function and %in_t% operator allow to match time indices to another set of time indices, possibly of different type (lower resolution).

In the following example, a sequence of dates is matched to months:

(x <- as.date("2025-03-02") + 15 * (0:5))
## date [tind]
## [1] 2025-03-02 2025-03-17 2025-04-01 2025-04-16 2025-05-01 2025-05-16
(table <- as.month("2025-03") + -1:1)
## month [tind]
## [1] 2025-02 2025-03 2025-04
match_t(x, table)
## [1]  2  2  3  3 NA NA

Below we check which dates fall in March 2025:

x %in_t% "2025-03"
## [1]  TRUE  TRUE FALSE FALSE FALSE FALSE

Comparison operators (e.g., >, >=) can be used to compare time indices. Below we check which dates fall in or after April 2025 and before April 2025:

x >= "2025-04"
## [1] FALSE FALSE  TRUE  TRUE  TRUE  TRUE
x < "2025-04"
## [1]  TRUE  TRUE FALSE FALSE FALSE FALSE

cut method for object of tind class divides time indices into periods. Using x from the last example, we can split dates into months and quarters:

cut(x, "m")
## [1] 2025-03 2025-03 2025-04 2025-04 2025-05 2025-05
## Levels: 2025-03 < 2025-04 < 2025-05
cut(x, "q")
## [1] 2025Q1 2025Q1 2025Q2 2025Q2 2025Q2 2025Q2
## Levels: 2025Q1 < 2025Q2