将文本解析为日期/时间
我们可以根据初始值创建一个自定义日期:
as.Date(1000, "1970-01-01")
## [1] "1972-09-27"
在更多的情况下,我们通过标准的文本格式来创建时间和日期:
my_date <- as.Date("2016-02-10")
my_date
## [1] "2016-02-10"
但是如果我们可以通过如 2016-02-10 这样的字符串来表示时间,为什么还要创建一个
日期对象呢?这是因为一个日期对象具有更多的功能,可以进行日期的数学计算。假设有
一个日期对象,我们可以加上或减去一些日期,并得到一个新日期:
my_date +3
## [1] "2016-02-13"
my_date +80
## [1] "2016-04-30"
my_date -65
## [1] "2015-12-07"
也可以直接将两个日期相减以得到两个日期之间间隔的天数:
date1 <- as.Date("2014-09-28")
date2 <- as.Date("2015-10-20")
date2 - date1
## Time difference of 387 days
date2-date1的结果看起来好像一条信息,其实是一个数值。我们可以通过as.numeric( )
使其更明显:
as.numeric(date2 - date1)
## [1] 387
时间也是类似的,但是并没有as.Time( )这样的函数。我们需要使用as.POSIXct( )
或 as.POSIXlt( )通过文本来创建日期时间。这两个函数是 POSIX 标准下对日期/时间对象
的不同实现。在接下来的例子中,我们使用 as.POSIXlt( )来创建一个日期/时间对象:
my_time <- as.POSIXlt("2016-02-10 10:25:31")
my_time
## [1] "2016-02-10 10:25:31 CST"
这种对象类型也定义了用于简单时间计算的 + 和−。不同于日期对象,该对象使用秒
而不是天作为计量单位:
my_time + 10
## [1] "2016-02-10 10:25:41 CST"
my_time + 12345
## [1] "2016-02-10 13:51:16 CST"
my_time - 1234567
## [1] "2016-01-27 03:29:24 CST"
给定一个数据中的日期或者时间,我们必须将其转换为日期/时间对象,以便进行计算。
然而原始数据中的日期或时间的格式通常不能直接被as.Date( )或as.POSIXlt( )识
别。在这种情况下,我们需要使用一系列特殊字母作为占位符来表示日期或时间的特定部
分,如同使用 sprintf( )的那样。
举个例子,对于 2015.07.25 这样的输入,如果没有提供格式字符串,as.Date( )就
会报错:
as.Date("2015.07.25")
## Error in charToDate(x): character string is not in a standard unambiguous
format
我们可以使用一个格式字符串作为模板,告知 as.Date( )如何将该字符串解析为日期:
as.Date("2015.07.25", format = "%Y.%m.%d")
## [1] "2015-07-25"
类似地,对于一个不标准的日期/时间字符串,也需要指定一个模板字符串以告知
as.POSIXlt( )如何处理:
as.POSIXlt("7/25/2015 09:30:25", format = "%m/%d/%Y %H:%M:%S")
## [1] "2015-07-25 09:30:25 CST"
另一种可以将字符串转换为时间的函数是 strptime( ),且更加直接:
strptime("7/25/2015 09:30:25", "%m/%d/%Y %H:%M:%S")
## [1] "2015-07-25 09:30:25 CST"
事实上,as.POSIXlt( )只是 strptime( )针对字符输入的一个封装。但是
strptime( )总是要求你提供格式字符串,而 as.POSIXlt( )无需提供模板,只对标
准格式起作用。
如同数值向量一样,日期和日期/时间也是向量。你可以为 as.Date( )提供一个字符
向量,从而获得一个日期向量:
as.Date(c("2015-05-01", "2016-02-12"))
## [1] "2015-05-01" "2016-02-12"
其数学运算也是向量化的。在下面的代码中,我们对日期值加上一些连续的整数,并
如愿得到连续的日期:
as.Date("2015-01-01") +0:2
## [1] "2015-01-01" "2015-01-02" "2015-01-03"
相同的功能在日期/时间对象上也适用:
strptime("7/25/2015 09:30:25", "%m/%d/%Y %H:%M:%S") + 1:3
## [1] "2015-07-25 09:30:26 CST" "2015-07-25 09:30:27 CST"
## [3] "2015-07-25 09:30:28 CST"
有时候,日期和时间是用整数表示的。这使得我们可以更加巧妙地解析日期和时
间。
例如,为了解析 20150610,需要运行以下代码:
as.Date("20150610", format = "%Y%m%d")
## [1] "2015-06-10"
为了解析 20150610093215,我们可以设定格式模板:
strptime("20150610093215", "%Y%m%d%H%M%S")
## [1] "2015-06-10 09:32:15 CST"
将日期/时间解析为数据框是一个更加巧妙的例子:
datetimes <- data.frame(
date = c(20150601, 20150603),
time = c(92325, 150621))
如果我们对datetimes使用paste0( )并直接套用之前例子中strptime( )的模
版,将会得到一个缺失值(NA)。这说明第 1 个元素不符合这种格式:
dt_text <- paste0(datetimes$date, datetimes$time)
dt_text
## [1] "2015060192325" "20150603150621"
strptime(dt_text, "%Y%m%d%H%M%S")
## [1] NA "2015-06-03 15:06:21 CST"
问题源于 92325,本应该是 092325。需要使用 sprintf( )来确保必要的时候开头
的 0 能被表示出来:
dt_text2 <- paste0(datetimes$date, sprintf("%06d", datetimes$time))
dt_text2
## [1] "20150601092325" "20150603150621"
strptime(dt_text2, "%Y%m%d%H%M%S")
## [1] "2015-06-01 09:23:25 CST" "2015-06-03 15:06:21 CST"
最终,转换工作得以完成。