率直に言うと,時間データの処理はややこしいです。データファイル,OS,言語エンコーディングによって時間データのフォーマットは異なります。
ベースRでは,POSIXlt
や POSIXct
のクラス(class) があります。strftime()
や strptime()
などをつかって,時間データの変換は可能です。ここでは,lubridate
パッケージの関数の使いかたを紹介します。このパッケージに多数の便利な関数が
あります。研究室のコード開発には,lubridate
のパッケージをつかってください。。
パッケージの読み込み
まずは実用なパッケージを読み込みます。
library(tidyverse) # データ処理や作図に使う関数はここにある
library(lubridate) # 時間データ処理に使う関数はここ
Rにおける日時について
実際には,Rにおける時間データ(デートタイム) は秒で記録されています。正確には, 1970-01-01 00:00:00 UTC
1 から経過した秒数です。
例えば,1542498800
を時間データに変換すると,次の通りです。このデータのクラスは POSIXct
と POSIXlt
です。
out = as_datetime(1542498000)
out
## [1] "2018-11-17 23:40:00 UTC"
class(out)
## [1] "POSIXct" "POSIXt"
年月日データは 1970-01-01
からの日数です。このデータのクラスは Date
です。
out = as_date(17850)
out
## [1] "2018-11-15"
class(out)
## [1] "Date"
時分秒データは 00:00:00
からの秒数です。hms
も時間データ処理用のパッケージです。lubridate
はこのパッケージの関数を使用しています。
このデータのクラスは hms
と difftime
です。
out = hms::as.hms(34000)
## Warning: as.hms() is deprecated, please use as_hms().
## This warning is displayed once per session.
out
## 09:26:40
class(out)
## [1] "hms" "difftime"
デートタイムのパース
パース (parse) は,構文解析をすることです。つまり,文字列の内容を解析し,構成要素を明らかにすることです。lubridate
には文字列として記述した
デートタイムデータをパースするための関数が数種類ありますが,もっとも使いやすい関数は次の通りです。
ymd_hms()
,ymd_hm()
,ymd_h()
: 年(y),月(m),日(d), 時(h),分(m),秒(s)ymd_hms("2017-01-21 01:10:05")
ydm_hms()
,ydm_hm()
,ydm_h()
: 年(y),日(d),月(m), 時(h),分(m),秒(s)ydm_hm("2017-21-01 01:10")
mdy_hms()
,mdy_hm()
,mdy_h()
: 月(m),日(d),年(y), 時(h),分(m),秒(s)mdy_h("01/21/2017 01")
dmy_hms()
,dmy_hm()
,dmy_h()
: 日(d),月(m),年(y), 時(h),分(m),秒(s)dmy_hms("21 Jan 2017 01:10:05")
ymd()
,ydm()
,mdy()
,myd()
,ymd()
,dmy()
,dym()
:ymd(20180108)
,dmy("2018-01-08")
date_decimal()
:date_decimal(2018.9)
now(tzone = "")
: 今日の日時,tzone
を渡せば地方時の指定ができます。now()
,now("UTC")
today(tzone = "")
: 今日年月日today()
fast_strptime()
: ベースRのstrptime()
よりも処理が早い。fast_strptime("2018/02/20", "%y/%m/%d")
parse_date_time()
: ベースRのstrptime()
より使いやすい。parse_date_time("2018/02/20", "ymd")
OS によりデートタイムの表示が異なります。
サーバのOSは Linux です。時間のロケール (locale) は日本語に設定されているかもしれないです。次のコードを実行すれば,確認できます。
Sys.getlocale("LC_TIME")
## [1] "ja_JP.UTF-8"
日本語の場合,デートタイムの地方時は日本 (JST) です。
now()
## [1] "2020-10-30 08:27:49 JST"
曜日や月などを抽出するとき,日本語で表示されます。
now() %>% wday(label = TRUE)
## [1] 金
## Levels: 日 < 月 < 火 < 水 < 木 < 金 < 土
now() %>% month(label = TRUE)
## [1] 10月
## 12 Levels: 1月 < 2月 < 3月 < 4月 < 5月 < 6月 < 7月 < 8月 < ... < 12月
英語にする場合,ロケールを英語に変更します。
Sys.setlocale("LC_TIME", "en_US.UTF-8") # アメリカ英語に設定
## [1] "en_US.UTF-8"
now() %>% wday(label = TRUE)
## [1] Fri
## Levels: Sun < Mon < Tue < Wed < Thu < Fri < Sat
now() %>% month(label = TRUE)
## [1] Oct
## 12 Levels: Jan < Feb < Mar < Apr < May < Jun < Jul < Aug < Sep < ... < Dec
デートタイムの要素を抽出
デートタイムデータから特定の要素を抽出したいときに使う関数です。
date()
: 年月日year()
: 年month()
: 月day()
: 日wday()
: 曜日hour()
: 時minute()
: 分second()
: 秒week()
: 週am()
,pm()
: 午前か午後を確認し,論理値を返す。leap_year()
: うるう年か確認し,論理値を返す。
四捨五入,切り上げ,切り下げ
x
にデートタイムオブジェクトを渡し,unit
に単位を渡す。単位に,year, month, day, hour, minute, second は有効ですが,
10 minute
などにすると 10分間隔の単位になります。
floor_date(x, unit)
: 切り下げround_date(x, unit)
: 四捨五入ceiling_date(x, unit)
: 切り上げ
x = now()
x
## [1] "2020-10-30 08:27:49 JST"
floor_date(x, unit = "minute")
## [1] "2020-10-30 08:27:00 JST"
floor_date(x, unit = "20 minute")
## [1] "2020-10-30 08:20:00 JST"
ceiling_date(x, unit = "month")
## [1] "2020-11-01 JST"
floor_date(x, unit = "month")
## [1] "2020-10-01 JST"
標準時 (Time zones)
Rは 600 以上の地方時の認識ができます。
OlsonNames()
の関数をつかえば,認識されている地方時の名前が返ってきます。日本の場合は,次の通りです。
OlsonNames() %>% grep(pattern = "Jap|Tok", value = TRUE)
## [1] "Asia/Tokyo" "Japan"
デートタイムを用いた計算
デートタイムの算数は本当にややこしいです。デートタイムを記録するために,lubridate
は 3 つのクラスを用意しています。
period
: 時計で経過した時間duration
: 実際の時間の経過interval
: 開始・終了時間の間の期間
これは夏時間 (daylight savings time; サマータイム) の時に大きな影響があります。次のアメリカの EST/EDT を参考にしてください。
x = ymd_hms("2018-03-11 01:30:00", tz = "US/Eastern")
x + minutes(90)
## [1] "2018-03-11 03:00:00 EDT"
x + dminutes(90)
## [1] "2018-03-11 04:00:00 EDT"
interval(x, x + minutes(90))
## [1] 2018-03-11 01:30:00 EST--2018-03-11 03:00:00 EDT
x = ymd_hms("2018-11-04 00:30:00", tz = "US/Eastern")
x + minutes(90)
## [1] "2018-11-04 02:00:00 EST"
x + dminutes(90)
## [1] "2018-11-04 01:00:00 EST"
interval(x, x + minutes(90))
## [1] 2018-11-04 00:30:00 EDT--2018-11-04 02:00:00 EST
うるう年の計算にも影響がでます。
x = ymd("2019-03-01")
x + years(1)
## [1] "2020-03-01"
x + dyears(1)
## [1] "2020-02-29 06:00:00 UTC"
interval(x, x + years(1))
## [1] 2019-03-01 UTC--2020-03-01 UTC
ときに,months()
で月を加算すると imaginary date の問題がでます。
ymd("2018-01-31") + months(1)
## [1] NA
ymd("2018-01-31") %m+% months(1)
## [1] "2018-02-28"
ymd("2018-03-30") - months(1)
## [1] NA
ymd("2018-03-30") %m-% months(1)
## [1] "2018-02-28"
時計時間には period, 経過時間には duration
時計時間の場合,period
クラスを使用してください。
out = years(1) + months(3) + minutes(20)
out
## [1] "1y 3m 0d 0H 20M 0S"
241ヶ月の期間
out = period(241, units = "months")
out
## [1] "241m 0d 0H 0M 0S"
period_to_seconds(out) # 秒に変換する
## [1] 633781800
interval
を period
に変換する。
out = now()
out = interval(out, out + minutes(90))
out
## [1] 2020-10-30 08:27:50 JST--2020-10-30 09:57:50 JST
as.period(out, unit = "seconds")
## [1] "5400S"
as.period(out, unit = "minutes")
## [1] "90M 0S"
経過時間の場合は,duration
クラスを使用してください。
out = ddays(13)
out
## [1] "1123200s (~1.86 weeks)"
duration(13, units = "days")
## [1] "1123200s (~1.86 weeks)"
duration
を period
に変換する。
out = now()
out = interval(out, out + minutes(90))
out
## [1] 2020-10-30 08:27:50 JST--2020-10-30 09:57:50 JST
as.duration(out)
## [1] "5400s (~1.5 hours)"
時間データの表記に使うフォーマット指定方法
日付関係のフォーマット記号
%a
: 曜日の省略%A
: 曜日%b
: 月名の省略%B
: 月名%c
:%a %b %e %H:%M:%S %Y
の省略%d
: 日,1 から 9 日は 1 桁目に 0%D
:%m/%d/%y
の省略%e
: 日,1 から 9 日は 1 桁目にスペース%F
:%Y-%m-%d
の省略%H
: 時,24時間表記,1 桁目に 0%I
: 時,12時間表記,1 桁目に 0%j
: 年日,001 から 366%m
: 月,1 から 12 は 1 桁目に 0%M
: 分,1 桁目に 0%p
: ロケールにおける AM/PM に相当する文字列(日本語の場合は午前・午後)%S
: 秒,0 から 61 は 1 桁目に 0%y
: 西暦の下 2 桁%Y
: 西暦 4 桁
Coordinated Universal Time; 協定世界時↩︎