■この記事の概要
この記事では、ツェラーの公式を使用して、指定した年月日から曜日を計算する方法を解説しています。また、mktime関数を用いた計算手法も紹介。具体例を交え、C言語での効率的な実装方法を説明し、閏年処理のポイントも取り上げています。
■ツェラー(Zeller)の公式で曜日を求める
#include <stdio.h>
/* 曜日の算出関数(ツェラーの公式版) 0:日〜6:土 */
char *zeller(int year, int mon, int day){
static char *w[] = {"日","月","火","水","木","金","土"};
if ((mon == 1) || (mon == 2)){
year--;
mon += 12;
}
int idx = (year + year/4 - year/100 + year/400 +
(13 * mon + 8)/5 + day) % 7;
return w[idx];
}
static inline int isleap(int y) {
return (y%4==0 && y%100!=0) || y%400==0 ;
}
static const int daytbl[2][13] = {
{-1,31,28,31,30,31,30,31,31,30,31,30,31,}, //平年
{-1,31,29,31,30,31,30,31,31,30,31,30,31,}, //閏年
};
int main(void){
for(int year = 1582; year <= 3999;year++){
for(int mon = 1; mon <= 12; mon++){
int mondays = daytbl[isleap(year)][mon] ;
for(int day = 1; day <= mondays; day++){
printf("%04d/%02d/%02dは%s曜日\n",
year,
mon,
day,
zeller(year,mon,day)
);
}
}
}
}
年月日から曜日を求めるのに有名な
ツェラーの公式をC言語化してます。
1月2月が前年の13月14月になったり、
4,100,400の閏年関連の定数が
筆者には難解です。
■mktime()関数で曜日を求める
#include <stdio.h>
#include <time.h>
/* 曜日の算出関数(mktime版) */
char *ymd2week(int year,int mon,int day){
struct tm tm = {
.tm_sec =0, /* 秒 [0-61] 最大2秒までのうるう秒を考慮 */
.tm_min =0, /* 分 [0-59] */
.tm_hour =0, /* 時 [0-23] */
.tm_mday =day, /* 日 [1-31] */
.tm_mon =mon-1, /* 月 [0-11] 0から始まることに注意 */
.tm_year =year-1900, /* 年 [1900からの経過年数] */
.tm_wday =0, /* 曜日 [0:日 1:月 ... 6:土] */
.tm_yday =0, /* 年内の通し日数 [0-365] 0から始まることに注意*/
.tm_isdst =-1 /* 夏時間が無効であれば 0 */
};
if(mktime(&tm) == (time_t)-1){
return "mktimeで失敗しました";
}
//1970/01/01 は木曜日
static char *w[] = {"日","月","火","水","木","金","土"};
return w[tm.tm_wday];
}
static inline int isleap(int y) {
return (y%4==0 && y%100!=0) || y%400==0 ;
}
static const int daytbl[2][13] = {
{-1,31,28,31,30,31,30,31,31,30,31,30,31,}, //平年
{-1,31,29,31,30,31,30,31,31,30,31,30,31,}, //閏年
};
int main(void){
for(int year = 1582; year <= 3999;year++){
for(int mon = 1; mon <= 12; mon++){
int mondays = daytbl[isleap(year)][mon] ;
for(int day = 1; day <= mondays; day++){
printf("%04d/%02d/%02dは%s曜日\n",
year,
mon,
day,
ymd2week(year,mon,day)
);
}
}
}
}
tm構造体にはtm_wdayという
曜日を表す便利なメンバがあります。
これを使うと分かりやすいですが
ちょっと処理が重たいです。
■坂本智彦氏方式で曜日を求める
#include <stdio.h>
#include <string.h>
/* 曜日の算出関数(坂本智彦氏版) */
//http://www.kouno.jp/home/c_faq/c20.html#31
/* 0 = Sunday, 1 <= m <= 12, y > 1752 or so */
char *dayofweek(int y, int m,int d)
{
static char *w[] = {"日","月","火","水","木","金","土"};
static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
y -= m < 3;
int n = (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7;
return w[n];
}
static inline int isleap(int y) {
return (y%4==0 && y%100!=0) || y%400==0 ;
}
static const int daytbl[2][13] = {
{-1,31,28,31,30,31,30,31,31,30,31,30,31,}, //平年
{-1,31,29,31,30,31,30,31,31,30,31,30,31,}, //閏年
};
int main(void){
for(int year = 1582; year <= 3999;year++){
for(int mon = 1; mon <= 12; mon++){
int mondays = daytbl[isleap(year)][mon] ;
for(int day = 1; day <= mondays; day++){
printf("%04d/%02d/%02dは%s曜日\n",
year,
mon,
day,
dayofweek(year,mon,day)
);
}
}
}
}
筆者にはさっぱりわかりませんが、
一番高速で軽量です
(C-FAQ 20.31で紹介されていました)
参考: