2

I currently have a period object with this value :

"35d 17H 15M 28.9999999995343S"

I would like to get a different output which is :

35 days 17 hours 15 minutes 28 seconds

I would like to also be able to format it so the units take a "s" or not depending if the time units > 1 or not.

I already tried to get the attributes of the object with attr(period_object, "unit") but I can't modify the seconds since it seems they are not in the object.

str(as.period(period_object))
Formal class 'Period' [package "lubridate"] with 6 slots
  ..@ .Data : num 29
  ..@ year  : num 0
  ..@ month : num 0
  ..@ day   : num 35
  ..@ hour  : num 17
  ..@ minute: num 15

Here is a sample of data :

library(lubridate)
time1 <- as.POSIXct("2019-01-01 15:12:07")
time2 <- as.POSIXct("2019-02-06 08:27:36")
period_object <- difftime(time2, time1)

as.period(period_object)
[1] "35d 17H 15M 28.9999999995343S"

So the final output I want is : 35 days 17 hours 15 minutes 28 seconds

Anyone got some clues? Thank you.

NelsonGon
  • 13,015
  • 7
  • 27
  • 57
Gainz
  • 1,721
  • 9
  • 24

2 Answers2

3

One way to the seconds:

period_object %/% dseconds(1) %% 60
#[1] 28

To get them all this way:

days    <- period_object %/% ddays(1)
hours   <- period_object %/% dhours(1) %% 24
minutes <- period_object %/% dminutes(1) %% 60
seconds <- period_object %/% dseconds(1) %% 60
Jon Spring
  • 55,165
  • 4
  • 35
  • 53
  • Thanks a lot, it is way simpler/faster than when I was doing this with seconds(). Do you know why the seconds aren't part of the attributes but all the other units are? – Gainz May 15 '19 at 18:37
  • I get an `Error: Incompatible classes: %/% ` with this solution. I simply used `period_object %/% days(1)` and it worked. – Fons MA Apr 20 '22 at 07:04
  • You might be encountering this bug, since resolved: https://stackoverflow.com/questions/48087358/tibbles-reject-lubridates-duration-and-period-objects – Jon Spring Apr 20 '22 at 15:44
0

The seconds are contained within the .Data slot. Except for seconds, time units do not have a fixed length until they are added to a date-time (see https://lubridate.tidyverse.org/reference/period.html). Seconds may be expressed as a decimal, and can thus be rounded.

Part of the problem you are having is using difftime to calculate time differences instead of the lubridate::interval function.

library(lubridate)
#> 
#> Attaching package: 'lubridate'
#> The following objects are masked from 'package:base':
#> 
#>     date, intersect, setdiff, union

time1 <- as.POSIXct("2019-01-01 15:12:07")
time2 <- as.POSIXct("2019-02-06 08:27:36")
difftime_object <- difftime(time2, time1)
interval_object <- interval(time1, time2)

as.period(difftime_object)
#> [1] "35d 17H 15M 28.9999999995343S"
round(as.period(difftime_object))
#> [1] "35d 17H 15M 29S"

as.period(interval_object)
#> [1] "1m 4d 17H 15M 29S"
as.period(interval_object, unit = "days")
#> [1] "35d 17H 15M 29S"


format_period <- function(x) {
  paste(x@day, "days", x@hour, "hours", x@minute, "minuets", x@.Data, "seconds", sep = " ")
  # or paste(day(x), "days", hour(x), "hours", minute(x), "minuets", second(x), "seconds", sep = " ")
}

format_period(as.period(interval_object, unit = "days"))
#> [1] "35 days 17 hours 15 minuets 29 seconds"

Created on 2021-12-06 by the reprex package (v2.0.1)

JWilliman
  • 3,558
  • 32
  • 36