parse_date_time()
でexact=TRUE
を指定したときとしないときの挙動で悩んだのでメモ。
追記(2020/11/3): macはまた違う挙動らしいです(参考)
AM/PMの区別を表す時刻フォーマット文字列はp
。?parse_date_time
のヘルプにはこう書かれています。
p
AM/PM indicator in the locale. Normally used in conjunction withI
and not withH
. But the lubridate C parser acceptsH
format as long as hour is not greater than 12. C parser understands only English locale AM/PM indicator.
I
じゃなくてH
でもいける、という話はいったん置いといて、とりあえず標準的なI
とp
でパースしてみましょう。うまくいきます。
x <- "2020-11-03 10:23:18 PM" parse_date_time(x, "YmdIMSp") #> [1] "2020-11-03 22:23:18 UTC"
一方、exact = TRUE
をつけると速いという知見(参考: R で文字列を POSIX time に変換するには lubridate::parse_date_time2() がやっぱりちょっぱや - Qiita)があるわけですが、
これをつけるとなぜかうまくいきません...
parse_date_time(x, "%Y-%m-%d %I:%M:%S %p", exact = TRUE) #> Warning: 1 failed to parse. #> [1] NA
なんでやねん、と思って試しにbase Rでやってみると、これも失敗しました。ということはどうやらlubridateが悪いわけではなさそうです。
strptime(x, "%Y-%m-%d %I:%M:%S %p") #> [1] NA
しばらく悩んだあと、同じフォーマットで時刻を文字列に変換してみるとどうなるかな?とやってみて謎が解けました。
strftime(as.POSIXct("2020-11-03 23:23:18"), "%Y-%m-%d %I:%M:%S %p") #> [1] "2020-11-03 11:23:18 午後"
おわかりいただけただろうか。
午後...
なるほどなーー?、とおもってヘルプを見返すと、AM/PM indicatorについてはlubridate 独自のフォーマットがありました。
Op
Matches AM/PM English indicator.
これを使ってみるとうまくいきました。
parse_date_time(x, "%Y-%m-%d %I:%M:%S %Op", exact = TRUE) #> [1] "2020-11-03 22:23:18 UTC"
ちなみに、ではPMじゃなくて午後になってる文字列を渡すと?と試してみると、これはp
でうまくいきました。
x_ja <- "2020-11-03 10:23:18 午後" parse_date_time(x_ja, "YmdIMSp") #> [1] "2020-11-03 22:23:18 UTC" parse_date_time(x_ja, "%Y-%m-%d %I:%M:%S %p", exact = TRUE) #> [1] "2020-11-03 22:23:18 UTC"
よくわからないのはEnglish indicatorなはずの Op
でもマッチする点ですが...。まあマッチされて困ることは少なそうなので決断的に見なかったことに。
parse_date_time(x_ja, "%Y-%m-%d %I:%M:%S %Op", exact = TRUE) #> [1] "2020-11-03 10:23:18 UTC"
感想
exact = TRUE
つけないときはどっちもいい感じにパースしてくれて偉いなと思いました(小並