【數據分析】R|時間格式處理|date format & lubridate

在R之中,我們有時會需要時間的轉換。常常抓到網路資料後,得到的timestamp欄位可能是char或是num的格式,這時候就可以採用內建的as.date或取用lubridate這個package。但在了解怎麼用後面的函數從字串中轉成時間前,得先知道什麼是標準的時間格式,才知道怎麼得到想要的結果。

標準時間格式

class為「POSIXlt」和「POSIXct」,包含資料的格式為"%Y-%m-%d %H:%M:%S"。
  • "年-月-日 時:分:秒" 在日期間以「-」區隔,時間以「:」區隔,兩者以一個空白分隔。
  • %m 小寫是月(month), %M 大寫是分(Minute) → 時間的格式都是大寫。
我們常用Sys.time()或now()來取得執行當下的時間點,可以得到標準格式"2018-11-09 11:35:06 CST"
  • 以我們台灣來講,CST = China Standard Time,也就是常聽到的中原標準時間,是我們這個經度所位在的時區。相對於UTC地球標準時間要加上八小時。即為UTC+8。
  • UTC = Coordinated Universal Time是像秒一樣的公定標準,格林威治標準時間GMT = Greenwich Mean Time所在時區與該時間相同。
  • now()之中可以設定時區 → now(tzone = "UTC") 會得到比CST少8小時的結果。
而日期格式較為簡單,class為「Date」,取得當天日期則用Sys.Date()。

轉換為日期

首先先看日期的部分,實作上,常碰到的是三種狀況:
  1. 長相已經是標準日期(Ex: 2018-11-09),但型別為character
  2. 長相是數字(Ex: 17844),型別為numeric
  3. 各式長相的時間(Ex: "November 9, 2018"、"09/11/2018"),型別為character
面對這些該如何怎麼解決呢?

解決方法:as.Date搭配format設定

[1] as.Date("2018-11-09")
  →"2018/11/09"也可以直接放入,自動轉換成-
[2] as.Date(17844, origin)
  →系統預設origin為1970-01-01,它會自動從這天開始得到17844天後之日期。
[3] as.Date("November 9, 2018", format="%B %d, %Y")
  →%B用來抓取月份的英文全名(%b則為縮寫)January vs. Jan
  →%A則是抓取星期幾的英文名(%a也為縮寫)Friday vs. Fri
[4] as.Date("09/11/2018", format="%d/%m/%Y")

注意

如果[3]類行不通,是跟語言設定有關,原因為預設之locale為「Chinese (Traditional)_Taiwan.950」,處理內容須為「十一月 09, 2018」才有效。處理方法是將locale語言做改變,依序步驟如下:
  • lct <- Sys.getlocale("LC_TIME") 取得當前的語言
  • Sys.setlocale("LC_TIME", "C") 設定語言
  • 將 [3] 英文版的內容輸入於此即可!
  • Sys.setlocale("LC_TIME", lct) 重新設定為原語言
有趣的是,中文的「%A是星期」五,「%a是週」五。

轉換為標準時間格式

再來看看時間,常碰到的也是三種狀況:
  1. 長相已經是標準時間格式的樣子,但型別為character
  2. 長相是數字(Ex: 1541111111),型別為numeric
  3. 各式長相的時間(Ex: "Nov 9, 2018 11:35:06"),型別為character
這些又該如何怎麼解決呢?

解決方法:as.POSIXct 或 as.POSIXlt(想知道他們有什麼不同可以點這)

[1] as.POSIXct("2018-11-09 15:17:18 CST")
[2] as.POSIXlt(1541111111, origin="1970-01-01 00:00:00")
  → 得到 "2018-11-02 06:25:11 CST"
[3] as.POSIXlt("Nov 9, 2018 15:17:18", format="%b %d, %Y %H:%M:%S")
  → 得到 "2018-11-09 15:17:18 CST"

解決方法:直接用Lubridate套件(package)

[1] as_datetime("2018-11-09 15:17:18 CST")
[2] as_datetime(1541111111)
[3] mdy_hms("Nov 9, 2018 11:35:06")

注意

缺點是轉換出來的結果會將時區統一變成UTC,所以需要額外做時區轉換,待下篇再著墨這部分。

那Lubridate的函數能解決轉換成日期的問題嗎?

當然可以!來看第一區塊怎麼快速轉換,如下:

[1] as_date("2018-11-09")或ymd("2018-11-09")
[2] as_date(17844)
[3] mdy("November 9, 2018")
[4] dmy("09/11/2018")

非常強大,包含%B都能處理並能自動忽略其他非數字,函數會自動依照你訂的順序找到相符的結果,輸出標準格式的日期出來。(但如果有數字的話會受到干擾)

Lubridate

含有許多專門針對日期時間所設計的函數。除了像上述轉換為POSIXct標準格式,還包含了年月日時分秒的快速取用(反過來,把標準時間轉成自己想要的輸出),以及對時區的轉換。
  比方,我習慣將現在系統時間a <- Sys.time()存起來,再來就能直接用month(a), day(a), hour(a)直接得到月、日、小時的資訊,方便我直接將抓取到的資料為檔案命名。

結語

Lubridate對於稍微醜又不會太醜(?)的時間日期做修正,是非常好用的,然而對於混雜的時間和日期就無法處理,比如"Nov 9 11:35:06, 2018"這種時間安插在日期之間的資料,它就沒有md_hms_y之類的Function處理,而直接用mdy_hms又會回報錯誤。

  所以這時候,反而回過頭用as.POSIXct自己根據資料內容觀察,自行設定format會較方便。例如:

  • as.POSIXlt("Nov 9,11:35:06,2018", format="%b %d,%H:%M:%S,%Y")

  如果再複雜一點,可以先用RegEx搭配相關擷取函數清理掉非數字,且保留日期和星期的特殊字,再將結果用這裡提到的方法整理成標準時間即可。


下一篇我會補充講解如何將as_datetime的結果修正,把時區轉換成自訂的時區。

留言

【熱門】# HOT

【數據分析】R|擷取字串|RegEx與常用函數

【軟體操作】Google Slides|下載共用簡報方式與網址