将日期时间转换为格式化的时间字符串。

23
我不知道为什么它不工作。这是我的代码:
> t <- hms("14:11:49")
> t
[1] "14H 11M 49S"
t <- t + minutes(3)
> format(t, format="%H:%M:%S")
[1] "14H 14M 49S"
# Expected output: "14:14:49"

更新:

目前我找到了这个解决方案,但我希望有一个更优雅的方案:

t <- hms("14:11:49") # example period object
sprintf("%s:%s:%s", hour(t), minute(t), second(t))
#"14:11:49"
3个回答

25

不确定为什么需要将时间转换为hms格式,然后再转回初始字符串格式。也许你需要使用parse_date_time函数:

library(lubridate)

myTime <- "14:11:49"
hms(myTime)
#"14H 11M 49S"

POSIXct_myTime <- parse_date_time(myTime,"hms")
format(POSIXct_myTime, format="%H:%M:%S")
#"14:11:49"

编辑: 我们可以使用paste命令:

tt <- hms("14:11:49")
tt
#[1] "14H 11M 49S"
tt <- tt + minutes(3)
tt
#[1] "14H 14M 49S"

paste(hour(tt), minute(tt), second(tt), sep = ":")
#[1] "14:14:49"

基准测试输出:

big <- rep(tt, 10000)
bench::mark(
  paste = paste(hour(big), minute(big), second(big), sep = ":"),
  sprintf = sprintf("%s:%s:%s", hour(big), minute(big), second(big)),
  shosaco = format(Sys.Date() + big, "%H:%M:%S"))
# # A tibble: 3 x 13
#   expression    min median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time
#   <bch:expr> <bch:> <bch:>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm>
# 1 paste      27.7ms 29.8ms      30.9  312.69KB        0    16     0      517ms
# 2 sprintf    29.5ms 42.7ms      23.3  312.69KB        0    12     0      515ms
# 3 shosaco    28.3ms 29.2ms      33.1    2.06MB        0    17     0      514ms
# # ... with 4 more variables: result <list>, memory <list>, time <list>,
# #   gc <list>

1
这似乎是一个更好的想法。 - MrFlick
当我写入文本文件时,我会(偏执地)考虑字符串格式可以为每个条目节省一些字节。然而,你的解决方案并没有达到我想要实现的目标。这一行是一个“鸡生蛋”的问题:POSIXct_myTime <- parse_date_time(myTime,"hms")。我没有以字符串格式拥有myTime。我读取了数百万个以%H:%M:%S格式的条目,对它们进行过滤,并希望以与输入完全相同的格式写回。 - biocyberman
1
抱歉造成混淆。我只是为了将时间字符串转换成对象而添加了“hms(“14:11:49”)”这一行。我的工作流程如下:读取数百万条时间字符串;使用lubridate进行一些计算;将结果写回文本文件。请查看我更新后的问题的开头部分。 - biocyberman
1
我在这种情况下忘记了paste函数。但我希望有一种方法可以避免调用hourminutesecond。我的想法是:lubridate包显然非常擅长读取许多输入日期时间格式,但不太擅长将这些输出返回出来。 - biocyberman
1
不幸的是,“paste”解决方案将“04”打印为“4”。我使用“format”函数添加了一个简单的解决方法。 - shosaco
显示剩余2条评论

2

提出的解决方案没有打印前导零。以下解决方案似乎更优雅:

最初的回答并没有考虑到前导零,下面的解决方案看起来更加简洁:

> t <- hms("14:01:49") + minutes(3)
> sprintf("%s:%s:%s", hour(t), minute(t), second(t))
[1] "14:4:49" # looking weird
> format(Sys.Date() + t, "%H:%M:%S")
[1] "14:04:49" # looking better

2
问题在于class(t)是“Period”,而format.Period()函数没有format=参数。 t对象不是您可能习惯使用的标准POSIXt样式对象,可用于使用format()。只有format.POSIXct()format.POSIXlt()函数才会像那样运行。

因此,最简单的方法可能是定义一个辅助函数,将Period类转换为POSIXct。 我们可以使用以下方式完成:

as.POSIXct.Period <- function(x, start=today()) {
    X<-as.interval(x, start); 
    X@.Data+X@start
}

需要注意的是POSIXct是一个日期/时间值,而不仅仅是一个时间值。因此,默认情况下,我们假定它从今天午夜开始。但是,我们可以按照您所需的方式使用格式。

format(as.POSIXct(t), format="%H:%M:%S")
# [1] "14:11:49"

我必须承认,我不是一个熟练的 lubridate 用户,也许我忽略了一个显而易见的函数,但似乎将 lubridate 类格式化为“漂亮”的格式的选项非常有限。


这个解决方案可行,但需要额外的步骤将时间转换为日期时间对象。无论如何,感谢提到format.POSIXct()format.POSIXlt()函数。 - biocyberman
1
好的,你最初的问题只是因为你不知道为什么它不起作用,而不是要求任何“解决方案”。如果那不是你真正的问题,那么我会尝试在将来更好地表达你的问题。我只进行了转换,因为你似乎真的想使用带有“%H:%M:%S”语法的format函数。 - MrFlick

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接