休日の偏りについて調べてみた

# はじめに

今年の結婚記念日が平日だという話を妻としていたときにふと、

> 日付によって休日の出現率にばらつきがあるか?

ということが頭をよぎり、調査してみた。

# 前提条件

- 土曜日と日曜日の出現数を考慮。
- 祝日は不確定要素なので考慮しない。

# 調査方法

単純に日付をインクリメントして曜日をカウントする。

# コード

https://gist.github.com/loasnir/9eab7f333daeab4ec20c245de045066d

```ruby
require 'date'

start_date = Date.parse('0001-01-01')
end_date   = Date.parse('9999-01-01')

cd     = start_date
result = {}
while cd <= end_date do
  key = cd.strftime('%m-%d')
  is_holiday = cd.sunday? or cd.saturday?
  result[key] = (result.has_key?(key) ? result[key] + 1 : 1) if is_holiday;
  cd += 1
end

result.sort_by{ |_, v| -v }.each do |day, count|
  puts "#{day} => #{count}"
end
```

# 結果
```
03-13 => 1448
02-26 => 1448
02-19 => 1448
02-12 => 1448
02-05 => 1448
01-29 => 1448
01-22 => 1448
01-15 => 1448
01-08 => 1448
01-01 => 1448
12-25 => 1448
12-18 => 1448
12-11 => 1448
12-04 => 1448
11-27 => 1448
11-20 => 1448
11-13 => 1448
11-06 => 1448
10-30 => 1448
10-23 => 1448
10-16 => 1448
10-09 => 1448
10-02 => 1448
09-25 => 1448
09-18 => 1448
09-11 => 1448
09-04 => 1448
08-28 => 1448
08-21 => 1448
08-14 => 1448
08-07 => 1448
07-31 => 1448
07-24 => 1448
07-17 => 1448
07-10 => 1448
07-03 => 1448
06-26 => 1448
06-19 => 1448
06-12 => 1448
06-05 => 1448
05-29 => 1448
05-22 => 1448
05-15 => 1448
05-08 => 1448
05-01 => 1448
04-24 => 1448
04-17 => 1448
04-10 => 1448
04-03 => 1448
03-27 => 1448
03-20 => 1448
03-06 => 1448
12-27 => 1447
03-04 => 1447
03-11 => 1447
03-18 => 1447
03-25 => 1447
04-01 => 1447
04-08 => 1447
04-15 => 1447
04-22 => 1447
04-29 => 1447
05-06 => 1447
05-13 => 1447
05-20 => 1447
05-27 => 1447
06-03 => 1447
06-10 => 1447
06-17 => 1447
06-24 => 1447
07-01 => 1447
07-08 => 1447
07-15 => 1447
07-22 => 1447
07-29 => 1447
08-05 => 1447
08-12 => 1447
08-19 => 1447
08-26 => 1447
09-02 => 1447
09-09 => 1447
09-16 => 1447
09-23 => 1447
09-30 => 1447
03-01 => 1447
03-08 => 1447
03-15 => 1447
03-22 => 1447
03-29 => 1447
04-05 => 1447
04-12 => 1447
04-19 => 1447
04-26 => 1447
05-03 => 1447
05-10 => 1447
05-17 => 1447
05-24 => 1447
05-31 => 1447
06-07 => 1447
06-14 => 1447
06-21 => 1447
06-28 => 1447
07-05 => 1447
07-12 => 1447
07-19 => 1447
07-26 => 1447
08-02 => 1447
08-09 => 1447
08-16 => 1447
08-23 => 1447
08-30 => 1447
09-06 => 1447
09-13 => 1447
09-20 => 1447
09-27 => 1447
10-04 => 1447
10-11 => 1447
10-18 => 1447
10-25 => 1447
11-01 => 1447
11-08 => 1447
11-15 => 1447
11-22 => 1447
11-29 => 1447
12-06 => 1447
12-13 => 1447
12-20 => 1447
02-24 => 1446
10-07 => 1446
10-14 => 1446
10-21 => 1446
10-28 => 1446
11-04 => 1446
11-11 => 1446
11-18 => 1446
02-28 => 1446
02-21 => 1446
02-14 => 1446
02-07 => 1446
01-31 => 1446
01-24 => 1446
01-17 => 1446
01-10 => 1446
11-25 => 1446
12-02 => 1446
12-09 => 1446
12-16 => 1446
12-23 => 1446
12-30 => 1446
01-06 => 1446
01-13 => 1446
01-20 => 1446
01-27 => 1446
02-03 => 1446
02-10 => 1446
02-17 => 1446
01-03 => 1446
06-08 => 1425
06-15 => 1425
06-22 => 1425
06-29 => 1425
07-06 => 1425
07-13 => 1425
07-20 => 1425
07-27 => 1425
03-10 => 1425
03-17 => 1425
03-24 => 1425
03-31 => 1425
04-07 => 1425
04-14 => 1425
04-21 => 1425
04-28 => 1425
03-03 => 1425
05-05 => 1425
05-12 => 1425
05-19 => 1425
05-26 => 1425
06-02 => 1425
06-09 => 1425
06-16 => 1425
06-23 => 1425
06-30 => 1425
07-07 => 1425
07-14 => 1425
07-21 => 1425
07-28 => 1425
08-04 => 1425
08-11 => 1425
08-18 => 1425
08-25 => 1425
09-01 => 1425
09-08 => 1425
09-15 => 1425
09-22 => 1425
09-29 => 1425
10-06 => 1425
10-13 => 1425
10-20 => 1425
10-27 => 1425
11-03 => 1425
11-10 => 1425
11-17 => 1425
11-24 => 1425
12-01 => 1425
12-08 => 1425
12-15 => 1425
12-22 => 1425
12-29 => 1425
01-05 => 1425
01-12 => 1425
01-19 => 1425
01-26 => 1425
02-02 => 1425
02-09 => 1425
02-16 => 1425
02-23 => 1425
08-03 => 1425
08-10 => 1425
08-17 => 1425
08-24 => 1425
08-31 => 1425
09-07 => 1425
09-14 => 1425
09-21 => 1425
09-28 => 1425
10-05 => 1425
10-12 => 1425
10-19 => 1425
10-26 => 1425
11-09 => 1425
11-02 => 1425
11-16 => 1425
11-23 => 1425
11-30 => 1425
12-07 => 1425
12-14 => 1425
12-21 => 1425
12-28 => 1425
01-04 => 1425
01-11 => 1425
01-18 => 1425
01-25 => 1425
02-01 => 1425
02-08 => 1425
02-15 => 1425
02-22 => 1425
03-02 => 1425
03-09 => 1425
03-16 => 1425
03-23 => 1425
03-30 => 1425
04-06 => 1425
04-13 => 1425
04-20 => 1425
04-27 => 1425
05-04 => 1425
05-11 => 1425
05-18 => 1425
05-25 => 1425
06-01 => 1425
09-24 => 1404
01-09 => 1404
01-16 => 1404
01-23 => 1404
01-30 => 1404
02-06 => 1404
02-13 => 1404
02-20 => 1404
02-27 => 1404
03-05 => 1404
03-12 => 1404
03-19 => 1404
03-26 => 1404
04-02 => 1404
04-09 => 1404
04-16 => 1404
04-23 => 1404
04-30 => 1404
05-07 => 1404
05-14 => 1404
05-21 => 1404
05-28 => 1404
06-04 => 1404
06-11 => 1404
06-18 => 1404
06-25 => 1404
07-02 => 1404
07-09 => 1404
07-16 => 1404
07-23 => 1404
07-30 => 1404
08-06 => 1404
08-13 => 1404
08-20 => 1404
08-27 => 1404
09-03 => 1404
09-10 => 1404
09-17 => 1404
01-02 => 1404
10-01 => 1404
10-08 => 1404
10-15 => 1404
10-22 => 1404
10-29 => 1404
11-05 => 1404
11-12 => 1404
11-19 => 1404
11-26 => 1404
12-03 => 1404
12-10 => 1404
12-17 => 1404
12-24 => 1404
12-31 => 1404
01-07 => 1404
01-14 => 1404
01-21 => 1404
01-28 => 1404
02-04 => 1404
02-11 => 1404
02-18 => 1404
02-25 => 1404
12-19 => 1403
12-26 => 1403
12-05 => 1403
11-28 => 1403
11-21 => 1403
11-14 => 1403
11-07 => 1403
10-31 => 1403
10-24 => 1403
10-17 => 1403
12-12 => 1403
08-01 => 1402
07-25 => 1402
07-18 => 1402
07-11 => 1402
07-04 => 1402
06-27 => 1402
06-20 => 1402
06-13 => 1402
06-06 => 1402
05-30 => 1402
05-23 => 1402
05-16 => 1402
05-02 => 1402
04-25 => 1402
04-18 => 1402
04-11 => 1402
04-04 => 1402
03-28 => 1402
03-21 => 1402
03-14 => 1402
03-07 => 1402
05-09 => 1402
10-10 => 1402
10-03 => 1402
09-26 => 1402
09-19 => 1402
09-12 => 1402
09-05 => 1402
08-29 => 1402
08-22 => 1402
08-15 => 1402
08-08 => 1402
02-29 => 329
```

# 追記

妻から「モジュロ演算を使いなさい!」というお達しがあったので追記します。
https://gist.github.com/loasnir/a40a84c733ee02cc12c33bdf282d606a

```ruby:app.rb
require 'date'
require './zeller'

start_date = Date.parse('1583-01-01')
end_date   = Date.parse('9999-01-01')

cd     = start_date
result = {}
while cd < end_date do
    key = cd.strftime('%m-%d')
    h = Zeller.calc(cd)
    is_holiday = h == 1 or h == 7
    result[key] = (result.has_key?(key) ? result[key] + 1 : 1) if is_holiday;
    cd += 1
end
  
result.sort_by{ |_, v| -v }.each do |day, count|
    puts "#{day} => #{count}"
end
```

```ruby:zeller.rb
module Zeller
    def calc(base_day)
        year  = base_day.year - ([1, 2].include?(base_day.month) ? 1 : 0)
        month = ([1, 2].include?(base_day.month) ? 12 : 0) + base_day.month
        day   = base_day.day

        j = (year.to_s + '00')[0, 2].to_i
        k = ('00' + year.to_s)[-2, 2].to_i
        m = month
        q = day

        h = (q + (26*(m + 1))/10 + k + k/4 + j/4 - 2*j)%7
        h
    end

    module_function :calc
end
```

結果は一致しました。

# 所感

結果を見ると多少の差はあれど誤差の範囲じゃないかなぁということになった。
あるいは、2月29日であれば閏年以外の年は2月28日とみなしてしまうと考えて、
2月29日が一番休日数が多いと考えられなくもない?

本当はこのあたりの計算をできるような式を考えるのが正しいのだろうが、
そこまでは良いかなと思い割愛させて頂く。