天泣記

2012-10-23 (Tue)

#1

折にふれて、さまざまな時刻表現の精度と範囲 (ファイルシステム、データベース、ファイルフォーマット、プロトコル、API など) を調べている。

以下、閏秒はすべて無視 (少なくとも未来の閏秒は決まっていないので確実なことをいえないため)。また、過去についてはグレゴリオ歴を延長したものと仮定する。

SQLite:
  ISO-8601 な文字列で表現するので範囲に制限なし。小数点以下も10進任意長。
  http://www.sqlite.org/lang_datefunc.html

EXIF 2.1: DateTime, SubsecTime
  0000-01-01 00:00:00 以上 10000-01-01 00:00:00 未満。小数点以下は10進任意長。時差の扱いは不明
  http://www.exif.org/Exif2-1.PDF

pax (POSIX):
  1970-01-01 00:00:00 UTC からの秒数を 任意長の10進数で表現して範囲制限なし。小数点以下も10進任意長。
  http://pubs.opengroup.org/onlinepubs/007904875/utilities/pax.html#tag_04_100_13_05

NTPv4 の NTP Date Format:
  1900-01-01 00:00:00 UTC からの秒数。符号付整数部64bit, 小数部64bit
  -292277022727-01-26 08:29:52 UTC 以上 292277026526-12-05 15:30:08 UTC 未満。2**(-64)秒単位 (約0.05e-18秒単位)。

FreeBSD 5.0 以降の struct bintime:
  範囲は time_t に依存。2**(-64)秒単位 (約0.05e-18秒単位)。
  struct bintime {
          time_t  sec;
          uint64_t frac;
  };
  void bintime(struct bintime *bt);
  void getbintime(struct bintime *bt);

DB2 の TIMESTAMP (DB2 9.7以降):
  0001-01-01 00:00:00.000000000000 以上 9999-12-31 23:59:59.999999999999 以下。1ps 単位。(タイムゾーン情報はない)
  (小数点以下の桁数を指定でき、12が最大。TIMESTAMP(12) とした場合)
  http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.sql.ref.doc/doc/r0008474.html
  http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.wn.doc/doc/c0053707.html

NFSv4 (RFC 3010):
  -292277022657-01-27 08:29:52.000000000 UTC 以上 292277026596-12-04 15:30:07.999999999 UTC 以下。1ns 単位
  struct nfstime4 {
          int64_t seconds;
          uint32_t nseconds;
  }

NFSv3 (RFC 1813):
  1970-01-01 00:00:00.000000000 UTC 以上 2106-02-07 06:28:15.999999999 UTC 以下。1ns 単位
  struct nfstime3 {
     uint32   seconds;
     uint32   nseconds;
  };

ext4:
  1901-12-13 20:45:52.000000000 UTC 以上 2514-05-30 01:53:03.999999999 UTC 以下。1ns 単位
  struct ext4_inode {
    ...
    __le32  i_atime;        /* Access time */
    __le32  i_ctime;        /* Inode Change time */
    __le32  i_mtime;        /* Modification time */
    ...
    __le32  i_ctime_extra;  /* extra Change time      (nsec << 2 | epoch) */
    __le32  i_mtime_extra;  /* extra Modification time(nsec << 2 | epoch) */
    __le32  i_atime_extra;  /* extra Access time      (nsec << 2 | epoch) */
    __le32  i_crtime;       /* File Creation time */
    __le32  i_crtime_extra; /* extra FileCreationtime (nsec << 2 | epoch) */
    ...
  }
  linux-2.6.33/fs/ext4/ext4.h
  http://www.kazamiya.net/ext4_inode
  http://computer-forensics.sans.org/blog/2011/03/14/digital-forensics-understanding-ext4-part-2-timestamps

xfs: ナノ秒
Reiser4: ナノ秒
JFS: ナノ秒
Btrfs: ナノ秒
zfs: ナノ秒

SUSv4 2008:
  int utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags)
  int futimens(int fd, const struct timespec times[2]);
  struct stat の st_atim, st_mtim, st_ctim フィールドが struct timespec として定義。
  timespec なので 1ns 単位。範囲は time_t に依存。

SUSv2 1997:
  int clock_gettime(clockid_t clock_id, struct timespec *tp);
  timespec なので 1ns 単位。範囲は time_t に依存。

4.4BSD-Alpha 1992:
  struct stat の st_atimespec, st_mtimespec, st_ctimespec フィールドが struct timespec として定義。
  timespec なので 1ns 単位。範囲は time_t に依存。
  Net2 1991 では定義されていない。

NTFS:
  1601-01-01 00:00:00.0000000 UTC 以上 60056-05-28T05:36:10.9551616 UTC 以下。100ns 単位
  (1601年から 100ns 単位で 64bit)

NFSv2 (RFC 1094):
  1970-01-01 00:00:00.000000 UTC 以上 2106-02-07 06:28:15.999999 UTC 以下。1μs 単位
  struct timeval {
      unsigned int seconds;
      unsigned int useconds;
  };

UDF (DVD などのフォーマット):
  -32768-01-01 00:00:00.000 以上 32767-12-31 23:59:59.999 以下。1μs 単位。1分単位の時差
  http://www.osta.org/specs/pdf/udf260.pdf
  struct timestamp { /* ECMA 167 1/7.3 */
    Uint16 TypeAndTimezone;
    Int16 Year;
    Uint8 Month;
    Uint8 Day;
    Uint8 Hour;
    Uint8 Minute;
    Uint8 Second;
    Uint8 Centiseconds;
    Uint8 HundredsofMicroseconds;
    Uint8 Microseconds;
  }

SUSv2 1997 (もっと古くからあるとは思う):
  int utimes(const char *filename, const struct timeval times[2])       4.2BSD (1983) に存在。Version 7 (1979) にはない。
  int gettimeofday(struct timeval *tp, void *tzp);                      4.2BSD (1983) に存在。Version 7 (1979) にはない。
  1μs 単位。範囲は time_t に依存。

SQL Server の datetime (1/300秒: 3.33ms)
  1753-01-01 00:00:00.000 以上 9999-12-31 23:59:59.997 以下。1ms の桁は 0, 3, 7 のいずれかに丸められる。時差の情報はない。
  http://msdn.microsoft.com/ja-jp/library/ms187819.aspx
  (別の型として datetime2 および datetimeoffset があり、そっちの精度は 100ns)

exFAT: 10ミリ秒(作成、修正)、2秒(アクセス)
  1980-01-01 00:00:00.00 以上 2107-12-31 23:59:59.99 以下。10ms 単位。(UTC もしくは ローカルタイム)
  http://shullich.blogspot.com/2009/12/time-stamp-format.html

ISO 9660 (ECMA-119):
  0001-01-01 00:00:00.00 以上 9999-12-31 23:59:59.99 以下。10ms 単位。15分単位の時差
  http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-119.pdf

ext3:
  1901-12-13 20:45:52 UTC 以上 2038-01-19 03:14:07 UTC 以下。1s 単位

ReiserFS: 1秒

HFS Plus (Mac, Mac OS 8.1 以降):
  1904-01-01 00:00:00 UTC 以上 2040-02-06 06:28:16 UTC 以下。1s 単位

HFS (Mac, System 3.1以降):
  1904-01-01 00:00:00 UTC 以上 2040-02-06 06:28:16 UTC 以下。1s 単位

Macintosh File System:
  1904-01-01 00:00:00 UTC 以上 2040-02-06 06:28:16 UTC 以下。1s 単位
  「初期の Macintosh コンピュータの設計が理由で、1904 年 1 月 1 日より前の日付はサポートされていません。
  この設計は、1900 年がうるう年ではなかったという事実に関連する問題の発生を避けることを目的としたものでした。」
  http://support.microsoft.com/kb/180162/ja

gzip (RFC 1952):
  1970-01-01 00:00:00 UTC から 1s 単位で 32bit 整数。符号の扱いは不明。
  値が 0 の場合は time stamp がないことを示すので、1970-01-01 00:00:00 UTC は表現できない。
  符号有なら 1901-12-13 20:45:52 UTC 以上 2038-01-19 03:14:07 UTC 以下。ただし 1970-01-01 00:00:00 UTC を除く。
  符号無なら 1970-01-01 00:00:01 UTC 以上 2106-02-07 06:28:15 UTC 以下。

png (RFC 2083): tIME Image last-modification time
  0000-01-01 00:00:00 UTC 以上 65535-12-31 23:59:59 UTC 以下。1s 単位

TIFF 6.0: DateTime header
  0000-01-01 00:00:00 以上 9999-12-31 23:59:59 以下。1s 単位。時差の扱いは不明
  http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf
  なお、TIFF/EP で TimeZoneOffset が定義され、それにより -12 から 11 まで 1h 単位で UTC との時差を指定できる。

ustar (POSIX):
  1970-01-01 00:00:00 UTC から 1s 単位で 8進数12桁。符号の扱いは不明。
  符号有なら 1697-10-17 11:03:28 UTC 以上 2242-03-16 12:56:31 UTC 以下。
  符号無なら 1970-01-01 00:00:00 UTC 以上 4147-08-20 07:32:15 UTC 以下。

Internet Mail (RFC 5322): Date ヘッダ
  0000-01-01 00:00:00 から 1s 単位で制限なし。時差は 1分単位

TLS 1.1 の struct Random 内の uint32 gmt_unix_time:
  1970-01-01 00:00:00 UTC 以上 2106-02-07 06:28:15 UTC 以下。1s 単位
  乱数の一部としての扱いで、時刻として扱われるものではないが。

FAT:
  1980-01-01 00:00:00 以上 2107-12-31 23:59:58 以下。2s 単位。(ローカルタイム)
  Date で 2byte, Time で 2byte, 計4byte で表現
  http://shullich.blogspot.com/2009/12/time-stamp-format.html

ZIP: FAT と同じ形式
  1980-01-01 00:00:00 以上 2107-12-31 23:59:58 以下。2s 単位。(ローカルタイム)
  http://www.pkware.com/documents/casestudies/APPNOTE.TXT

MySQL:
  DATETIME: 1000-01-01 00:00:00 以上 9999-12-31 23:59:59 以下。1s 単位
  TIMESTAMP (MAXDB モード): DATETIME と同じ
  TIMESTAMP (非MAXDB モードあるいはMySQL 4.1 より前): 1970 年の始まりから 2037 年の一定の時点までを範囲とし、時間分解能は 1 秒
  http://dev.mysql.com/doc/refman/4.1/ja/datetime.html
  MySQL 5.6 からは、1s未満も扱えるらしい http://nippondanji.blogspot.jp/2012/10/mysql-56.html

Internet X.509 Profile (RFC 5280):
  UTCTime: 1950-01-01 00:00:00 UTC 以上 2049-12-31 23:59:59 UTC 以下。1秒単位
  GeneralizedTime: 0000-01-01 00:00:00 UTC 以上 9999-12-31 23:59:59 UTC 以下。1秒単位

[latest]


田中哲