处理 R 中的数字(十进制)日期?
Dealing with numeric (decimal) dates in R?
我有一些来自 Excel 的数字日期数据:
> df <- data.frame(c(42613, 42612, 42614), c(42614.61, 42613.97, 42612.12))
> names(df) <- c("Closetime", "Opentime")
Closetime
和Opentime
都是numeric
。我想保留 OpenTime
中的 hour/minute/second 数据,并将时间 '00:00:00' 添加到 Closetime
:
中的每个日期
> df$Closetime <- paste(as.Date(df$Closetime, origin = '1900-01-01'), c('00:00:00'))
做起来很容易 Closetime
,但是当我尝试在 Opentime
上使用 lubridate::date_decimal
时,一切都变得糟糕了。
> df$Opentime <- date_decimal(df$Opentime)
> df
Closetime Opentime
1 2016-09-02 00:00:00 42614-08-11 15:36:00
2 2016-09-01 00:00:00 42613-12-21 01:12:00
3 2016-09-03 00:00:00 42612-02-13 22:04:48
如何让 Opentime
和 Closetime
成为相同的 type/format?我最终希望能够得到每列时间之间的小时数差异,以供参考。
如果你可以使用 POSIXct,你可以这样做
df$Opentime <- as.POSIXct( df$Opentime*24*60*60,
origin="1900-01-01",
tz="UTC")
推理:POSIXct 只是自原点以来的秒数
首先,我们遵循 help("as.Date")
中关于 Excel 日期的建议。我在这里假设 Windows Excel:
df$Closetime_p <- as.Date(df$Closetime, origin = "1899-12-30")
df$Opentime_p <- as.Date(floor(df$Opentime), origin = "1899-12-30")
然后我们转换为POSIXct:
df$Closetime_p <- as.POSIXct(as.POSIXlt(df$Closetime_p, tz = "GMT"), tz = "GMT")
df$Opentime_p <- as.POSIXct(as.POSIXlt(df$Opentime_p, tz = "GMT"), tz = "GMT")
现在我们加上时间:
df$Opentime_p <- df$Opentime_p + (df$Opentime - floor(df$Opentime)) * 24 * 3600
# Closetime Opentime Closetime_p Opentime_p
#1 42613 42614.61 2016-08-31 2016-09-01 14:38:24
#2 42612 42613.97 2016-08-30 2016-08-31 23:16:48
#3 42614 42612.12 2016-09-01 2016-08-30 02:52:48
像您一样转换为日期,然后转换为 POSIXct
:
首先,创建 data.frame(并注意我们如何设置列名):
R> df <- data.frame(CloseT=c(42613, 42612, 42614), OpenT=c(42614.61, 42613.97, 42612.12))
R> df
CloseT OpenT
1 42613 42614.6
2 42612 42614.0
3 42614 42612.1
R>
然后转换为日期:
R> df$CloseT <- as.Date(df$CloseT, origin="1900-01-01")
R> df$OpenT <- as.Date(df$OpenT, origin="1900-01-01")
R> df
CloseT OpenT
1 2016-09-02 2016-09-03
2 2016-09-01 2016-09-02
3 2016-09-03 2016-09-01
R>
最后,转换为POSIXct
:
R> df$OpenT <- as.POSIXct(df$OpenT)
R> df$CloseT <- as.POSIXct(df$CloseT)
R> df
CloseT OpenT
1 2016-09-01 19:00:00 2016-09-03 09:38:24
2 2016-08-31 19:00:00 2016-09-02 18:16:48
3 2016-09-02 19:00:00 2016-08-31 21:52:48
R>
通过 POSIXlt
可以设置时区,如 Roland 所示。
查看 date_decimal 上的文档:
a POSIXct object, whose year corresponds to the integer part of decimal.
date <- ymd("2009-02-10")
decimal <- decimal_date(date) # 2009.11
date_decimal(decimal) # "2009-02-10 UTC"
因此在您的示例中,它将 42614 解释为年份。
尝试使用 as.POSIXct
。您可能必须指定时区,但如果您只需要时差,则没有必要。下面我计算了时差:
df <- data.frame(c(42613, 42612, 42614), c(42614.61, 42613.97, 42612.12))
names(df) <- c("Closetime", "Opentime")
df$Closetime <- as.POSIXct(as.Date(df$Closetime, origin = '1900-01-01'))
df$Opentime <- as.POSIXct(as.Date(df$Opentime, origin = '1900-01-01'))
df$delta <- df$Opentime - df$Closetime
df
Closetime Opentime delta
1 2016-09-01 20:00:00 2016-09-03 10:38:24 1.61 days
2 2016-08-31 20:00:00 2016-09-02 19:16:48 1.97 days
3 2016-09-02 20:00:00 2016-08-31 22:52:48 -1.88 days
根据评论,如果您想确保显示的时间正确,则需要正确匹配时区。您可以在转换为 as.POSIXct
后通过设置 tzone
属性执行此操作。
df <- data.frame(c(42613, 42612, 42614), c(42614.61, 42613.97, 42612.12))
names(df) <- c("Closetime", "Opentime")
df$Closetime <- as.POSIXct(as.Date(df$Closetime, origin = '1900-01-01'))
df$Opentime <- as.POSIXct(as.Date(df$Opentime, origin = '1900-01-01'))
attr(df$Closetime, "tzone") <- "GMT"
attr(df$Opentime, "tzone") <- "GMT"
df$delta <- df$Opentime - df$Closetime
df
Closetime Opentime delta
1 2016-09-02 2016-09-03 14:38:24 1.61 days
2 2016-09-01 2016-09-02 23:16:48 1.97 days
3 2016-09-03 2016-09-01 02:52:48 -1.88 days
我有一些来自 Excel 的数字日期数据:
> df <- data.frame(c(42613, 42612, 42614), c(42614.61, 42613.97, 42612.12))
> names(df) <- c("Closetime", "Opentime")
Closetime
和Opentime
都是numeric
。我想保留 OpenTime
中的 hour/minute/second 数据,并将时间 '00:00:00' 添加到 Closetime
:
> df$Closetime <- paste(as.Date(df$Closetime, origin = '1900-01-01'), c('00:00:00'))
做起来很容易 Closetime
,但是当我尝试在 Opentime
上使用 lubridate::date_decimal
时,一切都变得糟糕了。
> df$Opentime <- date_decimal(df$Opentime)
> df
Closetime Opentime
1 2016-09-02 00:00:00 42614-08-11 15:36:00
2 2016-09-01 00:00:00 42613-12-21 01:12:00
3 2016-09-03 00:00:00 42612-02-13 22:04:48
如何让 Opentime
和 Closetime
成为相同的 type/format?我最终希望能够得到每列时间之间的小时数差异,以供参考。
如果你可以使用 POSIXct,你可以这样做
df$Opentime <- as.POSIXct( df$Opentime*24*60*60,
origin="1900-01-01",
tz="UTC")
推理:POSIXct 只是自原点以来的秒数
首先,我们遵循 help("as.Date")
中关于 Excel 日期的建议。我在这里假设 Windows Excel:
df$Closetime_p <- as.Date(df$Closetime, origin = "1899-12-30")
df$Opentime_p <- as.Date(floor(df$Opentime), origin = "1899-12-30")
然后我们转换为POSIXct:
df$Closetime_p <- as.POSIXct(as.POSIXlt(df$Closetime_p, tz = "GMT"), tz = "GMT")
df$Opentime_p <- as.POSIXct(as.POSIXlt(df$Opentime_p, tz = "GMT"), tz = "GMT")
现在我们加上时间:
df$Opentime_p <- df$Opentime_p + (df$Opentime - floor(df$Opentime)) * 24 * 3600
# Closetime Opentime Closetime_p Opentime_p
#1 42613 42614.61 2016-08-31 2016-09-01 14:38:24
#2 42612 42613.97 2016-08-30 2016-08-31 23:16:48
#3 42614 42612.12 2016-09-01 2016-08-30 02:52:48
像您一样转换为日期,然后转换为 POSIXct
:
首先,创建 data.frame(并注意我们如何设置列名):
R> df <- data.frame(CloseT=c(42613, 42612, 42614), OpenT=c(42614.61, 42613.97, 42612.12))
R> df
CloseT OpenT
1 42613 42614.6
2 42612 42614.0
3 42614 42612.1
R>
然后转换为日期:
R> df$CloseT <- as.Date(df$CloseT, origin="1900-01-01")
R> df$OpenT <- as.Date(df$OpenT, origin="1900-01-01")
R> df
CloseT OpenT
1 2016-09-02 2016-09-03
2 2016-09-01 2016-09-02
3 2016-09-03 2016-09-01
R>
最后,转换为POSIXct
:
R> df$OpenT <- as.POSIXct(df$OpenT)
R> df$CloseT <- as.POSIXct(df$CloseT)
R> df
CloseT OpenT
1 2016-09-01 19:00:00 2016-09-03 09:38:24
2 2016-08-31 19:00:00 2016-09-02 18:16:48
3 2016-09-02 19:00:00 2016-08-31 21:52:48
R>
通过 POSIXlt
可以设置时区,如 Roland 所示。
查看 date_decimal 上的文档:
a POSIXct object, whose year corresponds to the integer part of decimal.
date <- ymd("2009-02-10")
decimal <- decimal_date(date) # 2009.11
date_decimal(decimal) # "2009-02-10 UTC"
因此在您的示例中,它将 42614 解释为年份。
尝试使用 as.POSIXct
。您可能必须指定时区,但如果您只需要时差,则没有必要。下面我计算了时差:
df <- data.frame(c(42613, 42612, 42614), c(42614.61, 42613.97, 42612.12))
names(df) <- c("Closetime", "Opentime")
df$Closetime <- as.POSIXct(as.Date(df$Closetime, origin = '1900-01-01'))
df$Opentime <- as.POSIXct(as.Date(df$Opentime, origin = '1900-01-01'))
df$delta <- df$Opentime - df$Closetime
df
Closetime Opentime delta
1 2016-09-01 20:00:00 2016-09-03 10:38:24 1.61 days
2 2016-08-31 20:00:00 2016-09-02 19:16:48 1.97 days
3 2016-09-02 20:00:00 2016-08-31 22:52:48 -1.88 days
根据评论,如果您想确保显示的时间正确,则需要正确匹配时区。您可以在转换为 as.POSIXct
后通过设置 tzone
属性执行此操作。
df <- data.frame(c(42613, 42612, 42614), c(42614.61, 42613.97, 42612.12))
names(df) <- c("Closetime", "Opentime")
df$Closetime <- as.POSIXct(as.Date(df$Closetime, origin = '1900-01-01'))
df$Opentime <- as.POSIXct(as.Date(df$Opentime, origin = '1900-01-01'))
attr(df$Closetime, "tzone") <- "GMT"
attr(df$Opentime, "tzone") <- "GMT"
df$delta <- df$Opentime - df$Closetime
df
Closetime Opentime delta
1 2016-09-02 2016-09-03 14:38:24 1.61 days
2 2016-09-01 2016-09-02 23:16:48 1.97 days
3 2016-09-03 2016-09-01 02:52:48 -1.88 days