我有一个POSIXct值的向量,我想将它们舍入到最近的四分之一小时。我不关心这一天。如何将值转换为小时和分钟?
例如,我想要值
"2012-05-30 20:41:21 UTC"
是
"20:45"
答案 0 :(得分:21)
您可以使用round
。诀窍是在四舍五入之前除以900秒(15分钟* 60秒)并在之后乘以900:
a <-as.POSIXlt("2012-05-30 20:41:21 UTC")
b <-as.POSIXlt(round(as.double(a)/(15*60))*(15*60),origin=(as.POSIXlt('1970-01-01')))
b
[1] "2012-05-30 20:45:00 EDT"
要获得时间和分钟,只需使用格式
format(b,"%H:%M")
[1] "20:45"
as.character(format(b,"%H:%M"))
[1] "20:45"
答案 1 :(得分:18)
确实,这是一个老问题,到目前为止有一些有用的答案。 giraffhere的最后一个似乎是最优雅的。但是,不是floor_date而是round_date可以解决这个问题:
lubridate::round_date(x, "15 minutes")
答案 2 :(得分:14)
类似
format(strptime("1970-01-01", "%Y-%m-%d", tz="UTC") + round(as.numeric(your.time)/900)*900,"%H:%M")
会起作用
答案 3 :(得分:12)
旧问题,但我想注意lubridate
包现在可以使用floor_date
轻松处理。要将POSIXct对象的矢量剪切为15分钟间隔,请使用这样的方法。
x <- lubridate::floor_date(x, "15 minutes")
编辑:用户@ user3297928注意到,使用lubridate::round_date(x, "15 minutes")
进行四舍五入到最接近的15分钟。以上楼层。
答案 4 :(得分:4)
您可以使用xts包中的align.time
函数来处理舍入,然后format
返回一个字符串“HH:MM”:
R> library(xts)
R> p <- as.POSIXct("2012-05-30 20:41:21", tz="UTC")
R> a <- align.time(p, n=60*15) # n is in seconds
R> format(a, "%H:%M")
[1] "20:45"
答案 5 :(得分:3)
尝试此操作,它结合了两个请求,并基于查看round.POSIXt()
和trunc.POSIXt()
所做的事情。
myRound <- function (x, convert = TRUE) {
x <- as.POSIXlt(x)
mins <- x$min
mult <- mins %/% 15
remain <- mins %% 15
if(remain > 7L || (remain == 7L && x$sec > 29))
mult <- mult + 1
if(mult > 3) {
x$min <- 0
x <- x + 3600
} else {
x$min <- 15 * mult
}
x <- trunc.POSIXt(x, units = "mins")
if(convert) {
x <- format(x, format = "%H:%M")
}
x
}
这给出了:
> tmp <- as.POSIXct("2012-05-30 20:41:21 UTC")
> myRound(tmp)
[1] "20:45"
> myRound(tmp, convert = FALSE)
[1] "2012-05-30 20:45:00 BST"
> tmp2 <- as.POSIXct("2012-05-30 20:55:21 UTC")
> myRound(tmp2)
[1] "21:00"
> myRound(tmp2, convert = FALSE)
[1] "2012-05-30 21:00:00 BST"
答案 6 :(得分:3)
使用IDate
和ITime
类(刚刚开发)的data.table
和IPeriod
类,我能够获得更具伸缩性的解决方案。
只有 shhhhimhuntingrabbits 和 PLapointe 以最近的方式回答问题。 xts
解决方案仅使用 ceiling 进行轮次,我的IPeriod
解决方案允许指定 ceiling 或 floor 。
要获得最佳效果,您需要将数据保存在IDate
和ITime
类中。从基准测试来看,从POSIXct
生成IDate/ITime/IPeriod
是很便宜的。低于约22M时间戳的基准:
# install only if you don't have
install.packages(c("microbenchmarkCore","data.table"),
repos = c("https://olafmersmann.github.io/drat",
"https://jangorecki.github.io/drat/iperiod"))
library(microbenchmarkCore)
library(data.table) # iunit branch
library(xts)
Sys.setenv(TZ="UTC")
## some source data: download and unzip csv
# "http://api.bitcoincharts.com/v1/csv/btceUSD.csv.gz"
# below benchmark on btceUSD.csv.gz 11-Oct-2015 11:35 133664801
system.nanotime(dt <- fread(".btceUSD.csv"))
# Read 21931266 rows and 3 (of 3) columns from 0.878 GB file in 00:00:10
# user system elapsed
# NA NA 9.048991
# take the timestamp only
x = as.POSIXct(dt[[1L]], tz="UTC", origin="1970-01-01")
# functions
shhhhi <- function(your.time){
strptime("1970-01-01", "%Y-%m-%d", tz="UTC") + round(as.numeric(your.time)/900)*900
}
PLapointe <- function(a){
as.POSIXlt(round(as.double(a)/(15*60))*(15*60),origin=(as.POSIXlt('1970-01-01')))
}
# myRound - not vectorized
# compare results
all.equal(
format(shhhhi(x),"%H:%M"),
format(PLapointe(x),"%H:%M")
)
# [1] TRUE
all.equal(
format(align.time(x, n = 60*15),"%H:%M"),
format(periodize(x, "mins", 15),"%H:%M")
)
# [1] TRUE
# IPeriod native input are IDate and ITime - will be tested too
idt <- IDateTime(x)
idate <- idt$idate
itime <- idt$itime
microbenchmark(times = 10L,
shhhhi(x),
PLapointe(x),
xts = align.time(x, 15*60),
posix_ip_posix = as.POSIXct(periodize(x, "mins", 15), tz="UTC"),
posix_ip = periodize(x, "mins", 15),
ip_posix = as.POSIXct(periodize(idate, itime, "mins", 15), tz="UTC"),
ip = periodize(idate, itime, "mins", 15))
# Unit: microseconds
# expr min lq mean median uq max neval
# shhhhi(x) 960819.810 984970.363 1127272.6812 1167512.2765 1201770.895 1243706.235 10
# PLapointe(x) 2322929.313 2440263.122 2617210.4264 2597772.9825 2792936.774 2981499.356 10
# xts 453409.222 525738.163 581139.6768 546300.9395 677077.650 767609.155 10
# posix_ip_posix 3314609.993 3499220.920 3641219.0876 3586822.9150 3654548.885 4457614.174 10
# posix_ip 3010316.462 3066736.299 3157777.2361 3133693.0655 3234307.549 3401388.800 10
# ip_posix 335.741 380.696 513.7420 543.3425 630.020 663.385 10
# ip 98.031 151.471 207.7404 231.8200 262.037 278.789 10
IDate
和ITime
不仅在此特定任务中成功扩展。两种类型(与IPeriod
相同)都是基于整数的。我认为他们也可以通过 datetime 字段加入或分组
在线手册:https://jangorecki.github.io/drat/iperiod/