ステップ1:time_t
基準点として任意のものを選択します(現在の時刻は問題なく機能します)。それを呼び出しますt0
。
ステップ2:呼び出しgmtime
てt0
、結果とエポックの差を分解したstruct tm
形式で計算します。
ステップ3:呼び出しlocaltime
てt0
、ステップ2の内訳の差を結果のに適用しますstruct tm
。次に、それを呼び出しmktime
て、を取り戻しますtime_t
。
time_t
結果は、エポックを表すものになるはずです。
これを実装する最初の試みでは、たとえば夏時間が追加または中止された地域や、あるゾーンの観測から別のゾーンの観測に切り替わった地域など、現地時間のオフセットが時間の経過とともに一定でない場合に問題が発生しました。struct tm
これは、タイムゾーン情報の基になっているデータが変更されたためと思われます。これが元の実装とその問題です。
time_t get_epoch(time_t t0)
{
struct tm gmt = *gmtime(&t0);
struct tm tmp = *localtime(&t0);
tmp.tm_sec -= gmt.tm_sec;
tmp.tm_min -= gmt.tm_min;
tmp.tm_hour -= gmt.tm_hour;
tmp.tm_mday -= gmt.tm_mday-1;
tmp.tm_mon -= gmt.tm_mon;
tmp.tm_year -= gmt.tm_year-70;
return mktime(&tmp);
}
改良版では、POSIX式(http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_15)を使用してposix_time
、特定のエポックからの秒数を計算する関数が追加されています。struct tm
必要に応じて、1970年より前の年などを処理します。
time_t get_epoch(time_t t0)
{
struct tm gmt = *gmtime(&t0);
struct tm tmp = *localtime(&t0);
long long offset = posix_time(&gmt);
while (offset > INT_MAX) {
offset -= INT_MAX;
tmp.tm_sec -= INT_MAX;
mktime(&tmp);
}
while (offset < -INT_MAX+61) {
offset -= -INT_MAX+61;
tmp.tm_sec -= -INT_MAX+61;
mktime(&tmp);
}
tmp.tm_sec -= offset;
return mktime(&tmp);
}
C89との互換性のためにlong long
は、ドロップする必要があり、必要な呼び出しの数はmktime
劇的に増加します。単一の値として計算することはできませんが、 1年に複数回offset
呼び出すにはループが必要になります。mktime