パンダのメモ帳

技術系のネタをゆるゆると

各月の末日(最終日)を判定するアルゴリズム

JavaScript で各月の最終日を取得する場合に、2つのアルゴリズムを考えたので実行速度を比較してみた。

1. 単純なアルゴリズム

まず、誰でも思いつくであろう単純なアルゴリズム。

function eom_a(y, m){
  switch (m) {
    case 2:
      return isLeapYear(y) ? 29 : 28;
      
    case 4: case 6: case 9: case 11:
      return 30;
  }
  return 31;
}

isLeapYear() はうるう年判定の関数。2月のみうるう年の判定を行い、29 or 28 を返す。そのほかの月については 30日となる月のみ switch 文で判定し、マッチしない場合は 31 を返す。たぶん、誰でも思いつく簡単なアルゴリズム。

2. ちょっと変なアルゴリズム

単純なアルゴリズムを採用した場合に、条件判定が何度も行われるケースがあるのがちょっと気になり、以下のようなアルゴリズムを考えてみた。

function eom_b(y, m){
  if (m == 2) {
    return isLeapYear(y) ? 29 : 28;
  }
  return (m < 8) ? 30 + (m % 2) : 31 - (m % 2);
}

2月の場合の処理は一緒。7月までは奇数月が31日、8月以降は偶数月が31日であることに着目してみた。割算をしてるのが速度に影響しそう。

3. 検証

以下、検証用のスクリプト。上記の2関数を各20万回ずつ実行し、処理時間を計測・表示した。

<!DOCTYPE html>
<html lang="ja">
<head>
  <title>Get end of month</title>
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
  <script>
    $(function(){
      function isLeapYear(y){
        return ((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0)) ? true : false;
      }
      function eom_a(y, m){
        switch (m) {
          case 2:
            return isLeapYear(y) ? 29 : 28;
            
          case 4: case 6: case 9: case 11:
            return 30;
        }
        return 31;
      }
      function eom_b(y, m){
        if (m == 2) {
          return isLeapYear(y) ? 29 : 28;
        }
        return (m < 8) ? 30 + (m % 2) : 31 - (m % 2);
      }
      var i, st, et, b = $('body');
      // eom_a
      st = (new Date()).getTime();
      for (i = 200000; i > 0; --i) {
        eom_a(i % 2010, i % 12 + 1);
      }
      et = (new Date()).getTime();
      b.append('<p>'+(et-st)+' ms</p>');
      // eom_b
      st = (new Date()).getTime();
      for (i = 200000; i > 0; --i) {
        eom_b(i % 2010, i % 12 + 1);
      }
      et = (new Date()).getTime();
      b.append('<p>'+(et-st)+' ms</p>');
    });
  </script>
</head>
<body></body>
</html>

これを各ブラウザで実行してみたら、意外な結果に。ちなみに OS は Windows 7, CPU は Core2 Duo E7500。

ブラウザ eom_a eom_b
Internet Explorer 8 164 ms 175 ms
Firefox 3.6.3 203 ms 4 ms
Chrome 5 7 ms 11 ms
Safari 5 8 ms 6 ms
Opera 10 68 ms 59 ms

思ったより差がない……と思いきや、Firefox のみ圧倒的に後者のアルゴリズムの方が速い。その他のブラウザでは無視できる程度の差しかなかった。

4. 結論

だからどうした……って話だけど、せっかく調べたので投稿してみた。それにしてもいつの間にか Safari がかなり高速化されていてむしろそっちにびっくりした。