2015/7/1 にうるう秒が挿入されるということで、うるう秒の話題が盛り上がってるようなので自分も書いてみます。
Linux 上のプログラムが時刻で60秒を刻むには、うるう秒対応のタイムゾーンを使う必要があります。
通常はうるう秒を考慮していないタイムゾーンが使用されているので、60秒を含む時刻になることはありません。
60秒を含む時刻を扱うには、right/Japan
のように right/
を前につけたタイムゾーンを指定します。
前回のうるう秒は 2012/7/1 08:59:60 (JST) だったので、これで試してみます。
% TZ=Japan date --date='2012-07-01 08:59:60' date: `2012-07-01 08:59:60' は無効な日付です % TZ=right/Japan date --date='2012-07-01 08:59:60' 2012年 7月 1日 日曜日 08:59:60 JST
Ruby
うるう秒なしのタイムゾーン:
% TZ=Japan ruby -rtime -e 'p Time.at(p Time.parse("2012-07-01 08:59:59").to_i)' 1341100799 2012-07-01 08:59:59 +0900 % TZ=Japan ruby -rtime -e 'p Time.at(p Time.parse("2012-07-01 08:59:60").to_i)' 1341100800 2012-07-01 09:00:00 +0900 % TZ=Japan ruby -rtime -e 'p Time.at(p Time.parse("2012-07-01 09:00:00").to_i)' 1341100800 2012-07-01 09:00:00 +0900
08:59:60 を指定しても 09:00:00 として扱われています。
うるう秒ありのタイムゾーン:
% TZ=right/Japan ruby -rtime -e 'p Time.at(p Time.parse("2012-07-01 08:59:59").to_i)' 1341100823 2012-07-01 08:59:59 +0900 % TZ=right/Japan ruby -rtime -e 'p Time.at(p Time.parse("2012-07-01 08:59:60").to_i)' 1341100824 2012-07-01 08:59:60 +0900 % TZ=right/Japan ruby -rtime -e 'p Time.at(p Time.parse("2012-07-01 09:00:00").to_i)' 1341100825 2012-07-01 09:00:00 +0900
ちゃんと 08:59:60 を扱うことができています。
うるう秒を扱えるかどうかで時刻の内部表現(1970-01-01 00:00:00 UTC からの経過秒数)が25秒ずれていますが、これは今までに25回うるう秒が挿入されたためです。
MySQL
うるう秒なしのタイムゾーン(TZ=Japan で mysqld を起動):
mysql> select from_unixtime(1341100799), unix_timestamp('2012-07-01 08:59:59'); +---------------------------+---------------------------------------+ | from_unixtime(1341100799) | unix_timestamp('2012-07-01 08:59:59') | +---------------------------+---------------------------------------+ | 2012-07-01 08:59:59 | 1341100799 | +---------------------------+---------------------------------------+ mysql> select from_unixtime(1341100800), unix_timestamp('2012-07-01 08:59:60'); +---------------------------+---------------------------------------+ | from_unixtime(1341100800) | unix_timestamp('2012-07-01 08:59:60') | +---------------------------+---------------------------------------+ | 2012-07-01 09:00:00 | 0 | +---------------------------+---------------------------------------+ mysql> select from_unixtime(1341100800), unix_timestamp('2012-07-01 09:00:00'); +---------------------------+---------------------------------------+ | from_unixtime(1341100800) | unix_timestamp('2012-07-01 09:00:00') | +---------------------------+---------------------------------------+ | 2012-07-01 09:00:00 | 1341100800 | +---------------------------+---------------------------------------+ 1 row in set (0.00 sec)
08:59:60 はパースできずに 0 を返しています。
うるう秒ありのタイムゾーン(TZ=right/Japan で mysqld を起動):
mysql> select from_unixtime(1341100823), unix_timestamp('2012-07-01 08:59:59'); +---------------------------+---------------------------------------+ | from_unixtime(1341100823) | unix_timestamp('2012-07-01 08:59:59') | +---------------------------+---------------------------------------+ | 2012-07-01 08:59:59 | 1341100823 | +---------------------------+---------------------------------------+ mysql> select from_unixtime(1341100824), unix_timestamp('2012-07-01 08:59:60'); +---------------------------+---------------------------------------+ | from_unixtime(1341100824) | unix_timestamp('2012-07-01 08:59:60') | +---------------------------+---------------------------------------+ | 2012-07-01 08:59:59 | 0 | +---------------------------+---------------------------------------+ mysql> select from_unixtime(1341100825), unix_timestamp('2012-07-01 09:00:00'); +---------------------------+---------------------------------------+ | from_unixtime(1341100825) | unix_timestamp('2012-07-01 09:00:00') | +---------------------------+---------------------------------------+ | 2012-07-01 09:00:00 | 1341100825 | +---------------------------+---------------------------------------+
08:59:60 は 08:59:59 として扱われます。やはりパースはできません。
まとめ
- Linux の場合は特別な設定をしない限り、通常は 60秒を含む時刻を返すことはありません。
- 60秒を含む時刻をどのように扱うかはプログラム次第です。
- Ruby は 60秒を含む時刻文字列をパースできますが、MySQL はできません。
- うるう秒を扱えるタイムゾーンの場合、Ruby は 60秒を含む時刻を返すことがありますが、MySQL は 60秒になることはありません。