Skip to contents

cycle_time() cycles time span objects in a predetermined cycle length, adapting linear time objects into a circular time frame.

## Usage

cycle_time(time, cycle, reverse = TRUE)

## Arguments

time

An object belonging to one of the following classes: numeric, Duration, difftime, or hms.

cycle

A numeric or Duration object of length 1, equal or greater than 0, indicating the cycle length in seconds. See the Details section to learn more.

reverse

(optional) a logical value indicating if the function must use a reverse cycle for negative values in time. See the Details section to learn more (default: TRUE).

## Value

The same type of object of time cycled with the cycle parameter.

## Details

### Linear versus circular time

Time can have different "shapes".

If the objective is to measure the duration (time span) of an event, time is usually measured considering a linear frame, with a fixed point of origin. In this context, the time value distance itself to infinity in relation to the origin.

                                   B
|----------|
A
|---------------------|
- inf                                                inf +
<----------------------------|----------|----------|------->
s                           0          5          10     s
origin

A + B = 10 + 5 = 15s


But that's not the only possible "shape" of time, as it can also be measured in other contexts.

In a "time of day" context, the time will be linked to the rotation of the earth, "resetting" when a new rotation cycle starts. That brings a different kind of shape to time: a circular shape. With this shape the time value encounters the origin at the beginning and end of each cycle.

               - <--- h ---> +
origin
. . . 0 . . .
.                 .
.                   .
.                     .
.                       .
.                         .
18                        6
.                         .
.                       .
.                     .
.                   .
.                 .
. . . 12 . . .

18 + 6 = 0h


If we transpose this circular time frame to a linear one, it would look like this:

<----|---------------|---------------|---------------|----->
0h              12h              0h             12h
origin                           origin


Note that now the origin is not fix, but cyclical.

cycle_time() operates by converting linear time objects using a circular approach relative to the cycle length (e.g, cycle = 86400 (1 day)).

### Fractional time

cycle_time() uses the %% operator to cycle values. Hence, it can be subject to catastrophic loss of accuracy if time is fractional and much larger than cycle. A warning is given if this is detected.

%% is a builtin R function that operates like this:

function(a, b) {
a - floor(a / b) * b
}

### Negative time cycling

If time have a negative value and reverse == FALSE, cycle_time() will perform the cycle considering the absolute value of time and return the result with a negative signal.

However, If time have a negative value and reverse == TRUE (default), cycle_time() will perform the cycle in reverse, relative to its origin.

Example: If you have a -30h time span in a reversed cycle of 24h, the result will be 18h. By removing the full cycles of -30h you will get -6h (-30 + 24), and -6h relative to the origin will be 18h.

               - <--- h ---> +
origin
. . . 0 . . .
.                 .
.                   .
.                     .
.                       .
.                         .
(-6) 18                        6 (-18)
.                         .
.                       .
.                     .
.                   .
.                 .
. . . 12 . . .
(-12)


### Period objects

Period objects 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 a irregularity event.

Since the time span of a Period object can fluctuate, cycle_time() don't accept this kind of object. You can transform it to a Duration object and still use the function, but beware that this can produce errors.

Learn more about Period objects in the Dates and times chapter of Wickham & Grolemund book (n.d.).

## References

Wickham, H., & Grolemund, G. (n.d.). R for data science. Sebastopol, CA: O'Reilly Media. https://r4ds.had.co.nz

## See also

Other utility functions: assign_date(), pretty_mctq(), qplot_walk(), random_mctq(), raw_data(), round_time(), shorter_interval(), sum_time()

## Examples

## Scalar example

time <- lubridate::dhours(25)
cycle <- lubridate::ddays(1)
cycle_time(time, cycle)
#> [1] "3600s (~1 hours)"
#> [1] "3600s (~1 hours)" # Expected

time <- lubridate::dhours(-25)
cycle <- lubridate::ddays(1)
reverse <- FALSE
cycle_time(time, cycle, reverse)
#> [1] "-3600s (~-1 hours)"
#> [1] "-3600s (~-1 hours)" # Expected

time <- lubridate::dhours(-25)
cycle <- lubridate::ddays(1)
reverse <- TRUE
cycle_time(time, cycle, reverse)
#> [1] "82800s (~23 hours)"
#> [1] "82800s (~23 hours)" # Expected

## Vector example

time <- c(lubridate::dmonths(24), lubridate::dmonths(13))
cycle <- lubridate::dyears(1)
cycle_time(time, cycle)
#> [1] "0s"                     "2629800s (~4.35 weeks)"
#> [1] "0s"                     "2629800s (~4.35 weeks)" # Expected

time <- c(lubridate::dmonths(24), lubridate::dmonths(-13))
cycle <- lubridate::dyears(1)
reverse <- FALSE
cycle_time(time, cycle, reverse)
#> [1] "0s"                       "-2629800s (~-4.35 weeks)"
#> [1] "0s"                       "-2629800s (~-4.35 weeks)" # Expected

time <- c(lubridate::dmonths(24), lubridate::dmonths(-13))
cycle <- lubridate::dyears(1)
reverse <- TRUE
cycle_time(time, cycle, reverse)
#> [1] "0s"                       "28927800s (~47.83 weeks)"
#> [1] "0s"                       "28927800s (~47.83 weeks)" # Expected