FIELD NOTES: 書を持って街へ出よう

合同会社フィールドワークス プログラマ兼代表のブログ

OCamlでのタイムゾーンの取得方法

以前作成した「日付/時刻→文字列変換ライブラリ」にタイムゾーン(というかUTCとの差)を出力する機能を追加しようと,OCamlのライブラリを探したのですが,タイムゾーンをダイレクトに取得する関数が見つからず,ちょっと手間取りました。

調べたこと

Unix系のOSでは,gettimeofday()というシステムコールを呼ぶと,第1引数に1970年1月1日からの経過時刻がマイクロ秒単位で,第2引数にタイムゾーンを取得できます。OCamlUnixモジュールで対応するgettimeofdayのマニュアルを参照してみると,

val gettimeofday : unit -> float
Unix.time と同じですが、分解能が 1 秒より上です。

となっていて,第2引数のタイムゾーンの情報が欠落しています。

この理由を推察するに,Linuxではgettimeofday()の第2引数の使用が「時代遅れ (obsolete)」の扱いとなっていて,「通常は NULL に指定すべきである」となっていることが関係していると思われます。どの環境でも同じ振る舞いをするように,不確かな要素を除いたのではないでしょうか?

対策

では,どうするかですが,Unix.mktimeがローカル時刻とUTCとの差を知っていることを利用します。
ある時刻tでの経過秒をUnix.gmtimeでいったんtmレコードの形に変換してから,Unix.mktimeに渡すと,ローカル時刻換算での経過秒が求められます。時刻tはいつでも良いのですが,1970年1月1日0時0分0秒とすると計算が少しだけ簡単になり,UTCとローカル時刻との差を分単位で求める関数は以下のようになりました。

let tz_offset =
  let offset, _ = Unix.mktime (Unix.gmtime 0.) in
  -. offset