そーだいなるらくがき帳

そーだいが自由気侭に更新します。

PHPのDatetimeクラスはナノ秒を扱えない

 表題の通りなのだけど下記のコードはerrorになる。

<?php
$RFC3339Nano_format = '2019-12-24T19:00:30.123456789+09:00';
$datetime_object = new DateTime($RFC3339Nano_format);

 実行結果はこのとおり。

$ php test.php
PHP Fatal error:  Uncaught Exception: DateTime::__construct(): Failed to parse time string (2019-12-24T19:00:30.679012412+09:00) at position 20 (6): Double date specification in /tmp/test.php  on line 3

 これはPHPのDatetimeのコンストラクタの中の処理が8桁までしかサポートしてないために発生する。 なので 2019-12-24T19:00:30.12345678+09:00 と一桁削ってやると正しく動作する。 なので8桁よりも多い桁数のデータに対応したい場合は正規表現などで桁数を削るか、microsecまでにするなど渡す側のフォーマットを変える必要がある。

 では9桁でデータが渡されるパターンはどんなケースがあるだろうか? 例えばGoの time.Time などが該当する。

 ではGoから受け取るようなケースがあるだろうか? 最近作った Songmu/horenso から実行時間を受け取る時、まさに前述のような状況になる。

soudai.hatenablog.com

ドハマリして調べたら公式ドキュメントに書いてあった

But "u" can only parse microseconds up to 6 digits, but some language (like Go) return more than 6 digits for the microseconds, e.g.: "2017-07-25T15:50:42.456430712+02:00" (when turning time.Time to JSON with json.Marshal()). Currently there is no other solution than using a separate parsing library to get correct dates.

https://www.php.net/manual/en/datetime.formats.php

 今回の件がまさに json.Marshal() 経由でデータをもらっており、そのとおりなのである。

そもそもGoの仕様ってどうなってるの?

 Twitter有識者の皆様が教えてくれた。

何桁まで返してくるかはOS依存

 なのでWSLで実行してる時は末尾2桁をGoが切り捨てるのでたまたま動く

まとめ

  • PHPで時間を使う時はmicrosecまで
  • 言語の仕様はしっかりと理解する
  • ローカルの開発環境の振る舞いをしっかりと理解する