ア | イ | ウ | エ | オ |
カ | キ | ク | ケ | コ |
サ | シ | ス | セ | ソ |
タ | チ | ツ | テ | ト |
ナ | ニ | ヌ | ネ | ノ |
ハ | ヒ | フ | ヘ | ホ |
マ | ミ | ム | メ | モ |
ヤ | ユ | ヨ | ||
ラ | リ | ル | レ | ロ |
ワ | ヰ | ヴ | ヱ | ヲ |
ン |
A | B | C | D | E |
F | G | H | I | J |
K | L | M | N | O |
P | Q | R | S | T |
U | V | W | X | Y |
Z | 数字 | 記号 |
ANSI CやC++で時刻を表わす型。一般に、The Epochからの経過秒数で表現する(ただし、閏秒は数えない)。
#include <time.h>
定義は後述。
_tで終わる型は大抵はシステムデータ型で、必ずどこかでtypedefされている。元がどのような型であるかは、実装に委ねられている。
従来の実装では32ビット符号付き整数型(signed long int)だが、これは2038年問題を起こす。
32ビットのままでも無符号(unsigned long int)にすれば2106(令和88)年2月7日まで簡単に問題回避が可能だが、Cの日時処理の関数mktime()関数などはエラー時に(time_t)(-1)を返すという仕様があったため、64ビット化しsigned long longを採用することとなった。
このように、signed longではなくtime_tとしていたのは、サイズが変わった時にも対応できるようにした保険の一つだった。
ちなみに、POSIX(IEEE Std 1003.1-2004)仕様では、time_tは整数でも浮動小数点数でも良いとされている。しかしdoubleやlong doubleでは秒単位が正確に表現できない可能性が高く、浮動小数点数で実装しているシステムは現時点では確認できていない。
各ビットごとの最大日時は次の通り。
(中略)
Ubuntu 10.04のgcc 4.4.3とFreeBSDのclang/LLVMで確認したところ、正しいかどうかは不明だがフルビットでは55ビット(0x7fffffffffffff)までは一応動作した。
しかしそれ以上は想定外の問題として、struct tm内のint tm_yearがオーバーフローしてマイナスになってしまい、正常動作しなくなるもよう。要するに、年が31ビットに収まらないといけないということである。
したがって、2147485548/12/31 23:59:59までしか扱えないということになる。このときのtime_tは、0xf0c29d868bfd7fである。つまり21億4748万5548年問題があることになる。
なお、オーバーフロー時、gcc 4.4.3はデタラメな結果を返すが、clang/LLVMは1900/01/00 00:00:00を返す。つまりstruct tmの中をゼロクリアして返却する。
Windows用のC/C++コンパイラーであるVisual C++ 2010(Microsoft C/C++ Version 16)の場合、gmtime()関数で扱えるtime_t値の上限は、0x7934126cfだった。
これは、3001/1/1 20:59:59(UTC)に対応する。つまり、3001年問題が存在することになる。
UNIX愛好家界隈には、time_tパーティ(time_t parties)と称される祝賀会が存在するらしい。
キリ番ゲットのノリで、キリの良い数字になったときに、それを祝うというものであるとされる。
基本的には10進数でキリの良い数字を喜ぶらしく、16進数のキリの良い数字を喜ぶのは一部のグループだけであるらしい。
以下は今後起こりうるもの
Microsoft Visual C++ 2005/2008環境でも同様であるが、若干定義が異なる。
Win32環境でも__int64は利用可能で、もってtime_tは64ビット化されている。
time.hなど
typedef __time_t time_t;
stddef.h → sys/_types.h → machine/_types.h と間接的に呼ばれた /usr/include/machine/_types.h で、次のように定義される。
typedef int __int32_t;
typedef long __int64_t;
(32ビットFreeBSDの場合)
typedef __int32_t __time_t;
(64ビットFreeBSDの場合)
typedef __int64_t __time_t;
FreeBSDでは、間接的にintまたはlongで定義される。もって64ビット版ではtime_tは64ビット化されている。
Linuxカーネルでは、次のように定義される。
include/linux/types.h
typedef __kernel_time_t time_t;
__kernel_size_tの定義は環境ごとに様々であるが、代表的な環境(x86とARM)では次のようになっている。
x86の32ビットの場合、arch/x86/include/asm/posix_types_32.h で定義される。
typedef long __kernel_time_t;
x86の64ビットの場合、arch/x86/include/asm/posix_types_64.h で定義される。
typedef long __kernel_time_t;
ARMの32ビットの場合、arch/arm/include/asm/posix_types.h で定義される。
typedef long __kernel_time_t;
概ね、32ビット環境/64ビット環境問わずlongで間接的に定義されるようになっている。もってtime_tは64ビット環境において64ビット化されている。
time.h → bits/time.h → bits/types.h と間接的に呼ばれた /usr/include/bits/types.h で、次のように定義される。
# define __STD_TYPE __extension__ typedef (32ビットの場合)
# define __STD_TYPE typedef (64ビットの場合)
__STD_TYPE __TIME_T_TYPE __time_t;
/usr/include/bits/typesizes.h
#define __TIME_T_TYPE __SLONGWORD_TYPE
/usr/include/bits/types.h
#define __SLONGWORD_TYPE long int
LINUXでは、32ビット/64ビット問わず、間接的にlongで定義される。もってtime_tは64ビット環境において64ビット化されている。
Javaは、Cのtime_t互換の仕様は導入せず、独自のjava.util.Dateクラスを用いて日時を管理する。
従って2038年問題など、Cに存在する問題は生じない。
現時点では処理できる実装はないが、符号付き64ビットのtime_tでは、1ビットが符号となるため有効63ビットで、0x7fffffffffffffffまでを扱うことができる。
つまり64ビットtime_tは、1970年1月1日00:00:00(UTC)+0x7fffffffffffffff秒までの時刻表現が保証される。
最大値となる0x7fffffffffffffffの場合、閏年などの計算方法が今と変わらないという前提では、西暦2922億7702万6596年12月4日 15:30:07(UTC)まで表現できると計算できる。つまり、2922億7702万6596年問題が生じることが分かる。もっとも、現在、太陽の主系列星としての寿命は109億年とされ、太陽は寿命半ばの約46億歳と考えられていることから、この問題が生じる頃には既に地球はないか、仮にあったとしても人類が地球上に存在していない可能性が高い。
実際には、struct tmの仕様上の制限から、その全ての時刻を扱うことはできないが、少なくとも21億4748万3647年までは扱うことが可能である。
つまり、64ビット化は、単に問題を21億年あるいは2900億年ほど先送りしたに過ぎず、後々問題が発生する可能性があり、これを「2922億年問題」という。なお、これは宇宙の年齢(約137億年)の21倍程度という年月に相当する。
コメントなどを投稿するフォームは、日本語対応時のみ表示されます