Linuxと書いていますが、POSIX準拠であれば大体同じはずです。
サンプルコードでは返り値チェック等はあえて記載していません。
時刻を扱う4つの構造体
Linux上で時刻を扱う際に最初に混乱するのは、時刻を扱う構造体が主に4種類存在することです。
これは歴史的な経緯もあり、そういうもんだと思っておきます。
time_t
3つの内で最も古い。The Epoch(1970年1月1日0時0分0秒UTC)からの経過秒数を表す。
したがってミリ秒以下の情報は持たない。
具体的な定義は実装依存。Ubuntu16(64bit)ではtime_t
= long int
です。
1 | /* types.h */ |
timeval
マイクロ秒まで保有することを想定した構造体。
以下のlong
の部分は、実際の環境では別名でtypedef
されていますが、実質long
です。
1 | struct timeval { |
timespec
ナノ秒まで保有することを想定。一番新しい。
1 | struct timespec { |
tm
これは上記3つとは少し性質が異なり、エポック秒を年/月/日/…へ分解した情報を保有する。
精度的には秒までのため、time_t
と組み合わせて使うことが多いです。
1 | struct tm { |
時刻を取得する関数
上記のtime_t
,timeval
,timespec
それぞれに対して、時刻を取得する関数が異なります。
順番に見ていきます。
time
関数
返り値としてtime_t
を返します。
1 |
|
gettimeofday
関数
timeval
構造体のポインタを第1引数に与えます。
第2引数は本来はタイムゾーンの情報ですが、非推奨となっておりNULL
を与えます。
1 |
|
clock_gettime
関数
使い方はgettimeofday
関数と大差ありません。
第1引数の種類で時計の性質を選択できます。詳細はmanを見てください。
1 |
|
エポック時刻を現地時刻の文字列に変換する
前置きが長くなりましたが、エポック時刻を現地時刻の文字列(2019/6/8 13:33:25.345
みたいな感じ)に変換する処理を考えます。
基本的な考え方は以下です。
- 年月日時分秒までは、
time_t
型をstrftime
関数で文字列にする変換する処理が使える - (ナノ秒まで保持する
timespec
構造体の1つめの変数tv_sec
は、単なるtime_t
型です) - ミリ秒以下はタイムゾーン等に一切影響されない要素なので、上記で求めた結果に追加表示するだけ
以下、時刻取得はtimespec
型で取得した前提で記載します(あえて古いものを使う理由は特にないので)。
現地時刻の年月日時分秒を作る
localtime_r
関数でエポック秒を、冒頭で紹介したtm
構造体に変換します。
似た名前のlocaltime
関数はスレッドセーフではないため、localtime_r
を使います。
1 |
|
年と月の値に注意します。基本的にはこれで現地時刻へ変換は達成できていますが、文字列への変換をより手軽にやってくれるstrftime
関数も使ってみます。
フォーマット指定詳細はmanを見てください。
1 | char buf[32]; |
あとはミリ秒を追加するだけ
最後にミリ秒やマイクロ秒の情報を追加してあげればよいだけです。
方法はどうにでも出来ますが、以下サンプルです。
(最後だけ、返り値チェックも真面目にやっておきます)
1 |
|
これで2019/06/08 19:41:13.712
のような結果が得られます。
今回のコードはGitHubに置いてあります。