1#' @include timespans.r
2#' @include util.r
3#' @include durations.r
4NULL
5
6check_period <- function(object) {
7  errors <- character()
8
9  length(object@.Data) -> n
10  lengths <- c(length(object@year), length(object@month),
11               length(object@day), length(object@hour), length(object@minute))
12
13  if (any(lengths != n)) {
14    msg <- paste("Inconsistent lengths: year = ", lengths[1],
15      ", month = ", lengths[2],
16      ", day = ", lengths[3],
17      ", hour = ", lengths[4],
18      ", minute = ", lengths[5],
19      ", second = ", n,
20      sep = "")
21    errors <- c(errors, msg)
22  }
23
24  values <- c(object@year, object@month, object@day, object@hour, object@minute)
25  values <- na.omit(values)
26  if (sum(values - trunc(values))) {
27    msg <- "periods must have integer values"
28    errors <- c(errors, msg)
29  }
30
31  if (length(errors) == 0)
32    TRUE
33  else
34    errors
35}
36
37#' Period class
38#'
39#' Period is an S4 class that extends the [Timespan-class] class.
40#' Periods track the change in the "clock time" between two date-times. They
41#' are measured in common time related units: years, months, days, hours,
42#' minutes, and seconds. Each unit except for seconds must be expressed in
43#' integer values.
44#'
45#' The exact length of a period is not defined until the period is placed at a
46#' specific moment of time. This is because the precise length of one year,
47#' month, day, etc. can change depending on when it occurs due to daylight savings,
48#' leap years, and other conventions. A period can be
49#' associated with a specific moment in time by coercing it to an
50#' [Interval-class] object with [as.interval()] or by adding
51#' it to a date-time with "+".
52#'
53#' Periods provide a method for measuring generalized timespans when we wish to
54#' model clock times. Periods will attain intuitive results at this task even
55#' when leap years, leap seconds, gregorian days, daylight savings changes, and
56#' other events happen during the period.
57#'
58#' Because Period represents imprecise amount of time it cannot be compared to
59#' precise timestamps as Durations and Intervals are. You need to explicitely
60#' convert to durations. See [Duration-class].
61#'
62#' The logic that guides arithmetic with periods can be unintuitive. Starting
63#' with version 1.3.0, \pkg{lubridate} enforces the reversible property of arithmetic
64#' (e.g. a date + period - period = date) by returning an NA if you create an
65#' implausible date by adding periods with months or years units to a date. For
66#' example,  adding one month to January 31st, 2013 results in February 31st,
67#' 2013, which is not a real date. \pkg{lubridate} users have argued in the past that
68#' February 31st, 2013 should be rolled over to March 3rd, 2013 or rolled back
69#' to February 28, 2013. However, each of these corrections would destroy the
70#' reversibility of addition (Mar 3 - one month == Feb 3 != Jan 31, Feb 28 - one
71#' month == Jan 28 != Jan 31). If you would like to add and subtract months in a
72#' way that rolls the results back to the last day of a month (when appropriate)
73#' use the special operators, \code{\link{\%m+\%}},  \code{\link{\%m-\%}} or a
74#' bit more flexible [add_with_rollback()].
75#'
76#' Period class objects have six slots. 1) .Data, a numeric object. The
77#' apparent amount of seconds to add to the period. 2) minute, a numeric object.
78#' The apparent amount of minutes to add to the period. 3) hour, a numeric object.
79#' The apparent amount of hours to add to the period.4) day, a numeric object.
80#' The apparent amount of days to add to the period.5) month, a numeric object.
81#' The apparent amount of months to add to the period. 6) year, a numeric object.
82#' The apparent amount of years to add to the period.
83#'
84#' @export
85#' @keywords internal
86setClass("Period", contains = c("Timespan", "numeric"),
87  slots = c(year = "numeric", month = "numeric", day = "numeric",
88    hour = "numeric", minute = "numeric"),
89  prototype = prototype(year = 0, month = 0, day = 0, hour = 0, minute = 0),
90  validity = check_period)
91
92#' @name hidden_aliases
93#' @aliases Arith,ANY,Period-method Arith,Duration,Period-method
94#'   Arith,Period,Duration-method Compare,Period,Duration-method
95#'   Compare,numeric,Period-method Compare,difftime,Period-method
96#'   Compare,Period,difftime-method Compare,Period,Period-method
97#'   Compare,Period,character-method Compare,Period,numeric-method
98#'   Compare,character,Period-method second,Period-method second<-,Period-method
99#'   minute,Period-method minute<-,Period-method hour,Period-method
100#'   hour<-,Period-method Arith,Period,ANY-method day,Period-method
101#'   day<-,Period-method month,Period-method month<-,Period-method
102#'   year,Period-method year<-,Period-method date,Period-method
103#'   date<-,Period-method as.numeric,Period-method show,Period-method
104#'   c,Period-method rep,Period-method [,Period-method
105#'   [<-,Period,ANY,ANY,Period-method [[,Period-method
106#'   [[<-,Period,ANY,ANY,Period-method $,Period-method $<-,Period-method
107#'   as.difftime,Period-method as.character,Period-method
108#'   +,Period,Duration-method +,Period,Interval-method +,Period,Period-method
109#'   +,Period,Date-method +,Date,Period-method +,Period,difftime-method
110#'   +,difftime,Period-method +,Period,numeric-method +,numeric,Period-method
111#'   +,Period,POSIXct-method +,POSIXct,Period-method +,Period,POSIXlt-method
112#'   +,POSIXlt,Period-method /,Period,Duration-method /,Period,Interval-method
113#'   /,Period,Period-method /,Period,difftime-method /,difftime,Period-method
114#'   /,Period,numeric-method /,numeric,Period-method *,Period,ANY-method
115#'   *,ANY,Period-method -,Period,ANY-method -,Period,missing-method
116#'   -,ANY,Period-method -,Period,Period-method %%,Period,Duration-method
117#'   %%,Period,Interval-method %%,Period,Period-method >,Period,Period-method
118#'   >=,Period,Period-method ==,Period,Period-method !=,Period,Period-method
119#'   <=,Period,Period-method <,Period,Period-method >,Period,Duration-method
120#'   >=,Period,Duration-method ==,Period,Duration-method
121#'   !=,Period,Duration-method <=,Period,Duration-method
122#'   <,Period,Duration-method >,Duration,Period-method >=,Duration,Period-method
123#'   ==,Duration,Period-method !=,Duration,Period-method
124#'   <=,Duration,Period-method <,Duration,Period-method >,Period,numeric-method
125#'   >=,Period,numeric-method ==,Period,numeric-method !=,Period,numeric-method
126#'   <=,Period,numeric-method <,Period,numeric-method >,numeric,Period-method
127#'   >=,numeric,Period-method ==,numeric,Period-method !=,numeric,Period-method
128#'   <=,numeric,Period-method <,numeric,Period-method !=,Duration,Period
129#'   !=,Period,Duration !=,Period,Period !=,Period,numeric !=,numeric,Period
130#'   %%,Period,Duration %%,Period,Interval %%,Period,Period *,ANY,Period
131#'   *,Period,ANY -,ANY,Period -,Period,Interval -,Period,missing
132#'   /,numeric,Period <,Duration,Period <,Period,Duration <,Period,Period
133#'   <,Period,numeric <,numeric,Period <=,Duration,Period <=,Period,Duration
134#'   <=,Period,Period <=,Period,numeric <=,numeric,Period ==,Duration,Period
135#'   ==,Period,Duration ==,Period,Period ==,Period,numeric ==,numeric,Period
136#'   >,Duration,Period >,Period,Duration >,Period,Period >,Period,numeric
137#'   >,numeric,Period >=,Duration,Period >=,Period,Duration >=,Period,Period
138#'   >=,Period,numeric >=,numeric,Period
139NULL
140
141setMethod("initialize", "Period", function(.Object, ...) {
142  dots <- list(...)
143  names(dots)[!nzchar(allNames(dots))] <- ".Data"
144  lens <- unlist(lapply(dots, length), F, F)
145
146  ## if any 0-length components, the entire object is 0-length
147  if (any(lens == 0)) {
148    for (nm in slotNames(.Object))
149      slot(.Object, nm) <- numeric()
150    validObject(.Object)
151    return(.Object)
152  }
153
154  len <- max(lens)
155  nas <- FALSE
156  for (nm in slotNames(.Object)) {
157    el <-
158      if (is.null(obj <- dots[[nm]])) {
159        rep.int(0L, len)
160      } else {
161        if (length(obj) < len) rep_len(obj, len)
162        else obj
163      }
164    nas <- nas | is.na(el)
165    slot(.Object, nm) <- el
166  }
167
168  ## If any component has NAs the entire object should have those NAs
169  if (any(nas)) {
170    for (nm in slotNames(.Object)) {
171      slot(.Object, nm)[nas] <- NA_real_
172    }
173  }
174
175  validObject(.Object)
176  .Object
177})
178
179#' @export
180setMethod("show", signature(object = "Period"), function(object) {
181  if (length(object@.Data) == 0) {
182    cat("<Period[0]>\n")
183  } else {
184    print(format(object))
185  }
186})
187
188#' @export
189format.Period <- function(x, ...) {
190  if (length(x) == 0) {
191    return(character())
192  }
193
194  show <- paste(
195    x@year, "y ", x@month, "m ", x@day, "d ",
196    x@hour, "H ", x@minute, "M ", x@.Data, "S",
197    sep = ""
198  )
199  start <- regexpr("[-1-9]|(0\\.)", show)
200  show <- ifelse(start > 0, substr(show, start, nchar(show)), "0S")
201
202  show[is.na(x)] <- NA
203  show
204}
205
206#' @export
207xtfrm.Period <- function(x) {
208  xtfrm(period_to_seconds(x))
209}
210
211#' @export
212setMethod("c", signature(x = "Period"), function(x, ...) {
213  dots <- list(...)
214  nempty <- sapply(dots, length) != 0
215  elements <- lapply(dots[nempty], as.period)
216  seconds <- c(x@.Data, unlist(lapply(elements, slot, ".Data")))
217  years <- c(x@year, unlist(lapply(elements, slot, "year")))
218  months <- c(x@month, unlist(lapply(elements, slot, "month")))
219  days <- c(x@day, unlist(lapply(elements, slot, "day")))
220  hours <- c(x@hour, unlist(lapply(elements, slot, "hour")))
221  minutes <- c(x@minute, unlist(lapply(elements, slot, "minute")))
222  new("Period", seconds, year = years, month = months, day = days,
223    hour = hours, minute = minutes)
224})
225
226#' @export
227setMethod("rep", signature(x = "Period"), function(x, ...) {
228  new("Period", rep(x@.Data, ...), year = rep(x@year, ...),
229    month = rep(x@month, ...), day = rep(x@day, ...),
230    hour = rep(x@hour, ...), minute = rep(x@minute, ...))
231})
232
233#' @export
234setMethod("[", signature(x = "Period"),
235  function(x, i, j, ..., drop = TRUE) {
236    new("Period", x@.Data[i], year = x@year[i], month = x@month[i],
237      day = x@day[i], hour = x@hour[i], minute = x@minute[i])
238})
239
240#' @export
241setMethod("[[", signature(x = "Period"),
242          function(x, i, j, ..., exact = TRUE) {
243            new("Period", x@.Data[i], year = x@year[i], month = x@month[i],
244                day = x@day[i], hour = x@hour[i], minute = x@minute[i])
245})
246
247#' @export
248setMethod("[<-", signature(x = "Period", value = "Period"),
249  function(x, i, j, ..., value) {
250    x@.Data[i] <- value@.Data
251    x@year[i] <- value@year
252    x@month[i] <- value@month
253    x@day[i] <- value@day
254    x@hour[i] <- value@hour
255    x@minute[i] <- value@minute
256    x
257})
258
259#' @export
260setMethod("[[<-", signature(x = "Period", value = "Period"),
261          function(x, i, j, ..., value) {
262            x@.Data[i] <- value@.Data
263            x@year[i] <- value@year
264            x@month[i] <- value@month
265            x@day[i] <- value@day
266            x@hour[i] <- value@hour
267            x@minute[i] <- value@minute
268            x
269})
270
271#' @export
272setMethod("$", signature(x = "Period"), function(x, name) {
273  if (name == "second") name <- ".Data"
274    slot(x, name)
275})
276
277#' @export
278setMethod("$<-", signature(x = "Period"), function(x, name, value) {
279  if (name == "second") name <- ".Data"
280    slot(x, name) <- rep_len(value, length(x))
281    x
282})
283
284#' Create or parse period objects
285#'
286#' `period()` creates or parses a period object with the specified values.
287#'
288#' Within a Period object, time units do not have a fixed length (except for
289#' seconds) until they are added to a date-time. The length of each time unit
290#' will depend on the date-time to which it is added. For example, a year that
291#' begins on 2009-01-01 will be 365 days long.  A year that begins on 2012-01-01
292#' will be 366 days long. When math is performed with a period object, each unit
293#' is applied separately. How the length of a period is distributed among its
294#' units is non-trivial. For example, when leap seconds occur 1 minute is longer
295#' than 60 seconds.
296#'
297#' Periods track the change in the "clock time" between two date-times. They
298#' are measured in common time related units: years, months, days, hours,
299#' minutes, and seconds. Each unit except for seconds must be expressed in
300#' integer values.
301#'
302#' Besides the main constructor and parser [period()], period objects can also
303#' be created with the specialized functions [years()], [months()], [weeks()],
304#' [days()], [hours()], [minutes()], and [seconds()]. These objects can be added
305#' to and subtracted to date-times to create a user interface similar to object
306#' oriented programming.
307#'
308#' Note: Arithmetic with periods can result in undefined behavior when
309#' non-existent dates are involved (such as February 29th in non-leap years).
310#' Please see [Period-class] for more details and \code{\link{\%m+\%}} and
311#' [add_with_rollback()] for alternative operations.
312#'
313#' @name period
314#' @aliases periods
315#' @param num a numeric or character vector. A character vector can specify
316#'   periods in a convenient shorthand format or ISO 8601 specification. All
317#'   unambiguous name units and abbreviations are supported, "m" stands for
318#'   months, "M" for minutes unless ISO 8601 "P" modifier is present (see
319#'   examples). Fractional units are supported but the fractional part is always
320#'   converted to seconds.
321#' @param units a character vector that lists the type of units to be used. The
322#'   units in units are matched to the values in num according to their
323#'   order. When `num` is character, this argument is ignored.
324#' @param ... a list of time units to be included in the period and their
325#'   amounts. Seconds, minutes,  hours, days, weeks, months, and years are
326#'   supported. Normally only one of `num` or `...` are present. If both are
327#'   present, the periods are concatenated.
328#' @param x Any R object for `is.periods` and a numeric value of the number of
329#'   units for elementary constructors. With the exception of seconds(), x must
330#'   be an integer.
331#' @param abbreviate Ignored. For consistency with S3 generic in base namespace.
332#' @seealso [Period-class], [period()], \code{\link{\%m+\%}},
333#'   [add_with_rollback()]
334#' @return a period object
335#' @keywords chron classes
336#' @examples
337#'
338#' ### Separate period and units vectors
339#'
340#' period(c(90, 5), c("second", "minute"))
341#' #  "5M 90S"
342#' period(-1, "days")
343#' period(c(3, 1, 2, 13, 1), c("second", "minute", "hour", "day", "week"))
344#' period(c(1, -60), c("hour", "minute"))
345#' period(0, "second")
346#'
347#' ### Units as arguments
348#'
349#' period (second = 90, minute = 5)
350#' period(day = -1)
351#' period(second = 3, minute = 1, hour = 2, day = 13, week = 1)
352#' period(hour = 1, minute = -60)
353#' period(second = 0)
354#' period(c(1, -60), c("hour", "minute"), hour = c(1, 2), minute = c(3, 4))
355#'
356#' ### Lubridate style parsing
357#'
358#' period("2M 1sec")
359#' period("2hours 2minutes 1second")
360#' period("2d 2H 2M 2S")
361#' period("2days 2hours 2mins 2secs")
362#' period("2 days, 2 hours, 2 mins, 2 secs")
363#' # Missing numerals default to 1. Repeated units are added up.
364#' duration("day day")
365#'
366#' ### ISO 8601 parsing
367#'
368#' period("P10M23DT23H") # M stands for months
369#' period("10DT10M") # M stands for minutes
370#' period("P3Y6M4DT12H30M5S") # M for both minutes and months
371#' period("P23DT60H 20min 100 sec") # mixing ISO and lubridate style parsing
372#'
373#' ### Comparison with characters (from v1.6.0)
374#'
375#' duration("day 2 sec") > "day 1sec"
376#'
377#' ### Elementary Constructors
378#'
379#' x <- ymd("2009-08-03")
380#' x + days(1) + hours(6) + minutes(30)
381#' x + days(100) - hours(8)
382#'
383#' class(as.Date("2009-08-09") + days(1)) # retains Date class
384#' as.Date("2009-08-09") + hours(12)
385#' class(as.Date("2009-08-09") + hours(12))
386#' # converts to POSIXt class to accomodate time units
387#'
388#' years(1) - months(7)
389#' c(1:3) * hours(1)
390#' hours(1:3)
391#'
392#' # sequencing
393#' y <- ymd(090101) # "2009-01-01 CST"
394#' y + months(0:11)
395#'
396#' # compare DST handling to durations
397#' boundary <- ymd_hms("2009-03-08 01:59:59", tz="America/Chicago")
398#' boundary + days(1) # period
399#' boundary + ddays(1) # duration
400#' @export
401period <- function(num = NULL, units = "second", ...) {
402  if (is.character(num)) {
403    parse_period(num)
404  } else {
405    out1 <- .period_from_num(num, units)
406    out2 <- .period_from_units(list(...))
407    if (is.null(out1) && is.null(out2)) new("Period", numeric())
408    else if (is.null(out1)) out2
409    else if (is.null(out2)) out1
410    else c(out1, out2)
411  }
412}
413
414parse_period <- function(x) {
415  out <- .Call(C_parse_period, as.character(x))
416  new("Period",
417      out[1, ],
418      minute = out[2, ],
419      hour   = out[3, ],
420      day    = out[4, ] + 7L*out[5, ],
421      month  = out[6, ],
422      year   = out[7, ])
423}
424
425.period_from_num <- function(num, units) {
426  if (length(num) == 0)
427    return(NULL)
428
429  if (!is.numeric(num)) {
430    stop(sprintf("First argument to `period()` constructor must be character or numeric. Supplied object of class '%s'", class(num)))
431  }
432
433  ## qucik check for common wrongdoings: #462
434  if (inherits(num, c("Interval", "Duration")))
435    stop("Interval or Durations objects cannot be used as input to 'period()' constructor. Plese use 'as.period()'.")
436
437  if (length(units) %% length(num) != 0)
438    stop("Arguments `num` and `units` must have same length")
439
440  .period_from_units(structure(num, names = units))
441}
442
443.period_from_units <- function(pieces) {
444  if (length(pieces) == 0)
445    return(NULL)
446
447  if (!is.numeric(pieces))
448    pieces <- lapply(pieces, as.numeric)
449
450  out <- list(second = 0, minute = 0, hour = 0, day = 0,
451              week = 0, month = 0, year = 0)
452
453  unit <- standardise_date_names(names(pieces))
454  for (i in seq_along(unit)) {
455    nm <- unit[[i]]
456    out[[nm]] <- out[[nm]] + pieces[[i]]
457  }
458  out$day <- out$day + 7 * out$week
459
460  new("Period", out$second, year = out$year, month = out$month,
461      day = out$day, hour = out$hour, minute = out$minute)
462}
463
464#' @rdname period
465#' @examples
466#' is.period(as.Date("2009-08-03")) # FALSE
467#' is.period(period(months= 1, days = 15)) # TRUE
468#' @export
469is.period <- function(x) is(x, "Period")
470
471#' @export seconds minutes hours days weeks years milliseconds microseconds microseconds nanoseconds picoseconds
472#' @rdname period
473seconds <- function(x = 1) period(second = x)
474#' @rdname period
475minutes <- function(x = 1) period(minute = x)
476#' @rdname period
477hours <- function(x = 1) period(hour = x)
478#' @rdname period
479days <- function(x = 1) period(day = x)
480#' @rdname period
481weeks <- function(x = 1) period(week = x)
482#' @rdname period
483years <- function(x = 1) period(year = x)
484#' @rdname period
485milliseconds <- function(x = 1) seconds(x/1000)
486#' @rdname period
487microseconds <- function(x = 1) seconds(x/1000000)
488#' @rdname period
489nanoseconds <- function(x = 1) seconds(x/1e9)
490#' @rdname period
491picoseconds <- function(x = 1) seconds(x/1e12)
492
493#' @rdname period
494#' @export
495months.numeric <- function(x, abbreviate) {
496  period(month = x)
497}
498
499#' Contrive a period to/from a given number of seconds
500#'
501#' `period_to_seconds()` approximately converts a period to seconds assuming
502#' there are 365.25 days in a calendar year and 365.25/12 days in a month.
503#'
504#' @param x A numeric object. The number of seconds to coerce into a period.
505#' @return A number (period) that roughly equates to the period (seconds) given.
506#' @export
507period_to_seconds <- function(x) {
508  x@.Data +
509    60 * x@minute +
510    60 * 60 * x@hour +
511    60 * 60 * 24 * x@day +
512    60 * 60 * 24 * 365.25 / 12 * x@month +
513    60 * 60 * 24 * 365.25 * x@year
514}
515
516#' @description
517#' `seconds_to_period()` create a period that has the maximum number of
518#' non-zero elements (days, hours, minutes, seconds). This computation is exact
519#' because it doesn't involve years or months.
520#' @rdname period_to_seconds
521#' @export
522seconds_to_period <- function(x) {
523  span <- as.double(x)
524  remainder <- abs(span)
525  newper <- period(second = rep(0, length(x)))
526
527  slot(newper, "day") <- remainder %/% (3600 * 24)
528  remainder <- remainder %% (3600 * 24)
529
530  slot(newper, "hour") <- remainder %/% (3600)
531  remainder <- remainder %% (3600)
532
533  slot(newper, "minute") <- remainder %/% (60)
534
535  slot(newper, ".Data") <- remainder %% (60)
536
537  newper * sign(span)
538}
539
540#' @export
541summary.Period <- function(object, ...) {
542  nas <- is.na(object)
543  object <- object[!nas]
544  persecs <- period_to_seconds(object)
545  qq <- stats::quantile(persecs)
546  qq <- c(qq[1L:3L], mean(persecs), qq[4L:5L])
547  qq <- seconds_to_period(qq)
548  qq <- as.character(qq)
549  names(qq) <- c("Min.", "1st Qu.", "Median", "Mean", "3rd Qu.",
550                 "Max.")
551  if (any(nas))
552    c(qq, `NA's` = sum(nas))
553  else qq
554}
555
556#' @export
557setMethod("Arith", signature(e1 = "Period", e2 = "ANY"), function(e1, e2) {
558  stop_incompatible_classes(e1, e2, .Generic)
559})
560
561#' @export
562setMethod("Arith", signature(e1 = "ANY", e2 = "Period"), function(e1, e2) {
563  stop_incompatible_classes(e1, e2, .Generic)
564})
565
566## duration is.numeric. So we need these explicits here:
567#' @export
568setMethod("Arith", signature(e1 = "Duration", e2 = "Period"), function(e1, e2) {
569  stop_incompatible_classes(e1, e2, .Generic)
570})
571
572#' @export
573setMethod("Arith", signature(e1 = "Period", e2 = "Duration"), function(e1, e2) {
574  stop_incompatible_classes(e1, e2, .Generic)
575})
576
577#' @export
578setMethod("Compare", signature(e1 = "Period", e2 = "Period"),
579          function(e1, e2) {
580            callGeneric(period_to_seconds(e1), period_to_seconds(e2))
581          })
582
583#' @export
584setMethod("Compare", signature(e1 = "Period", e2 = "character"),
585          function(e1, e2) {
586            callGeneric(e1, as.period(e2))
587          })
588
589#' @export
590setMethod("Compare", signature(e1 = "character", e2 = "Period"),
591          function(e1, e2) {
592            callGeneric(as.period(e1), e2)
593          })
594
595#' @export
596setMethod("Compare", signature(e1 = "Period", e2 = "Duration"),
597          function(e1, e2) {
598            callGeneric(as.duration(e1), e2)
599          })
600
601#' @export
602setMethod("Compare", signature(e1 = "Duration", e2 = "Period"),
603          function(e1, e2) {
604            callGeneric(e1, as.duration(e2))
605          })
606
607#' @export
608setMethod("Compare", signature(e1 = "Period", e2 = "numeric"),
609          function(e1, e2) {
610            callGeneric(as.numeric(e1, "secs"), e2)
611          })
612
613#' @export
614setMethod("Compare", signature(e1 = "numeric", e2 = "Period"),
615          function(e1, e2) {
616            callGeneric(e1, as.numeric(e2, "secs"))
617          })
618
619#' @export
620setMethod("Compare", c(e1 = "Period", e2 = "difftime"),
621          function(e1, e2) {
622            callGeneric(as.numeric(e1, units = "secs"), as.numeric(e2, units = "secs"))
623          })
624
625#' @export
626setMethod("Compare", c(e1 = "difftime", e2 = "Period"),
627          function(e1, e2) {
628            callGeneric(as.numeric(e1, units = "secs"), as.numeric(e2, units = "secs"))
629          })
630