鈴木うどんの横須賀おもしろ生活

撮った写真や思ったことや技術ネタなど。出来るだけ大きなディスプレイで見ると良いと思う。ここでの発言は個人の見解であり、所属する組織の公式見解ではありません。

言語別に範囲外の日付のフォーマットに対する挙動を試した、あるいは言語別 Repl について

以前の記事にも書いたとおり、JavaScript の場合 new Date(2014,1,32) のように、存在しない日付を指定してDateを初期化しても、よきに計らった(おせっかいな?)値を返してくれる。例えばこの例のように1月32日を指定すると、2月1日のDateオブジェクトが返ってくる。実は、存在しないような不正な入力に対しては Type Error が投げられると勝手に思い込んでいたので驚いた。

という経緯もあって、良い機会なので他のスクリプト言語で同様のことをしたときの挙動を調べることにした。この手の実験はReplを使うと便利なのでそのあたりの言及もする。対象言語は Perl, Ruby, Python, PHP あたりのよく使われているスクリプト言語を選んだ。先に結果を言ってしまうと、前者2つは日付のフォーマットチェックがあるが、他は JavaScript と同じような挙動だと分かった。具体的な挙動は以下に示す通り。

Perl

僕の知る限り Perl には標準でRepl環境が無い。とはいうものの、CPAN を用いて簡単にRepl環境を構築することが可能だ。今回は依存関係が少なくインストールの容易な Carp::Reply を利用した。他に有名で補完機能などが充実したさらに高機能なものにDevel::REPLが存在している。けれども、僕の環境では、その依存関係の多さからなのか、これまで一度もうまくインストールできたことがない…。

% perl -v

This is perl 5, version 12, subversion 4 (v5.12.4) built for darwin-thread-multi-2level

Copyright 1987-2010, Larry Wall

Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.

Complete documentation for Perl, including FAQ lists, should be found on
this system using "man perl" or "perldoc perl".  If you have access to the
Internet, point your browser at http://www.perl.org/, the Perl Home Page.

% reply
0> use Time::Local qw(timelocal);
1> timelocal(0,0,0, 32, 0, 2014)
Day '32' out of range 1..31 at reply input line 1.
2> timelocal(0,0,0, 31, 1, 2014)
Day '31' out of range 1..28 at reply input line 1.

見ての通りちゃんとフォーマットチェックが走る理想的な動作だ。もちろん、2月などの月の最終日が31日以外でもきちんとしたチェックになっている。

Ruby

結論から言えば、今回に限っての Ruby はドジっ子かわいい。Repl環境は標準搭載の irb を利用した。他に高機能なpryというReplがあるけれど、僕は使っていない。

% ruby -v
ruby 2.0.0p247 (2013-06-27 revision 41674) [universal.x86_64-darwin13]
% irb
irb(main):001:0> Time.local(2014, 1, 32)
ArgumentError: argument out of range
    from (irb):1:in `local'
    from (irb):1
    from /usr/bin/irb:12:in `<main>'
irb(main):002:0> Time.local(2014, 2, 31)
=> 2014-03-03 00:00:00 +0900

一応チェックはしているようだが、dd が 1..31 かどうかしかチェックしていないようである。ドジっ子である。

Python

PythonCLIで引数無しで起動するとデフォルトでRepl環境になる。これは嬉しい。

% python
Python 2.7.5 (default, Aug 25 2013, 00:04:04) 
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import time
>>> time.mktime([2014,1,32,0,0,0,0,0,0])
1391180400.0

特にチェックは走っていない。Rubyの挙動を見たあとだと、これはこれで割り切っていて自然な実装に思えてくる。例えば特定の日付から2ヶ月分取ってくるみたいなときに便利だ(86400ずつ UNIX TIME をインクリメントするのが正攻法だが)。

PHP

どこに行ってもお騒がせな感があるPHP。実はデフォルトで Repl 環境があることはあまり知られていない(かも?)。ただし、行末のセミコロンが必要だったり、返り値の表示がされなかったり、機能的にはアレである。

% php -v
PHP 5.4.17 (cli) (built: Aug 25 2013 02:03:38) 
Copyright (c) 1997-2013 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2013 Zend Technologies
% php -a
php > echo mktime(0, 0, 0, 1, 32, 2014);
1391180400

こちらも Python と同様の動作だ。

まとめ

Ruby しっかりしろ。