Skip to contents

This article explains why the mctq package uses Duration instead of Period (objects from the lubridate package) as the default object for time spans.

Duration versus Period objects

The lubridate package offers three types of objects for storing and manipulating time spans: Duration, Period, and Interval.

To understand the difference between Duration and Period objects you must first remember that the timeline is not always consistent, as it can have irregularities caused by, for example, leap years, DST (Daylight Saving Time), or leap seconds. That’s when Period objects differ from Duration objects.

Duration objects represent time spans by their exact number of seconds. That is, a Duration object of 1 hour will always represent a 1-hour time span, even with possible timeline irregularities.

start <- lubridate::ymd_hms("2020-01-01 10:00:00", tz = "America/New_York")
#> Warning in system("timedatectl", intern = TRUE): running command 'timedatectl'
#> had status 1

start + lubridate::duration(1, units = "hour")
#> [1] "2020-01-01 11:00:00 EST"

Period objects work a little bit differently. They are a special type of object developed by the lubridate team that represents “human units”, ignoring possible timeline irregularities. That is to say that 1 day as Period can have different time spans when looking to a timeline after an irregular event.

To illustrate this behavior, take the case of a DST event, starting at 2016-03-13 01:00:00 EST.

start <- lubridate::ymd_hms("2016-03-13 01:00:00", tz = "America/New_York")

start + lubridate::duration(1, units = "hour")
#> [1] "2016-03-13 03:00:00 EDT"
start + lubridate::period(1, units = "hour")
#> [1] NA

You might ask: why the result is NA when adding 1 hour as a Period object? That’s because Period objects ignore time irregularities. When the DST starts at 01:00:00 the timeline “jumps” to 03:00:00, so the period from 02:00:00 to 02:59:59 doesn’t exist.

base: 2016-03-13 01:00:00, tz = "America/New_York" 

                        DST + 1 hour
-----|---------------|               |---------------|----->
  01:00             NA           03:00           04:00

From the `Duration` perspective: base + 1 hour = 2016-03-13 03:00:00

     |-------------------------------|---------------|
                   1 hour                  1 hour

From the `Period` perspective: base + 1 hour = NA

     |---------------|---------------|---------------|
           1 hour          1 hour          1 hour

Period objects are useful when you need to consider the human units of time. For example:

start <- lubridate::ymd_hms("2016-03-13 01:00:00", tz = "America/New_York")

start + lubridate::duration(1, units = "day")
#> [1] "2016-03-14 02:00:00 EDT"
start + lubridate::period(1, units = "day")
#> [1] "2016-03-14 01:00:00 EDT"

In this case, 1 day, by human standards, represents the same time of day of the next day. But, considering the DST event, that 1 day has a time span of 23 hours.

You can learn more about lubridate time span objects in the Dates and times chapter from Wickham & Grolemund’s book “R for Data Science”.

The MCTQ context

At first glance you might think that, since MCTQ was made for human respondents, the best representation for time spans would be the one that better represents “human units”, right? That would be fine if we were talking about a time span in a timeline irregularity context, but MCTQ doesn’t deal with this scenario.

When using MCTQ, the interest is to measure the exact time span between one local time to another. By ignoring irregularities in the timeline, Periods produce a fluctuating time span, hence Period objects are not compatible with other time spans like objects (e.g., hms).

hms::parse_hm("10:00") + lubridate::period(1, units = "hours")

#> Error: Incompatible classes: <hms> + <Period>

In summary, Period objects were made considering a very specific context that doesn’t apply to MCTQ. That’s why Duration objects are the default object for time spans.