R 中的日期和时间处理


2022 年 4 月 16 日, Learn eTutorial
2091

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

date,time img

我们还将介绍 **lubridate** 包的用法。 **lubridate** 包是 R 中处理日期和时间数据的包之一。

安装 lubridate 包

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")

如何获取当前日期和时间?

current date,time img

我们使用 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 标准来指定和表示数据和时间。从输出中可以清楚地看出,因为日期部分后面跟着时间部分。

ISO std img
date,time snippet

如何检查时间是上午还是下午?

`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 中我们讨论过的代码的截图

am pm snippet

如何检查闰年?

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()` 代码的。

leap yr snippet

日期和时间在 R 中如何存储?

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

如何理解 R 中的日期和时间类?

date n time classes img

内置的 R 函数具有不同的类。lubridate 包的 `Sys.Date()`、R 基础包的 `now()` 用于表示日期,它们属于不同的类。例如


class(Sys.Date())
[1] "Date"
> class(now())
[1] "POSIXct" "POSIXt"

注意: `class()` 用于确定 R 对象的内部类型。有多种类型的类,如字符、整数、逻辑、因子、数据框等。日期也是其中一种类。

在此部分,您将了解三个不同的类

  1. 日期 (Date)
  2. POSIXct
  3. POSIXlt

日期类 – `as.Date()` 用于日期

在 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 类仅用于包含日期组件的数据,不用于日期和时间组件或时区。

日期和时间的 POSIX 类

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 POSIXlt
POSIXct 将日期和时间组件在内部存储为自 1970 年 1 月 1 日以来的秒数。 POSIXlt 将日期和时间组件以列表格式存储,用于秒、分、小时、月份中的第几天、月份、年份、年份中的第几天数等。

注意: `as.POSIX*` 函数将对象转换为用于表示日期/时间的两个类之一。

如何在 R 中提取日期和时间组件?

您可以使用 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()` 星期几

`wday(DT)`  

`wday(DT,label=TRUE)`    

`wday(DT,label=TRUE,abbr=FALSE)`   

[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()` 星期几

`weekdays(DT)`

`weekdays(DT,abbreviate=FALSE)`

`weekdays(DT,abbreviate=TRUE)`

[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"
ISO std img

如何创建日期和时间?

要创建日期,您可以使用 `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"
)

其中参数

  • **year** 数值年份
  • **month** 数值月份
  • **day** 数值日期
  • **hour** 数值小时
  • **min** 数值分钟
  • **sec** 数值秒
  • **tz** 时区。默认为 UTC。

为这两个函数考虑一个简单的例子

函数 示例 输出
`make_date()`

`make_date(year =2020, m day=27)` 

[1] "2020-03-27"  
`make_datetime()`

`make_datetime(year =2020,mday=27, hour = 0L,min = 0L,sec = 0, tz = "UTC")`  

 [1] "2020-03-27 UTC"

R 中的日期和时间格式

日期可以表示为不同的格式,如 **“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"