如何获得具有多个单位的输出的时差

时间:2019-03-24 20:46:29

标签: r time posixct difftime

美好的一天,

我在as.POSIXct中有两个日期列,格式为YYYY-MM-DD HH:MM:SS。我想得到两者之间的差异,格式为Days Hours:Seconds。这是一些虚拟数据:

    a<-c("2018-03-20 11:52:25 AST", "2018-03-20 12:51:25 AST", "2018-03-20 14:19:04 AST",
"2018-03-21 14:12:12 AST", "2018-03-21 12:09:22 AST", "2018-03-21 15:28:01 AST")

b<-c("2018-04-09 18:39:38 AST", "2018-06-23 19:13:14 AST", "2018-03-20 23:23:03 AST",
     "2018-05-10 21:29:28 AST", "2018-03-22 03:17:23 AST", "2018-05-12 00:19:39 AST")

ab<-data.frame(a,b)

给出以下数据框:

                        a                       b
 2018-03-20 11:52:25 AST 2018-04-09 18:39:38 AST
 2018-03-20 12:51:25 AST 2018-06-23 19:13:14 AST
 2018-03-20 14:19:04 AST 2018-03-20 23:23:03 AST
 2018-03-21 14:12:12 AST 2018-05-10 21:29:28 AST
 2018-03-21 12:09:22 AST 2018-03-22 03:17:23 AST
 2018-03-21 15:28:01 AST 2018-05-12 00:19:39 AST

我想得到a和b之间的差,或者从时间b中减去时间a,以获得X天X小时:X秒的输出。

我在下面使用了difftime以及设置不同的单位:

ab$time_difference<-difftime(ab$b, ab$a)
ab
                            a                       b   time_difference
     2018-03-20 11:52:25 AST 2018-04-09 18:39:38 AST  486.786944 hours
     2018-03-20 12:51:25 AST 2018-06-23 19:13:14 AST 2286.363611 hours
     2018-03-20 14:19:04 AST 2018-03-20 23:23:03 AST    9.066389 hours
     2018-03-21 14:12:12 AST 2018-05-10 21:29:28 AST 1207.287778 hours
     2018-03-21 12:09:22 AST 2018-03-22 03:17:23 AST   15.133611 hours
     2018-03-21 15:28:01 AST 2018-05-12 00:19:39 AST 1232.860556 hours

我也尝试了以下方法:

ab$time_difference<-difftime(ab$b, ab$a,units=c("days","hours","seconds"))

但是会得到“单位”的长度必须为1的错误。我是否应该使用其他命令,或者是否有任何方法可以使difftime产生更精确的时差?

谢谢!

4 个答案:

答案 0 :(得分:3)

hms库可以在此处提供一些帮助:

library(hms)
as.hms(ab$time_difference, format="%H:%M:S")
# 486:47:13
# 2286:21:49
# 09:03:59
# 1207:17:16
# 15:08:01
# 1232:51:38

有关其他选项,请参见此问题:Outputting difftime as HH:MM:SS:mm in R

以下是上述问题的答案代码:

Fmt <- function(x) UseMethod("Fmt")
Fmt.difftime <- function(x) {
   units(x) <- "secs"
   x <- unclass(x)
   NextMethod()
}
Fmt.default <- function(x) {
   y <- abs(x)
   sprintf("%s%02d:%02d:%02d:%02d", 
           ifelse(x < 0, "-", ""), # sign
           y %/% 86400,  # days
           y %% 86400 %/% 3600,  # hours 
           y %% 3600 %/% 60,  # minutes
           y %% 60 %/% 1) # seconds
}


a<-c("2018-03-20 11:52:25 AST", "2018-03-20 12:51:25 AST", "2018-03-20 14:19:04 AST",
     "2018-03-21 14:12:12 AST", "2018-03-21 12:09:22 AST", "2018-03-21 15:28:01 AST")

b<-c("2018-04-09 18:39:38 AST", "2018-06-23 19:13:14 AST", "2018-03-20 23:23:03 AST",
     "2018-05-10 21:29:28 AST", "2018-03-22 03:17:23 AST", "2018-05-12 00:19:39 AST")
ab<-data.frame(a,b)

#Passing two dates to  the function(s)
Fmt(as.POSIXct(ab$b)-as.POSIXct(ab$a))
#Passing a time difference in seconds
Fmt(difftime(ab$b, ab$a, units="secs"))

此处的键是在脚本开始处运行函数定义的代码,以便可以使用这些函数。

答案 1 :(得分:2)

由于您需要几天,几小时,几分钟,几秒钟,因此我们可以使用lubridate软件包获得此结果:

a<-c("2018-03-20 11:52:25 AST", "2018-03-20 12:51:25 AST", "2018-03-20 14:19:04 AST",
 "2018-03-21 14:12:12 AST", "2018-03-21 12:09:22 AST", "2018-03-21 15:28:01 AST")

b<-c("2018-04-09 18:39:38 AST", "2018-06-23 19:13:14 AST", "2018-03-20 23:23:03 AST",
 "2018-05-10 21:29:28 AST", "2018-03-22 03:17:23 AST", "2018-05-12 00:19:39 AST")

a = as.POSIXct(a)
b = as.POSIXct(b)

library(lubridate)
timespan = interval(ymd_hms(ab[,1]), ymd_hms(ab[,2]))
> as.period(timespan)
[1] "20d 6H 47M 13S"    "3m 3d 6H 21M 49S"  "9H 3M 59S"         "1m 19d 7H 17M 16S"
[5] "15H 8M 1S"         "1m 20d 8H 51M 38S"

如果需要,我们可以通过指定以下格式来将月份转换为天:

> as.period(timespan, unit = "day")
[1] "20d 6H 47M 13S" "95d 6H 21M 49S" "9H 3M 59S"      "50d 7H 17M 16S"
[5] "15H 8M 1S"      "51d 8H 51M 38S"

答案 2 :(得分:1)

require(lubridate)

a<-c("2018-03-20 11:52:25 AST", "2018-03-20 12:51:25 AST", "2018-03-20 14:19:04 AST",
     "2018-03-21 14:12:12 AST", "2018-03-21 12:09:22 AST", "2018-03-21 15:28:01 AST")

b<-c("2018-04-09 18:39:38 AST", "2018-06-23 19:13:14 AST", "2018-03-20 23:23:03 AST",
     "2018-05-10 21:29:28 AST", "2018-03-22 03:17:23 AST", "2018-05-12 00:19:39 AST")

# Make df
ab <- data.frame(a = as.POSIXct(a),b = as.POSIXct(b),stringsAsFactors = FALSE)

# Time diff
ab$time_difference <- ab$b - ab$a
ab$time_difference <- as.duration(ab$time_difference)
ab$time_difference 

1 2018-03-20 11:52:25 2018-04-09 18:39:38   1752433s (~2.9 weeks)
2 2018-03-20 12:51:25 2018-06-23 19:13:14 8230909s (~13.61 weeks)
3 2018-03-20 14:19:04 2018-03-20 23:23:03    32639s (~9.07 hours)
4 2018-03-21 14:12:12 2018-05-10 21:29:28  4346236s (~7.19 weeks)
5 2018-03-21 12:09:22 2018-03-22 03:17:23   54481s (~15.13 hours)
6 2018-03-21 15:28:01 2018-05-12 00:19:39  4438298s (~7.34 weeks)

答案 3 :(得分:1)

使用sprintf和模块化算法:

# first, be sure to specify units in difftime, or it will internally
#   choose units for each row
# using 'secs' here since it's the lowest common denominator
# wrapping as.double() to remove the class attribute which will
#   screw up dispatch to Ops below
ab$time_difference <- as.double(difftime(ab$b, ab$a, units = 'secs'))

#  3600 =   60*60 seconds in an hour;
# 86400 = 3600*24 seconds in a day
ab$hms = with(ab, sprintf('%d days; %d hours; %d seconds',
                          time_difference %/% 86400L,
                          (time_difference %% 86400L) %/% 3600L,
                          time_difference %% 3600L))
ab$hms
# [1] "20 days; 6 hours; 2833 seconds" "95 days; 6 hours; 1309 seconds"
# [3] "0 days; 9 hours; 239 seconds"   "50 days; 7 hours; 1036 seconds"
# [5] "0 days; 15 hours; 481 seconds"  "51 days; 8 hours; 3098 seconds"

我选择一种特别冗长的输出格式只是为了说明;当然,请牢记构建基块,当然,请记住,您应将%d替换为%02d(例如),以便将输出移至{{1 }}个数字。