首頁 > 軟體

R語言日期時間的使用

2022-03-04 13:00:43

1.日期和日期時間型別

       R 中日期可以儲存為 Date 型別,一般用整數儲存,數值為從 1970-1-1 經過的天數。

        R 中用一種叫做 POSIXct 和 POSIXlt 的特殊資料型別儲存日期和時間,可以僅包含日期部分,也可以同時有日期和時間。技術上,POSIXct 把日期時間儲存為從 1970 年 1 月 1 日零時到該日期時間的時間間隔秒數,所以資料框中需要儲存日期時用 POSIXct 比較合適,需要顯示時再轉換成字串形式;POSIXlt 把日期時間儲存為一個包含年、月、日、星期、時、分、秒等成分的列表,所以求這些成分可以從 POSIXlt 格式日期的列表變數中獲得。日期時間會涉及到所在時區、夏時制等問題,比較複雜。

        基礎的 R 用 as.Date()、as.POSIXct() 等函數生成日期型和日期時間型,R 擴充套件包 lubridate 提供了多個方便函數,可以更容易地生成、轉換、管理日期型和日期時間型資料。
載入擴充套件包的方式:

載入擴充套件包的方式:

library(lubridate)

如果下面內容:

證明你沒有安裝此擴充套件包

此時需要安裝擴充套件包,安裝方式如下:

點選【程式包】,再點選【安裝程式包】

然後,找到 China(Beijing 2)

然後找到需要安裝的擴充套件包 lubridate 

 然後,點選【確定】即可,安裝完成會出現如下內容

這次我們再此載入擴充套件包 lubridate 

2.從字串生成日期資料

        函數 lubridate::today() 返回當前日期

today()

返回:

        函數 lubridate::now() 返回當前日期時間

now()

返回:

在結果中,我們看到了 CST 字樣,CST 是時區,這裡使用了作業系統提供的當前時區。CST 不是一個含義清晰的時區,在不同國家對應不同的時區,在中國代表中國標準時間(北京時間)

        用 lubridate::ymd(), lubridate::mdy(), lubridate::dmy() 字元型向量轉換為日期型向量,但是他們的輸入方式不相同,y 表示m 表示d 表示,如:         年 - 月 - 日

ymd(c("2022-1-24","2022-01-24"))

返回:

        月 - 日 - 年

mdy(c("1-24-2022", "01-24-2022"))

返回:

        日 - 月 - 年: 

dmy(c("24-1-2022","24-01-2022"))

返回:

如果在年號只有兩位數位時,預設對應到 1969-2068 範圍。

        lubridate::make_date(year, month, day) 可以從三個數值構成日期向量。如

make_date(2022, 1, 24)

返回:

        lubridate 包的 ymd、mdy、dmy 等函數新增 hms、hm、h 等字尾,可以用於將字串轉換成日期時間。如

ymd_hms("2022-1-24 19:26:35")

返回:

結果顯示中 UTC 是時區,UTC 是協調世界時 (Universal Time Coordinated) 英文縮寫,是由國際無線電諮詢委員會規定和推薦, 並由國際時間局 (BIH) 負責保持的以秒為基礎的時間標度。UTC 相當於本初子午線 (即經度 0 度) 上的平均太陽時,過去曾用格林威治平均時 (GMT) 來表示. 北京時間比 UTC 時間早 8 小時,以 1999 年 1 月 1 日 0000UTC 為例,UTC 時間是零點,北京時間為 1999 年 1 月 1 日早上 8 點整。

Date()as.DateTime()ymd() 等函數中,可以用 tz= 指定時區,比如北京時間可指定為 tz="Etc/GMT+8" 或 tz="Asia/Shanghai"。

        lubridate::make_datetime(year, month, day, hour, min, sec) 可以從最多六個數值組成日期時間,其中時分秒預設值都是 0。如

make_datetime(2022, 1, 24, 19, 32, 36)

返回:

        用 lubridate::as_date() 可以將日期時間型轉換為日期型,如

as_date(as.POSIXct("2022-01-24 19:32:36"))

返回:

        用 lubridate::as_datetime() 可以將日期型資料轉換為日期時間型,如

as_datetime(as.Date("2022-01-24"))

返回:

3.日期顯示格式

        用 as.character() 函數把日期型資料轉換為字元型, 如

x <- as.POSIXct(c('2022-1-24', '2022-01-24'))
as.character(x)

返回:

        在 as.character() 中可以用 format 選項指定顯示格式,格式中 “%Y” 代表四位的公元年號,“%m” 代表兩位的月份數位,“%d” 代表兩位的月內日期號

如 %m/%d/%Y 表示 月-日-年

x <- as.POSIXct(c('2022-1-24', '2022-01-24'))
as.character(x, format='%m/%d/%Y')

返回:

        "15Mar98" 這樣的日期在英文環境中比較常見,但是在 R 中的處理比較複雜。在下面的例子中,R 日期被轉換成了類似"Mar98" 這樣的格式,在 format 選項中用了 “%b” 代表三英文字母月份縮寫,但是因為月份縮寫依賴於作業系統預設語言環境,需要用 Sys.setlocale() 函數設定語言環境為"C"。範例程式如下

x <- as.POSIXct(c('2022-1-24', '2022-01-24'))
old.lctime <- Sys.getlocale('LC_TIME')
Sys.setlocale('LC_TIME', 'C')

返回:

as.character(x, format='%b%y')

返回:

Sys.setlocale('LC_TIME', old.lctime)

返回:

 包含時間的轉換,

x <- as.POSIXct('2022-1-24 19:56:42')
as.character(x)

返回:

as.character(x, format='%H:%M:%S')

返回:

這裡 “%H” 代表小時(按 24 小時制),“%M” 代表兩位的分鐘數位,“%S” 代表兩位的秒數。

4.存取日期時間的組成值

lubridate 包的如下函數可以取出日期型或日期時間型資料中的組成部分:

  • year() 取出年
  • month() 取出月份數值
  • mday() 取出日數值
  • yday() 取出日期在一年中的序號,元旦為 1
  • wday() 取出日期在一個星期內的序號,但是一個星期從星期天開始,星期天為 1, 星期一為 2,星期六為 7。
  • hour() 取出小時
  • minute() 取出分鐘
  • second() 取出秒

比如, 2022-1-24 是星期一,則 提取月份

month(as.POSIXct("2022-1-24 19:56:42"))

返回:

提取日

mday(as.POSIXct("2022-1-24 19:56:42"))

返回:

提取日期在一個星期內的序號

wday(as.POSIXct("2022-1-24 19:56:42"))

lubridate 的這些成分函數還允許被賦值,結果就修改了相應元素的值,如         將年份由 2022 賦值為 2000

x <- as.POSIXct("2022-1-24 20:08:15")
year(x) <- 2000
month(x) <- 1
mday(x) <- 1 
x

返回:

        update() 可以對一個日期或一個日期型向量統一修改其組成部分的值,如

x <- as.POSIXct("2022-1-24 20:08:15")
y <- update(x, year=2000) 
y

返回:

update() 函數中可以用 year, month, mday, hour, minute, second 等引數修改日期的組成部分。

5.日期舍入計算

lubridate 包提供了 floor_date(), round_date(), ceiling_date() 等函數,對日期可以用 unit= 指定一個時間單位進行舍入。時間單位為字串,如 seconds, 5 seconds, minutes, 2 minutes, hours, days, weeks, months, years 等。

比如,以 10 minutes 為單位,floor_date() 將時間向前歸一化到 10 分鐘的整數倍:

x <- ymd_hms("2022-1-24 20:08:15")
floor_date(x, unit="10 minutes")

返回:

 

        ceiling_date() 將時間向後歸一化到 10 分鐘的整數倍:

x <- ymd_hms("2022-1-24 20:08:15")
ceiling_date(x, unit="10 minutes")

返回: 

        round_date() 將時間歸一化到最近的 10 分鐘的整數倍,時間恰好是 5 分鐘倍數時按照類似四捨五入的原則向上取整。例如

x <- ymd_hms("2022-1-24 20:08:15")
round_date(x, unit="10 minutes")

返回:

如果單位是星期,會涉及到一個星期週期的開始是星期日還是星期一的問題。用引數week_start=7 指定開始是星期日week_start=1 指定開始是星期一。  

6.日期計算

lubridate 的支援下日期可以相減,可以進行加法、除法。lubridate 包提供瞭如下的三種與時間長短有關的資料型別:

  • 時間長度 (duration),按整秒計算
  • 時間週期 (period),如日、周
  • 時間區間 (interval),包括一個開始時間和一個結束時間

 6.1 時間長度         

R 的 POSIXct 日期時間之間可以相減,如

d1 <- ymd_hms("2022-01-24 0:0:0")
d2 <- ymd_hms("2022-01-24 12:0:5")
di <- d2 - d1; di

返回:

結果顯示與日期之間差別大小有關係,結果是型別是 difftime

        lubridate 包提供了 duration 型別,處理更方便:

as.duration(di)

返回:

        lubridatedseconds(), dminutes(), dhours(), ddays(), dweeks(), dyears() 函數可以直接生成時間長度型別的資料,如

dhours(1)

返回:

        lubridate 的時間長度型別總是以秒作為單位,可以在時間長度之間相加,也可以對時間長度乘以無量綱數,如

dhours(1) + dseconds(5)

返回:

dhours(1)*10

返回:

        可以給一個日期加或者減去一個時間長度,結果嚴格數按推移的秒計算,如

d2 <- ymd_hms("2022-01-24 12:0:5")
d2 - dhours(5)

 返回:

d2 <- ymd_hms("2022-01-24 12:0:5")
d2 + ddays(10)

返回:

時間的前後推移在涉及到時區和夏時制時有可能出現未預料到的情況。

        用 unclass() 函數將時間長度資料的型別轉換為普通數值,如:

unclass(dhours(1))

返回:

 6.2 時間週期

        時間長度的固定單位是秒,但是像月、年這樣的單位,因為可能有不同的天數,所以日曆中的時間單位往往沒有固定的時長。         lubridate 包的 seconds(), minutes(), hours(), days(),weeks(), years() 函數可以生成以日曆中正常的週期為單位的時間長度,不需要與秒數相聯絡,可以用於時間的前後推移。這些時間週期的結果可以相加、乘以無量綱整數:

years(2) + 10*days(1)

返回:

lubridate 的月度週期因為與已有函數名衝突,所以沒有提供,需要使用 lubridate::period(num, units="month") 的格式,其中 num 是幾個月的數值。

        為了按照日曆進行日期的前後平移,而不是按照秒數進行日期的前後平移,應該使用這些時間週期。例如,因為 2016 年是閏年,按秒數給 2016-01-01 加一年,得到的並不是 2017-01-01:

ymd("2016-01-01") + dyears(1)

返回:

        使用時間周期函數則得到預期結果

ymd("2016-01-01") + years(1)

返回:

 6.3 時間區間

        lubridate 提供了%--% 運運算元構造一個時間期間。時間區間可以求交集、並集等。

         構造如:

d1 <- ymd_hms("2000-01-01 0:0:0")
d2 <- ymd_hms("2000-01-02 12:0:5")
din <- (d1 %--% d2); din

返回:

        對一個時間區間可以用除法計算其時間長度,如

din / ddays(1)

返回:

din / dseconds(1)

返回:

        生成時間區間,也可以用 lubridate::interval(start, end) 函數,如

interval(ymd_hms("2000-01-01 0:0:0"), ymd_hms("2000-01-02 12:0:5"))

返回:

        可以指定時間長度和開始日期生成時間區間,如

d1 <- ymd("2022-01-24")
din <- as.interval(dweeks(1), start=d1); din

返回:

注意這個時間區間表面上涉及到 8 個日期,但是實際長度還是隻有 7 天,因為每一天的具體時間都是按零時計算,所以區間末尾的那一天實際不含在內。         用 lubridate::int_start()lubridate::int_end() 函數存取時間區間的端點,如:

int_start(din)

返回:

int_end(din)

返回:

可以用 as.duration() 將一個時間區間轉換成時間長度,用 as.period() 將一個時間區間轉換為可變時長的時間週期個數。         用 lubridate::int_shift() 平移一個時間區間,如

din2 <- int_shift(din, by=ddays(3)); din2

返回:

        用 lubridate::int_overlaps() 判斷兩個時間區間是否有共同部分,如

int_overlaps(din, din2)

返回:

        時間區間允許開始時間比結束時間晚,用 lubridate::int_standardize() 可以將時間區間標準化成開始時間小於等於結束時間lubridate() 現在沒有提供求交集的功能,一個自定義求交集的函數如下:

int_intersect <- function(int1, int2){
n <- length(int1)
int1 <- lubridate::int_standardize(int1)
int2 <- lubridate::int_standardize(int2)
sele <- lubridate::int_overlaps(int1, int2)
inter <- rep(lubridate::interval(NA, NA), n)
if(any(sele)){
inter[sele] <-
lubridate::interval(pmax(lubridate::int_start(int1[sele]),
lubridate::int_start(int2[sele])),
pmin(lubridate::int_end(int1[sele]),
lubridate::int_end(int2[sele])))
}
inter
}

測試如下:

d1 <- ymd(c("2018-01-15", "2018-01-18", "2018-01-25"))
d2 <- ymd(c("2018-01-21", "2018-01-23", "2018-01-30"))
din <- interval(d1, d2); din

返回:

接下來,我們用用上面自定義的函數試試:

首先得先匯入這個函數

source("D:/桌面/R語言/int_intersect.r")

然後,我們呼叫一下

int_intersect(rep(din[1], 2), din[2:3])

返回:

 此自定義函數還可以進一步改成允許兩個自變數長度不等的情形。

7.基本 R 軟體的日期功能

7.1 生成日期和日期時間型資料

        對 yyyy-mm-dd 或 yyyy/mm/dd 格式的資料,可以直接用 as.Date() 轉換為 Date 型別,如:

x <- as.Date("2022-1-24"); x

返回:

as.numeric(x)

返回:

        as.Date() 可以將多個日期字串轉換成 Date 型別,如

as.Date(c("2022-1-24", "2022-01-24"))

返回:

        對於非標準的格式,在 as.Date() 中可以增加一個 format 選項,其中用%Y 表示四位數位的年,%m 表示月份數位,%d 表示日數位。如

as.Date("1/24/2022", format="%m/%d/%Y")

返回:

        用 as.POSIXct() 函數把年月日格式的日期轉換為 R 的標準日期,沒有時間部分就認為時間在午夜。 年月日中間的分隔符可以用號也可以用正斜槓,但不能同時有減號又有斜槓。如

as.POSIXct(c('2022-1-24'))

返回:

as.POSIXct(c('2022/01/24'))

返回:

        待轉換的日期時間字串,可以是年月日之後隔一個空格以 “時: 分: 秒” 格式 帶有時間。如

as.POSIXct('2022-01-24 13:15:45')

返回:

        用 as.POSIXct() 可以同時轉換多項日期時間,如

as.POSIXct(c('1998-03-16 13:15:45', '2015-11-22 9:45:3'))

返回:

        轉換後的日期變數有 class 屬性,取值為 POSIXctPOSIXt, 並帶有一個 tzone(時區)屬性

x <- as.POSIXct(c('1998-03-16 13:15:45', '2015-11-22 9:45:3'))
attributes(x)

返回:

        在 as.POSIXct() 函數中用 format 引數指定一個日期格式。如

as.POSIXct('1/24/22', format='%m/%d/%y')

返回:

        如果日期僅有年和月,必須新增日(新增 01 為日即可)才能讀入。比如用’1991-12’ 表示 1991 年 12 月,則如下程式將其讀入為’1991-12-01’:

as.POSIXct(paste('1991-12', '-01', sep=''), format='%Y-%m-%d')

返回:

又如

old.lctime <- Sys.getlocale('LC_TIME')
Sys.setlocale('LC_TIME', 'C')

返回:

as.POSIXct(paste('01', 'DEC91', sep=''), format='%d%b%y')

返回:

Sys.setlocale('LC_TIME', old.lctime)

返回:

 把'DEC91' 轉換成了’1991-12-01’。

        如果明確地知道時區,在 as.POSIXct()as.POSIXlt() 中可以加選項 tz= 字串。選項 tz 的預設值為空字串,這一般對應於當前作業系統的預設時區。但是,有些作業系統和 R 版本不能使用預設值,這時可以為 tz 指定時區,比如北京時間可指定為 tz='Etc/GMT+8'。如

as.POSIXct('1949-10-01', tz='Etc/GMT+8')

返回:

7.2 取出日期時間的組成值

        把一個 R 日期時間值用 as.POSIXlt() 轉換為 POSIXlt 型別,就可以用列表元素方法取出其組成的年、月、日、時、分、秒等數值。如

x <- as.POSIXct('1998-03-16 13:15:45')
y <- as.POSIXlt(x)
cat(1900+y$year, y$mon+1, y$mday, y$hour, y$min, y$sec, 'n')

返回:

注意 year 要加 1900,mon 要加 1。另外,列表元素 wday 取值 1-6 時表示星期一到星期六,取值 0 時表示星期天。         對多個日期,as.POSIXlt() 會把它們轉換成一個列表(列表型別稍後講述),這時可以用列表元素 year, mon, mday 等取出日期成分。如

x <- as.POSIXct(c('1998-03-16', '2015-11-22'))
as.POSIXlt(x)$year + 1900

返回:

7.3  日期計算

因為 Date 型別是用數值儲存的,所以可以給日期加減一個整數,如:

x <- as.Date("1970-1-5")
x1 <- x + 10; x1

返回:

x2 <- x - 5; x2

返回:

所有的比較運算都適用於日期型別。         可以給一個日期加減一定的秒數,如

as.POSIXct(c('1998-03-16 13:15:45')) - 30

返回:

as.POSIXct(c('1998-03-16 13:15:45')) + 10

返回:

但是兩個日期不能相加。         給一個日期加減一定天數,可以通過加減秒數實現,如

as.POSIXct(c('1998-03-16 13:15:45')) + 3600*24*2

返回:

這個例子把日期推後了兩天。

difftime(time1, time2, units='days') 計算 time1 減去 time2 的天數,如

x <- as.Date("1970-1-5")
x1 <- x + 10; x1

返回:

函數結果用 c() 包裹以轉換為數值, 否則會帶有單位。

呼叫 difftime() 時如果前兩個自變數中含有時間部分,則間隔天數也會帶有小數部分。如

x <- as.POSIXct(c('1998-03-16 13:15:45', '2015-11-22 9:45:3'))
c(difftime(x[2], x[1], units='days'))

返回:

difftime() 中 units 選項還可以取為 'secs', 'mins', 'hours' 等。

練習

設檔案dates.csv中包含如下內容:
"出生日期","發病日期"
"1941/3/8","2007/1/1"
"1972/1/24","2007/1/1"
"1932/6/1","2007/1/1"
"1947/5/17","2007/1/1"
"1943/3/10","2007/1/1"
"1940/1/8","2007/1/1"
"1947/8/5","2007/1/1"
"2005/4/14","2007/1/1"
"1961/6/23","2007/1/2"
"1949/1/10","2007/1/2"
把這個檔案讀入為 R 資料框 dates.tab,執行如下程式定義 date1 和 date2
變數:

date1 <- dates.tab[,' 出生日期']
date2 <- dates.tab[,' 發病日期']

(1) 把 date1、date2 轉換為 R 的 POSIXct 日期型。
(2) 求 date1 中的各個出生年。
(3) 計算髮病時的年齡,以週歲論(過生日才算)
(4) 把 date2 中發病年月轉換為’monyy’ 格式,這裡 mon 是如 FEB 這樣英文三字母縮寫,yy 是兩數位的年份。
(5) 對諸如’FEB91’, ’OCT15’ 這樣的年月資料,假設 00—20 表示 21 世紀年份,21—99 表示 20 實際年份。編寫 R 函數,輸入這樣的字元型向量,返回相應的 POSIXct 格式日期,具體日期都取為相應月份的 1 號。這個習題和後兩個習題可以預習函數部分來做。
(6) 對 R 的 POSIXct 日期,寫函數轉換成’FEB91’, ’OCT15’ 這樣的年月表示,假設 00—20 表示 21 世紀年份,21—99 表示 20 實際年份。
(7) 給定兩個 POSIXct 日期向量 birth 和 work,birth 為生日,work 是入職日期,編寫 R 函數,返回相應的入職週歲整數值(不到生日時週歲值要減一)。

到此這篇關於R語言日期時間的使用的文章就介紹到這了,更多相關R語言日期時間內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com