Unix時間とWindowsのFILETIMEを変換する
はじめに
Unix系では1970-01-01 00:00:00 UTC(Unixエポック)からの経過秒数で表されるUnix時間が主に使われていますが、Windowsでは1601-01-01 00:00:00 UTC(NTタイムエポック)からの100ナノ秒単位の経過秒数で表されるFILETIME
が使われています。
今回はこの2つのタイムスタンプの変換方法についてまとめたいと思います。
前提条件
-
time_t
などで表される秒単位のUnix時間のデータ型は64ビット符号付き整数型とします。 -
timespec
などで表されるナノ秒単位のUnix時間のデータ型は128ビット符号付き整数型とします。 -
FILETIME
のデータ型は64ビット符号なし整数型とします。 - 整数同士の割り算の結果は小数点以下を切り捨てた整数値とします。
Unix時間 to FILETIME
Unix時間からFILETIME
への変換では、Unix時間がNTタイムエポックからFILETIME
の最大値の+60056-05-28 05:36:10.955161500 UTCに収まらない可能性があるので、範囲内かを確認する処理が必要になります。
秒単位
秒単位のUnix時間をFILETIME
に変換するには以下のような処理を行います。
- Unix時間が1,833,029,933,770(
FILETIME
の最大値)以下であることを確認する。 - Unix時間にUnixエポックとNTタイムエポックの差の秒数の11,644,473,600を足す。
- 2の結果が正の数であることを確認する。
- 2の結果に10,000,000を掛けて100ナノ秒単位にする。
ナノ秒単位
ナノ秒単位のUnix時間をFILETIME
に変換するには以下のような処理を行います。
- Unix時間が1,833,029,933,770,955,161,500(
FILETIME
の最大値)以下であることを確認する。 - Unix時間にUnixエポックとNTタイムエポックの差のナノ秒数の11,644,473,600,000,000,000を足す。
- 2の結果が正の数であることを確認する。
- 2の結果を100で割って100ナノ秒単位にする。
FILETIME to Unix時間
64ビット符号付き整数型のUnix時間ではおよそ紀元前3000億年からおよそ3000億年の範囲を表すことができるので、FILETIME
からUnix時間への変換は常に成功します。
ナノ秒単位のUnix時間の場合もこの変換は128ビット符号付き整数型に収まるので同様です。
秒単位
FILETIME
を秒単位のUnix時間に変換するには以下のような処理を行います。
-
FILETIME
を10,000,000で割って秒単位にする。 - 1の結果からUnixエポックとNTタイムエポックの差の秒数の11,644,473,600を引く。
ナノ秒単位
FILETIME
をナノ秒単位のUnix時間に変換するには以下のような処理を行います。
-
FILETIME
に100を掛けてナノ秒単位にする。 - 1の結果からUnixエポックとNTタイムエポックの差のナノ秒数の11,644,473,600,000,000,000を引く。
まとめ
Unix時間とFILETIME
の変換方法についてまとめました。
今回は64ビット符号付き整数型の秒単位のUnix時間と128ビット符号付き整数型のナノ秒単位のUnix時間を扱いましたが、2038年問題で知られている古い32ビット符号付き整数型の秒単位のUnix時間の場合はFILETIME
からUnix時間への変換が失敗する可能性がある[1]など、データ型のサイズによって変換が常に成功するか失敗する可能性があるかが変化することに注意してください。
-
FILETIME
が1901-12-13 20:45:52 UTCから2038-01-19 03:14:07 UTCに収まらない日時を表している場合に失敗します。 ↩︎
Discussion