年月日から曜日を求める式がかなり短く書けると分かったためメモ。
A simple function to get the weekday from Year-Month-Day.
調べたら「ツェラーの公式」ってのもあるらしいが,「1月と2月は前年の 13・14 月として計算する」とか……ややこしいやん。if 文が余計に要るやん。
ここ 200 年ほど(1900-3~2100-2)は,「100 の倍数で 400 の倍数でない年は閏年にしない」という法則を考えずに済むから,この期間に限定すれば,かなりシンプルになる。そこで,if 文が不要で,短い式1つで済む方法を考えてみた。
なお,この記事内では月の数値は 1~12。もし 0~11 を使う場合はソース内の以下の部分を置き換える。
mon < 3 → mon < 2 mon + 9 → mon + 10
● C言語
Cでは整数の割り算は「切り捨て」てくれる点で,このアルゴリズム的にはありがたい。かなり短く書ける。
int weekday( int year, int mon, int day ){ // 0:Sun - 6:Sat return( ( (year -(mon < 3 ? 1 : 0))* 5 / 4 + ((( mon + 9 )% 12)* 13 + 2)/ 5 + day + 1)% 7 ); }
● JavaScript
JavaScript には Date というクラスがあって,そのオブジェクトで曜日を取得する getDay() というメソッドもあるから,関数を独自定義する必要性は薄いが,フォームなどの年月日が個別に指定されたデータでそれを使おうとすると,いちいち setYear() などのメソッドを呼び出す必要がある。年月日から曜日が分かる関数があれば,コード全体も簡単になると思われる。
ただ,自動で切り捨てはされず,Math オブジェクトの floor 関数を使う必要があるから,記述は少々面倒。
function weekday( year, mon, day ){ // 0:Sun - 6:Sat return( ( Math.floor( (year -(mon < 3 ? 1 : 0))* 5 / 4 )+ Math.floor( ((( mon + 9 ) % 12)* 13 + 2)/ 5 )+ day + 1)% 7 ); }
曜日を文字で得たい時はこんな感じか。
"日月火水木金土".charAt( weekday( year, mon, day ) )
"SunMonTueWedThuFriSat".substr( 3 * weekday( year, mon, day ), 3 )
["Sun","Mon","Tues","Wednes","Thurs","Fri","Sat"] [ weekday( year, mon, day ) ]+"day"
● Perl
「切り捨て」に int 関数を使う必要がある点以外は,そのまま。
sub weekday { my ( $year, $mon, $day )= @_; # 0:Sun - 6:Sat return( ( int( ($year -($mon < 3 ? 1 : 0))* 5 / 4 )+ int( ((( $mon + 9 ) % 12)* 13 + 2)/ 5 )+ $day + 1)% 7 ); }
曜日を文字で得たい場合,たとえば UTF-8 でエンコードされている処理系だと,1文字=3バイトになるから,こうする必要がある。
substr( "日月火水木金土", weekday( year, mon, day )* 3, 3 )
perl の文字列では,正確に1文字単位で扱う「内部表現」モードが存在する。その場合は,上記式の 3 を 1 にして使う。つまり,こう。
use Encode qw(decode encode); my $wd = decode( 'UTF-8', "日月火水木金土" ); substr( $wd, weekday( year, mon, day ), 1 )
ただ,このまま出力しても正しく表示しないので,出力する時には,Encode モジュールの encode ルーチンなどを使って UTF-8 などにエンコードする。詳しくは,Perl の Encode モジュール POD などを参照。
● 表計算
そもそも表計算ソフトには,WEEKDAY() という曜日を求める関数がある。ただ,その引数は,日付(年月日)を表す「ひとつの数値」である必要があって,年月日が別々のセルに記載されている場合は使えない。
まぁそんな場合でも,以下のようにすればいい(year,mon,day はそれぞれセル名)。ただし,求まる値は 1:Sun - 7:Sat となる点で,他と異なる。
=WEEKDAY( DATE( year, mon, day ) )