平常運転

アニソンが好き

過去記事とかは記事一覧で見れます

Perl6 の DBDish::mysql でクライアント側と異なる time_zone に接続すると insert/update した際の DateTime のタイムゾーンがずれる

最近 Perl6 を勉強してる。当然仕事で使うわけではなくて、単純な趣味です。

DBDish::mysql::StatementHandle では、 INSERTUPDATE のために DateTime 型を文字列に展開する時に、DateTime.localで実行環境のローカルのタイムゾーンに展開してから更新する。

			when DateTime {
			    # mysql knows nothing of timezones, all assumed local-time
			    # but in Windows the parser chokes with the offset, so
			    # we should remove it. See _row for the reverse
			    .local.Str.subst(/ <[\-\+]>\d\d ':' \d\d /,'').encode;
			}
https://github.com/perl6/DBIish/blob/1bb0d44/lib/DBDish/mysql/StatementHandle.pm6#L104-L109

Returns a DateTime object for the same time, but in the local time zone ($*TZ).

https://doc.perl6.org/type/DateTime#method_local

いっぽうで、 mysql が接続する際のタイムゾーンはクライアントが明示しない限りサーバ側の @@GLOBAL.time_zone の値が使われる。

Per-connection time zones. Each client that connects has its own time zone setting, given by the session time_zone variable. Initially, the session variable takes its value from the global time_zone variable, but the client can change its own time zone with this statement:

https://dev.mysql.com/doc/refman/5.6/en/time-zone-support.html

なので、以下のどちらかの状況下では DateTime 型を意図したように mysql とやりとりすることができる。

しかしながら、前者はサーバと実行環境のタイムゾーンが一致していることを祈るだけになるので現実的ではない。また、後者については環境を問わずに整合性が保てるものの、国際対応したWebアプリケーションなどでは「アプリケーション内部ではUTCで取り扱い、表示部分で明示的にタイムゾーンを指定する」という方針で実装したくなることがあるので、その方針からするとややしっくりこないような気もする。
まあ、この辺のタイムゾーンDBDishmysqlclient の中に閉じた話題であって、それより外の層には漏出しないので、とりあえずはSET time_zoneで実行環境のタイムゾーンに揃えて *1 整合性を保つに留めた方がよいのかなあ、と思っている。

Perl6 素人なのでほんとはこうしたほうがいい、みたいな話あったら是非教えてください。

*1:一方で、$*TZ の値で取れる offset 秒から mysql timezone として指定可能な +09:00 みたいな形式に手動に変換するのもなかなか渋いなァと思っている。。。