在本教程中,您将学习如何在 R 中处理**日期和时间**。在日常生活中,日期和时间似乎很简单,但在编程语言的概念中则有点复杂。但 R 通过不同的选项使其变得更简单,可以使用 **as.Date、as.POSIXct、as.POSIXlt、转换规范**等来单独处理日期,或同时处理日期和时间。它还介绍了使用 `make_date()`、`make_datetime()` 等创建日期和时间。

我们还将介绍 **lubridate** 包的用法。 **lubridate** 包是 R 中处理日期和时间数据的包之一。
Lubridate 包使 R 编程语言中处理最令人沮丧的日期和时间数据变得更加容易。此函数对夏令时、闰日、时区等具有鲁棒性。
我们已经讨论了 R 包的安装,如需了解更多,请查看我们的教程 R 包安装。在 RStudio 的包下检查 lubridate 包,如果已安装,请使用 `library(lubridate)` 函数将其加载到您的程序中。如果 lubridate 包未安装,请按照我们 R 包安装教程中提到的任何一种方式安装它,以下载并使用该包。
# The easiest way to get lubridate is to install the whole tidyverse:
install.packages("tidyverse")
# Alternatively, install just lubridate:
install.packages("lubridate")
# Or the the development version from GitHub:
# install.packages("devtools")
devtools::install_github("tidyverse/lubridate")

我们使用 lubridate 包函数来处理日期和时间,在开始学习之前,请将 RStudio 准备好以处理日期和时间,加载 lubridate 包。
我们将一步一步学习。让我们开始加载 lubridate 包。
#Load lubridate package
library(lubridate)
要获取当前日期,可以使用来自不同可用 R 包的两个函数。基础 R 支持使用 `Sys.Date()` 函数检索日期。lubridate R 包使用 `today()` 函数来获得与 `Sys.Date()` 函数相同的输出。两者都提供当前日期“2022-03-27”,其格式为年/月/日。
检索当前日期和时间的方法和输出是
# to get current date
Sys.Date() #{base}
today() #{lubridate}
执行后的输出
> Sys.Date() [1] "2022-03-27" > today() [1] "2022-03-27"
lubridate 和基础 R 包支持用户通过以下两个函数获取当前时间:
# to get current time
Sys.time()
now()
运行代码后的输出是
> Sys.time() [1] "2022-03-27 07:38:04 IST" > now() [1] "2022-03-27 07:38:04 IST"
输出中还提到了时区 IST(印度标准时间)。R 遵循 ISO 标准来指定和表示数据和时间。从输出中可以清楚地看出,因为日期部分后面跟着时间部分。


`am()` 和 `pm()` 是 lubridate 包函数,用于检查日期时间是上午还是下午?它根据 x 是上午还是下午返回逻辑值 TRUE 或 FALSE。
am(x)
pm(x)
其中 x 是指定 R 日期时间对象的参数。
让我们看一个例子,
#to get time in a.m or p.m
am(Sys.time())
pm(Sys.time())
函数 `Sys.time()` 提供当前时间,并形成传递给 am() 或 pm() 函数的参数(在语法中表示为 x)。该函数获取当前时间并检查时间是在中午之前还是下午。代码执行后的输出是
> am(Sys.time()) [1] TRUE > pm(Sys.time()) [1] FALSE
我们的示例的 `Sys.time()` 是“2022-03-27 08:24:51 IST”,所以 `am(x)` 函数返回逻辑 **True**。当使用 `pm(x)` 检查相同时间时,它返回逻辑 **FALSE**,因为时间与下午时段不匹配,即不是 pm。
我们还可以使用 lubricate 包的 `ymd()` 来检查 am(x) 或 pm(x)。这些函数解析日期并识别分隔符,将存储在字符中的日期转换为日期对象。让我们看一个例子
x <- ymd("2022-03-27")
am(x)
pm(x)
由于时间相同,代码返回与上面相同的输出。
> x <- ymd("2022-03-27")
> am(x)
[1] TRUE
> pm(x)
[1] FALSE
注意:`ymd()` 系列函数基于 `parse_date_time()`
RStudio 中我们讨论过的代码的截图

lubridate 包提供了一个 `leap_year(x)` 函数来检查**年份是否为闰年**?它接受两种类型的参数,参数 x 可以是**年份**或 `Sys.Date()` 函数,以确定给定的年份或当前年份是否为闰年。
leap_year(x)
其中参数 x 是一个日期时间对象或年份。
| 函数 `leap_year(x)` | 描述 |
|---|---|
| `leap_year(year)` | 如果参数 x 是一个年份(数字),`leap_year` 函数根据格里高利历返回一个逻辑 TRUE(如果是闰年)或 FALSE。例如:`leap_year(2022)` |
| `leap_year(Date)` | 如果 x 被识别为日期,`leap year()` 函数会检查并返回逻辑值作为输出。例如:`leap_year(Sys.Date())` |
注意: `Sys.Date()` 返回当前日期
让我们做一个实际的例子
#To check a leap year or not?
leap_year(2022) #{lubridate package}
leap_year(Sys.Date())
运行代码后的输出是
> leap_year(2022) #{lubridate package}
[1] FALSE
> leap_year(Sys.Date())
[1] FALSE
考虑另一个具有稍微不同日期表示方式的例子。这里一个变量 x 被赋值为日期转换函数 as.Date()。
x <- as.Date("2009-08-02")
leap_year(x) # FALSE
leap_year(2009) # FALSE
leap_year(2008) # TRUE
leap_year(1900) # FALSE
leap_year(2000) # TRUE
注意: **as.Date()** 是 R 基础包中的一个函数,用于将字符表示形式转换为“Date”类对象
截图显示了我们在讨论中是如何学习 `leap_year()` 代码的。

日期在内部存储为自 1970-01-01 起的天数,属于日期类。日期和时间使用 POSIXct 或 POSIXlt 类表示。时间在内部存储为自 1970-01-01 起的秒数。

内置的 R 函数具有不同的类。lubridate 包的 `Sys.Date()`、R 基础包的 `now()` 用于表示日期,它们属于不同的类。例如
class(Sys.Date())
[1] "Date"
> class(now())
[1] "POSIXct" "POSIXt"
注意: `class()` 用于确定 R 对象的内部类型。有多种类型的类,如字符、整数、逻辑、因子、数据框等。日期也是其中一种类。
在此部分,您将了解三个不同的类
在 R 中,所有日期在内部都存储为天数。当我们存储某个日期时,R 会在内部将该日期存储为某种数字表示。 **为什么 R 将日期存储为数字?**
在 R 中,日期表示为自 1970-01-01 起的天数,用于 R 中的日期和时间。您可以在 RStudio 中使用 **lubridate::origin** 查看它。R 将当前日期存储为自 1970-01-01 起的天数。
让我们做一个实际的例子,找出当前日期“2022-03-27”以天数表示,即自 1970-01-01 起的 19078 天。
#date
lubridate::origin
Sys.Date()
unclass(Sys.Date())
运行这些代码后的输出是
lubridate::origin [1] "1970-01-01 UTC" > Sys.Date() [1] "2022-03-27" > unclass(Sys.Date()) [1] 19078
R 基础包中的 `as.Date()` 函数用于将存储为字符类的日期转换为日期类对象。不存储有关日期信息。
Todays_date = as.Date("2022-03-27")
> print(Todays_date)
[1] "2022-03-27"
当您尝试使用 `class()` 确定 `Todays_date` 属于哪个类时,它会返回 **Date**。
class(Todays_date) [1] "Date"
考虑下面的代码和结果输出。您可以看到日期表示存储在变量 `date` 中,作为字符字符串(“2022-03-27”)。它是一个日期,但系统仅将其识别为字符串。`class()` 返回字符作为输出。因此,要将给定的数据存储为日期格式,我们应该使用 `as.Date()`,然后才能将字符串转换为日期类以内部存储为日期。
date = "2022-03-27" > print(date) [1] "2022-03-27" > class(date) [1] "character"
注意: `as.Date()` 将一个数字转换为日期,该日期根据 R 中的日期和时间原点。
示例
数字 19078 与日期和时间原点一起返回该特定日期。
as.Date( 19078,origin= "1970-01-01 ") [1] "2022-03-27"
注意: Date 类仅用于包含日期组件的数据,不用于日期和时间组件或时区。
R 提供了两个相似的 POSIX 类 **POSIXct 和 POSIXlt 来操作日期和时间**。
POSIXct – `as.POSIXct`
POSIX 是 **portable operating system interface** 的缩写,ct 是 **calendar time** 的缩写。**它是一个标准系列**,用于指定与不同操作系统保持兼容性。我们从之前的讨论中知道 `now()` 属于 **POSIXct** 类。此类包含日期和时间组件。`as.POSIXct()` 存储日期和时间组件。语法如下,其中日期和时间参数包含在括号内。
#POSIXct
as.POSIXct("2022-03-27 08:24:51 ")
产生的输出是
[1] "2022-03-27 08:24:51 IST"
POSIXlt – `as.POSXlt`
POSIXlt 类以列表格式存储日期和时间信息(例如,秒、分、小时、月份中的第几天、月份、年份、年份中的第几天数等)。**POSIXlt** 看起来与 **POSIXct 格式**相似。
as.POSIXlt("2022-03-27 08:24:51 ")
[1] "2022-03-27 08:24:51 IST"
> #convert character data into POSIXlt date and time
> A=as.POSIXlt("2022-03-27 08:24:51 ")
> unclass(A)
$sec
[1] 51
$min
[1] 24
$hour
[1] 8
$mday
[1] 27
$mon
[1] 2
$year
[1] 122
$wday
[1] 0
$yday
[1] 85
$isdst
[1] 0
$zone
[1] "IST"
$gmtoff
[1] NA
注意: `as.POSIXct` 方法将日期时间字符串转换为 POSIXct 类。
注意: 在 R 中,`unclass` 函数允许查看有关特定对象存储的详细信息。
| POSIXct | POSIXlt |
|---|---|
| POSIXct 将日期和时间组件在内部存储为自 1970 年 1 月 1 日以来的秒数。 | POSIXlt 将日期和时间组件以列表格式存储,用于秒、分、小时、月份中的第几天、月份、年份、年份中的第几天数等。 |
注意: `as.POSIX*` 函数将对象转换为用于表示日期/时间的两个类之一。
您可以使用 R 中提供的特殊内置函数提取 YEAR、MONTH、DAY、HOUR、MINUTES、SECONDS、WEEK 等日期和时间组件。请看下表,了解如何提取年份、月份和星期函数及其相应的描述。
| 函数 | 描述 |
|---|---|
| `year()` | 获取年份 |
| `month()` | 以数字形式获取月份 |
| `month(label=TRUE)` | 以缩写形式获取月份 |
| `month(abbr=FALSE)` | 以全名获取月份 |
| `months()` | 获取月份 |
| `week()` | 获取星期 |
让我们做一些实际的例子来展示它的工作原理。首先创建一个日期和时间对象。让它存储在一个名为 **DT** 的变量中,该变量使用 lubridate 包的另一个函数 `ymd_hms()` 构建。
>DT = ymd_hms("2022-03-27 08:24:51")
> DT
[1] "2022-03-27 08:24:51 UTC"
>
让我们看表,找到从同一个 DATE 对象(创建为 DT)中提取不同部分的语法。
| 函数 | 输出 |
|---|---|
| `year(DT)` | [1] 2022 |
| `month(DT)` | [1] 3 |
| `month(DT, label = TRUE)` | [1] Mar 12 Levels: Jan < Feb < Mar < Apr < ... < Dec |
| `month(DT,label = TRUE,abbr=FALSE)` | [1] March 12 Levels: January < February < ... < December |
| `months(DT)` | [1] "March" |
| `week(DT)` | [1] 13 |
现在让我们看看如何从日期和时间中提取与日期相关的组件。请看下表,了解一些函数及其描述,后面是示例。DT 是我们在前面的示例中创建的日期对象 "2022-03-27 08:24:51 UTC"
| 函数 | 描述 | 语法 | 输出 |
|---|---|---|---|
| `day()` | 获取日期 | `day(DT)` |
[1] 27 |
| `mday()` | 月份中的第几天 | `mday(DT)` |
[1] 27 |
| `wday()` | 星期几 |
|
[1] 1 [1] Sun 7 Levels: Sun < Mon < Tue < Wed < ... < Sat [1] Sunday 7 Levels: Sunday < Monday < ... < Saturday |
| `qday()` | 季度中的第几天 | `qday(DT)` |
[1] 86 |
| `yday()` | 一年中的第几天 | `yday(DT)` |
[1] 86 |
| `weekdays()` | 星期几 |
|
[1] "Sunday" [1] "Sunday" [1] "Sun" |
| `days_in_month()` | 月份中的天数 | `days_in_month(DT)` |
Mar 31 |
以类似的方式,使用内置函数 `hours`、`minutes` 和 `seconds` 可以从 Date 对象中提取。同样,下表有助于更清晰地理解查找或提取小时、分钟和秒的不同函数。
| 函数 | 语法 | 输出 |
|---|---|---|
| `hour()` | `hour(DT)` | [1] 8 |
| `minute()` | `minute(DT)` | [1] 24 |
| `second()` | `second(DT)` | [1] 51 |
| `seconds()` | `seconds(DT)` | [1] "1648369491S" |

要创建日期,您可以使用 `make_date()` 函数,并且要创建日期和时间,可以使用内置函数 `make_datetime()`。
用于创建**日期**和**日期和时间**的语法如下:
make date(year = 1970L, m day = 1L) #To make date only
or
make_datetime( #To make both date and time
year = 1970L, m
day = 1L,
hour = 0L,
min = 0L,
sec = 0,
tz = "UTC"
)
其中参数
| 函数 | 示例 | 输出 |
|---|---|---|
| `make_date()` |
|
[1] "2020-03-27" |
| `make_datetime()` |
|
[1] "2020-03-27 UTC" |
日期可以表示为不同的格式,如 **“March 03, 22”、“3rd march 2022”、“Mar 3rd, 2022”、“03.03.22”** 等。转换规范可以与百分号(后跟一个字母,可以是大小写字母)的引入一起使用。在本节中,我们将学习一些最重要的格式。
我们使用转换规范来指定日期的格式。我们使用 `as.Date()` 函数,在参数的第一个位置使用代表所需格式类型的字符串,然后是 format 参数,它代表转换规范。
让我们做一个简单的例子,`as.Date()` 接收需要存储为日期对象类的字符串 **"22/03/27"**,并将其转换为 `format` 参数中指定的格式,即 **format = "%y/%m/%d"**。
#date and time formats in R
#"27/03/22"
as.Date("22/03/27",format ="%y/%m/%d" )
它会创建一个输出
[1] "2022-03-27"
请看下表,其中显示了用于不同日期和时间组件的转换规范。
| 规范 | 描述 | 示例 |
|---|---|---|
| %d | 月份中的日期(十进制数) | 27 |
| %m | 月份(十进制数) | 03 |
| %b | 月份(缩写) | Mar |
| %B | 月份(全名) | March |
| %y | 年份(2 位数) | 22 |
| %Y | 年份(4 位数) | 2022 |
| %H | 小时 | 8 |
| %M | 分钟 | 15 |
| %S | 秒 | 5 |
下面的程序包含一组不同的格式规范。使用 `as.Date()`、`as.POSIXct()`。尝试亲自进行每个程序,以更好地理解不同的格式。
#date and time formats in R
#"26/03/22"
as.Date("22/03/26",format ="%y/%m/%d" )
#2022-march-26
as.Date("2022-march-26",format="%Y-%b-%d")
#adding time component
#"26/03/22" 06:06:02
as.POSIXct("22/03/26 06:06:02 ",format ="%y/%m/%d %H:%M:%S" )
#adding time component with time zone
#"26/03/22" 06:06:02
as.POSIXct("22/03/26 06:06:02 ",format ="%y/%m/%d %H:%M:%S",tz="UTC")
这些不同转换规范的输出很容易理解。
> as.Date("22/03/27",format ="%y/%m/%d" )
[1] "2022-03-27"
> as.Date("2022-march-26",format="%Y-%b-%d")
[1] "2022-03-26"
> as.POSIXct("22/03/26 06:06:02 ",format ="%y/%m/%d %H:%M:%S" )
[1] "2022-03-26 06:06:02 IST"
> as.POSIXct("22/03/26 06:06:02 ",format ="%y/%m/%d %H:%M:%S",tz="UTC")
[1] "2022-03-26 06:06:02 UTC"