R言語の日付と時間に関してよく使うテクニックをまとめました。
Rに標準でインストールされているパッケージbaseの中のDateクラスとPOSIXクラスの操作方法について解説していきます。
日付や時間からhour, min, secなどを抽出する例やシリアル値から対応する日付または時間に変換する例をみていきます。
今回扱うプログラミングコードは以下のファイルにまとめています。
R言語 日付・時間の操作
日付・Dateクラス
まずは日付の操作に用いられるDateクラスについてみていきます。
"2021-12-5"のような日付を表す文字列のフォーマットを変えて"2021年12月-5日"にしたり、2021年や12月を抽出するときに、Dateクラスを用います。
関数Sys.Dateを使うと、実行したときの日付を取得することができます。関数strを用いてクラスを確認するとDateクラスであることが分かります。
1 2 3 4 | > #日付 > today <- Sys.Date() > str(today) Date[1:1], format: "2021-12-05" |
余談ですが、関数julianでDateクラスオブジェクトのorigin(基準日)を参照することができます。1970年1月1日基準から18966日後(シリアル値)であり、基準日が変わるとこの値も変わってきます。
1 2 3 4 | > julian(today) #基準日1970-01-01からの日数 [1] 18966 attr(,"origin") [1] "1970-01-01" |
年月日の抽出
Dateクラスから年月日を抽出するための便利なパッケージがありますが、ここでは標準の環境で取り出す例を紹介します。
関数monthsとweekdaysでそれぞれ月と曜日を取得することが可能です。
1 2 3 4 5 | > #年月日の抽出 > months(today) #月 [1] "12月" > weekdays(today) #曜日 [1] "日曜日" |
また、Dateクラスオブジェクトを時間・POSIXct, POSIXltクラスで紹介するPOSIXltクラスに変換することで、月と曜日だけでなく年・月・日などの情報を全て抽出することができます。
1 2 3 4 5 6 7 8 9 10 11 12 | > todaylt <- as.POSIXlt(today, tz = "UTC") > list_todaylt <- unclass(todaylt) > list_todaylt$mday #日 [1] 5 > list_todaylt$mon #基準日からの月数 [1] 11 > list_todaylt$year #基準日からの年数 [1] 121 > list_todaylt$wday #一週間のうち何日目か [1] 0 > list_todaylt$yday #基準日の日付からの日数 [1] 338 |
注意として、一部の値はoriginからのずれとなっているため、1だけずれていたりします(12月ですが、monを参照すると11が返ってきます)。
フォーマットの変換
次に、Dateクラスのフォーマットの変換について解説します。最初に述べたように"2021/12/5"などのデータを"2021年12月05日"や"12-05-2021"に変換したいときがあると思いますが、関数format.Dateを用いることで次のように簡単に変換することができます。
1 2 3 4 5 | > #format > format(today, "%y %m %d") #年月日のformat [1] "21 12 05" > format(today, "%Y %B %d") [1] "2021 12月 05" |
また、localeを変更することで月や曜日を英語に変更することもできます。
1 2 3 4 5 | > lct <- Sys.getlocale("LC_TIME") > Sys.setlocale("LC_TIME", "C") [1] "C" > format(today, "%Y %B %d") #英語表記 [1] "2021 December 05" |
localeを元の日本語に戻すには、以下を実行してください。
1 | Sys.setlocale("LC_TIME", lct) |
文字列からDateクラスに変換する際は、対応するフォーマットの記号を引数formatに並べればおkです。
1 2 3 | > date <- "April, 15, 2021" > as.Date(date, format = "%B, %d, %Y") #文字列からDateクラスへの変換 [1] "2021-04-15" |
以下にDateクラスで用いるフォーマットの記号をまとめておきます。
%d | 日 |
%m | 月(数字) |
%b | 月(文字列 省略) |
%B | 月(文字列) |
%y | 年(2桁) |
%Y | 年(4桁) |
日付の生成
日付を生成したいときは関数seq.Dateを用いると便利です。
関数seqで連続する数値を生成できたように、連続する日付を生成することができます。
1 2 3 4 5 6 7 | > #日付の生成 > startDate <- as.Date("21/10/15", "%y/%m/%d") > endDate <- as.Date("21/10/30", "%y/%m/%d") > seq(from = startDate, to = endDate, by = "day") [1] "2021-10-15" "2021-10-16" "2021-10-17" "2021-10-18" "2021-10-19" "2021-10-20" "2021-10-21" [8] "2021-10-22" "2021-10-23" "2021-10-24" "2021-10-25" "2021-10-26" "2021-10-27" "2021-10-28" [15] "2021-10-29" "2021-10-30" |
また、数値のときと同様に 関数sampleでランダムな日付を取得することもできます。
1 2 3 | > sample(seq(from = startDate, to = endDate, by = "day"), 10) [1] "2021-10-25" "2021-10-20" "2021-10-23" "2021-10-15" "2021-10-26" "2021-10-24" "2021-10-30" [8] "2021-10-28" "2021-10-29" "2021-10-22" |
Dateクラスの演算
Dateクラスの演算を紹介します。Dateクラスに差の演算「-」を適用し日付の差を計算することができます。何日後であるかを計算するときに重宝します。
昨日の日付yeseterdayと今日の日付todayの差は以下のように計算できます。
1 2 3 4 5 6 7 8 9 | > #Dateクラスの演算 > yesterday <- today - 1 #一日前 > diffDays <- today - yesterday #日付の差 > diffDays <- difftime(today, yesterday, units = "days") #単位: 時 > diffSecs <- difftime(today, yesterday, units = "sec") #単位: 秒 > as.numeric(diffDays) [1] 1 > as.numeric(diffSecs) [1] 86400 |
シリアル値から日付への変換
最後に、シリアル値から日付に戻す例を紹介します。
関数as.Dateの引数のoriginをシリアル値に対応する基準日に設定することで、元の日付を取得することができます。
1 2 3 4 5 6 | #シリアル値からの日付への変換 > serials <- seq(365, 730) > head(as.Date(serials, origin = "1970-01-01")) #1970年1月1日基準 [1] "1971-01-01" "1971-01-02" "1971-01-03" "1971-01-04" "1971-01-05" "1971-01-06" > head(as.Date(serials, origin = "1900-01-01")) #1900年1月1日基準 [1] "1901-01-01" "1901-01-02" "1901-01-03" "1901-01-04" "1901-01-05" "1901-01-06" |
時間・POSIXct, POSIXltクラス
続いて、POSIXct及びPOSIXltPOSIXct及びPOSIXltクラスについてみていきます。
POSIXctとPOSIXltクラスは時間に関するクラスであり、前述したDateクラスに時・分・秒などのより細かいオブジェクトが追加されたクラスとなります。
POSIXct及びPOSIXlt基本的にDateクラスと使い方はおんなじで、Dateクラスの操作で用いたほとんどの関数がそのまま適用できます。
シリアル値からの変換
まず、シリアル値から時間に変換する方法を紹介します。POSIXクラスの場合、origin(基準時間)からの秒数がシリアル値となります。
1 2 3 4 5 6 7 8 | > #POSIXctクラス > options(digits = 11) > z <- 1636363849.6 #2021-11-08 18:30:49 JSTのシリアル値 > as.POSIXct(z, origin = "1960-01-01") [1] "2011-11-08 18:30:49 JST" > as.POSIXct(z, origin = "1960-01-01", tz = "UTC") #UTC基準 [1] "2011-11-08 09:30:49 UTC" > options(digits = 7) |
optionsでdigitsを11に変更しているのは、デフォルト(digits = 7)だと1636363849.6の小数点以下が丸められてしまうためです。
年月日時分秒の抽出
POSIXクラスから年月日時分秒を抽出するには、POSIXltクラスを用います。POSIXltクラスはPOSIXctとは違い、年月日時分秒などのオブジェクトから成るリストであり、以下のように年月日時分秒を抽出することが可能です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | > #POSIXltクラス > #現在の時刻 > now <- Sys.time() > str(now) POSIXct[1:1], format: "2021-12-12 15:22:33" > nowlt <- as.POSIXlt(now, tz = "UTC") #UTC基準 > #秒 分 時,... などの抽出 > months(now) #月 [1] "12月" > weekdays(now) #曜日 [1] "日曜日" > list_nowlt <- unclass(nowlt) > list_nowlt$sec #秒 [1] 33.91863 > list_nowlt$min #分 [1] 22 > list_nowlt$hour #時 [1] 6 > list_nowlt$mday #日 [1] 12 > list_nowlt$mon #基準日からの月数 [1] 11 > list_nowlt$year #基準日からの年数 [1] 121 > list_nowlt$wday #一週間のうち何日目か [1] 0 > list_nowlt$yday #基準日の日付からの日数 [1] 345 |
フォーマットの変換
POSIXクラスのフォーマットの変換はDateと同様に、format.POSIXを用いることでできます。
1 2 3 4 5 6 | > #formatの変換 > lct <- Sys.getlocale("LC_TIME") > Sys.setlocale("LC_TIME", "C") [1] "C" > format(now, "%b %d %y, %p %I:%M:%S %Z") [1] "Dec 12 21, PM 03:22:33 JST" |
Dateクラスと同様に、formatを指定してすることで任意の時間を表す文字列をPOSIXクラスに変換することができます。
1 2 3 4 5 | > now_jp <- "2021年11月8日 9時5分52秒" > as.POSIXct(now_jp, format = "%Y年%m月%d日 %H時%m分%OS秒") [1] "2021-05-08 09:00:52 JST" > as.POSIXlt(now_jp, format = "%Y年%m月%d日 %H時%m分%OS秒") [1] "2021-05-08 09:00:52 JST" |
POSIXクラスのフォーマットで用いる記号は以下の通りです。
%a | 曜日(省略) | %A | 曜日 |
%b | 月(文字列 省略) | %B | 月(文字列) |
%c | ローカルの日付と時間 | %d | 日付 |
%H | 時(24時間表記) | %I | 時(12時間表記) |
%j | 1年で何日目か | %m | 月(数字) |
%M | 分 | %p | ローカルのam, pm |
%S | 秒 | %U | 1年で何週目か(日曜から) |
%w | 曜日(数字、日曜から) | %W | 1年で何週目か(月曜から) |
%x | ローカルの日付 | %X | ローカルの時間 |
%y | 年(2桁) | %Y | 年(4桁) |
%z | GMTからのずれ | %Z | タイムゾーン |
POSIXクラスの演算
Dateクラスと同様にPOSIXクラスは差の演算を行うことが可能です。次のようにして時間の差を計算できます。
1 2 3 4 5 6 7 8 9 | > #POSIXltクラスの演算 > yesterday <- now - 24 * 60 * 60 #一日前 > diffDays <- now - yesterday #時間の差 > diffDays <- difftime(now, yesterday, units = "days") #単位: 時 > diffSecs <- difftime(now, yesterday, units = "sec") #単位: 秒 > as.numeric(diffDays) [1] 1 > as.numeric(diffSecs) [1] 86400 |
時間の生成
seq.POSIXで時間のシークエンスを生成することができます。引数byで1秒ごと、1分ごと、1時間ごとなど指定することができます。以下、実行例です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | > #時間の生成 > timeSeqBySec <- seq(from = yesterday, to = now, by = "sec") #1秒ごと > timeSeqByMin <-seq(from = yesterday, to = now, by = "min") #1分ごと > timeSeqByHour <-seq(from = yesterday, to = now, by = "hour") #1時間ごと > head(timeSeqBySec) [1] "2021-12-11 15:22:33 JST" "2021-12-11 15:22:34 JST" [3] "2021-12-11 15:22:35 JST" "2021-12-11 15:22:36 JST" [5] "2021-12-11 15:22:37 JST" "2021-12-11 15:22:38 JST" > head(timeSeqByMin) [1] "2021-12-11 15:22:33 JST" "2021-12-11 15:23:33 JST" [3] "2021-12-11 15:24:33 JST" "2021-12-11 15:25:33 JST" [5] "2021-12-11 15:26:33 JST" "2021-12-11 15:27:33 JST" > head(timeSeqByHour) [1] "2021-12-11 15:22:33 JST" "2021-12-11 16:22:33 JST" [3] "2021-12-11 17:22:33 JST" "2021-12-11 18:22:33 JST" [5] "2021-12-11 19:22:33 JST" "2021-12-11 20:22:33 JST" |
ランダムな時間を生成したいときは、関数sampleを用います。時間を含むベクトルをsampleに適用することで、ランダムに時間を取得することができます。
1 2 3 4 5 6 | > sample(timeSeqBySec, 10) [1] "2021-12-11 22:18:11 JST" "2021-12-12 15:18:51 JST" [3] "2021-12-11 22:34:43 JST" "2021-12-12 03:12:05 JST" [5] "2021-12-11 18:26:08 JST" "2021-12-12 00:11:28 JST" [7] "2021-12-12 09:20:44 JST" "2021-12-12 11:40:22 JST" [9] "2021-12-11 16:24:40 JST" "2021-12-11 22:11:57 JST" |
まとめ
DateクラスとPOSIXクラスの基本的な扱い方をまとめました。
文字列や数値(シリアル値)からDateやPOSIXクラスに変換することで、時間を表すオブジェクトの操作が簡単になります。