アプリ版:「スタンプのみでお礼する」機能のリリースについて

西暦年月日を入力して、その日の曜日を表示させるプログラムを作りたいのですが、とりあえず、やってみましたが…

int main(void)
{

int i,y,m,d,dy,dw;

int D[]={0,31,28,31,30,31,30,31,31,30,31,30,31};

printf("Year?");

scanf("%d",&y);

printf("Month?");

scanf("%d",&m);

printf("Day?");

scanf("%d",&d);

for(i=0;i<=m-1;i++){
dy = d + D[i] ;
}

if(m>=3){
if(y % 4 == 0){
if(y % 400 == 0){
dy = dy + 1 ;
}
else if(y % 100 ==0){
dy = dy ;
}
else{
dy = dy + 1 ;
}
}

else if(y % 4 == 1 || y % 4 == 2 || y % 4 == 3 ){
dy = dy ;
}
}
dw = (dy -1 + ( y + ( y - 1 )/4 - ( y - 1 )/100 + ( y - 1 )/400))%7 ;

if (dw == 0) printf("Sunday\n");
else if (dw == 1) printf("Monday\n");
else if (dw == 2) printf("Tuesday\n");
else if (dw == 3) printf("Wednesday\n");
else if (dw == 4) printf("Thursday\n");
else if (dw == 5) printf("Friday\n");
else if (dw == 6) printf("Saturday\n");

return 0 ;

}
このプログラムを各年の1月1日~2月28日で試してみると、うまくいくのですが、3月1日に入るとなぜかうまく働いてくれません。(ちなみに2005年の11月では偶然うまくいっています。)その理由が分からないのでどなたか教えてください。ちなみに、この一連のプログラムを行うにはもっと簡単に行える関数というかコマンド?みたいなものがあるようですが、基本的に各年の1月1日を、
(y+(y-1)/4-(y-1)/100+(y-1)/400)%7で(0:Sunday~)、同年の○月○日は1月1日から△日経過しているという考え方で、曜日を割り出すプログラムにしなければならないといけないので、注文が多いですがよろしくお願いします。

A 回答 (8件)

プログラムのおかしいところについては#1の回答のとおりです。


したがって、
>int D[]={0,31,28,31,30,31,30,31,31,30,31,30,31};
これを
>int D[]={0,31,59,90,120,151,181,212,243,273,304,335};
>//各月の前月までの年初からの日数
として、
>for(i=0;i<=m-1;i++){
> dy = d + D[i] ;
>}

>dy = d[m-1] + d;
とするという解法もあります。あらかじめ足しておいてはいけないということはないでしょう。

ただ、標準関数に日付の関数はあります。
もちろん制限はあって、time_tのサイズが32bit(=signed long int)の場合、1901年12月14日05:45:52~2038年1月19日12:14:07の間だけが正常に動作するようになっていますし、上記のアルゴリズムとは違って1970年1月1日00:00:00を基準とした秒数をもとにして計算しているため、今回は利用できませんね。

ところで、
> ちなみに2005年の11月では偶然うまくいっています。
の理由について回答が出ていませんが、それは、2005年1月と2005年10月がたまたま同じ曜日で始まっていてかつ、1月と10月が同じ日数(31日)だからです。
    • good
    • 0
この回答へのお礼

2005年11月で偶然うまくいっている理由についてもコメントしていだたきありがとうございます。

お礼日時:2005/11/29 23:09

蛇足ながら、1582年を境にグレゴリオ暦とユリウス暦が使い分けられています。

そのパッチを加えました。
#include <stdio.h>
#include <stdlib.h>

int
getint(void)
{
char buf[BUFSIZ];
fgets(buf, BUFSIZ, stdin);
return (atoi(buf));
}

int
main(void)
{
int i, y, m, d, dy, dw;
int D[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
char *Week[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
"Friday", "Saturday" };
printf("Year?");
y = getint();
printf("Month?");
m = getint();
printf("Day?");
d = getint();

for (i = 0; i <= m - 1; i++) {
d += D[i];
}
dy = d;
if (m >= 3) {
if (y % 400 == 0 || (y % 100 != 0 && y % 4 == 0)) dy++;
}
dy += y * 365 + y / 4 - y / 100 + y / 400;
/* printf("dy = %d\n", dy); */
if (dy >= 578101) { /* 1582年10月15日以降はグレゴリオ暦 */
dw = (dy + 6) % 7;
}
else if (dy <= 578090) { /* 1582年10月4日以前はユリウス暦 */
dy = d;
if (m >= 3) {
if (y % 4 == 0) dy++;
}
dy += y * 365 + y / 4;
dw = (dy + 4) % 7;
}
else {
printf("その日は存在しません。\n");
return(0);
}
printf("%s\n", Week[dw]);
return 0;
}
    • good
    • 0
この回答へのお礼

暦が1582年を境に違うなんて初めて知りました。親切にありがとうございます!

お礼日時:2005/11/29 23:12

がると申します。


んっと。曜日の算出にはいくつか種類がありますが、有名なツェラーの公式をお勧めします。
どうでしょうか?

参考URL:http://www004.upp.so-net.ne.jp/s_honma/doweek.ht …
    • good
    • 0

>この一連のプログラムを行うにはもっと簡単に行える関数というかコマンド?みたいなものがあるようですが


蛇足ですが…
#include <stdio.h>
#include <time.h>

int
getint(void)
{
char buf[BUFSIZ];
fgets(buf, BUFSIZ, stdin);
return (atoi(buf));
}

int
main(void)
{
struct tm day;
time_t time;

char *Week[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
"Friday", "Saturday" };
printf("Year?");
day.tm_year = getint() - 1900;
printf("Month?");
day.tm_mon = getint() - 1;
printf("Day?");
day.tm_mday = getint();
day.tm_hour = day.tm_min = day.tm_sec = 0;
time = mktime(&day);
localtime_r(&time, &day);

printf("%s\n", Week[day.tm_wday]);
return 0;
}
    • good
    • 0

#include <stdio.h>



int
getint(void)
{
char buf[BUFSIZ];
fgets(buf, BUFSIZ, stdin);
return (atoi(buf));
}

int
main(void)
{
int i, y, m, dy, dw;
int D[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
char *Week[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
"Friday", "Saturday" };
printf("Year?");
y = getint();
printf("Month?");
m = getint();
printf("Day?");
dy = getint();

for (i = 0; i <= m - 1; i++) {
dy += D[i];
}
if (m >= 3) {
if (y % 400 == 0 || (y % 100 != 0 && y % 4 == 0)) dy++;
}
dw = (dy - 1 + (y + (y - 1) / 4 - (y - 1) / 100 + (y - 1) / 400)) % 7;

printf("%s\n", Week[dw]);
return 0;
}
    • good
    • 0

#3です。

書き間違えてました。
>int D[]={0,31,59,90,120,151,181,212,243,273,304,335};
最後の335は334の間違い。
    • good
    • 0

//何かの参考に


#include <stdio.h>
#include <stdlib.h>

int isLeapYear(unsigned y){
return ((0 == y % 400)||((0 == y % 4)&&(0 != y % 100)));
}

unsigned leapDays(unsigned y){
/* 基準日から指定年までの閏日の日数 */
return (y/4 - y/100 + y/400);
}

unsigned daysFromYearTop(unsigned y, unsigned m, unsigned d){
/* 指定日の年頭からの日数 */
static unsigned daysOfMonth[]={
NULL, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
};
return (daysOfMonth[m]+((m>2 && isLeapYear(y))? 1:0) + d);
}

unsigned long days(unsigned y, unsigned m, unsigned d){
/* 基準日から指定日までの通算日数 */
unsigned lastYear=y-1;

return(leapDays(lastYear) + lastYear*365 + daysFromYearTop(y, m, d));
}
#define JAPANESE 0
#define ENGLISH 1
#define ENGSHORT 2
const char *week_day(unsigned long days,int country){
/* 基準日からの通算日を指定した時の曜日を文字列で返す */
static const char *weekDays[][7]={
{"日", "月", "火", "水", "木", "金", "土"},
{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"},
{"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"}
};
return(weekDays[country][days % 7]);
}

int main(void){
unsigned y, m, d;

printf("Year?");
scanf("%u",&y);
printf("Month?");
scanf("%u",&m);
printf("Day?");
scanf("%u",&d);

printf("%s\n",week_day(days(y,m,d), ENGLISH));//通算日の曜日

return(EXIT_SUCCESS);
}
    • good
    • 0

>for(i=0;i<=m-1;i++){


>dy = d + D[i] ;
>}
これでは前月のみの日付が加算されるだけです。
だから2月までならうまくいくわけです。

簡単に修正するならこんな感じでしょうか。
dy = d;
for (i = 0; i < = m - 1; i++)
{
dy += D[i] ;
}

Cの標準関数で日付関数はなかったと思います。
日付計算はよく使われるので探せばライブラリがありそうですが。
参考URLに日付関数のサンプルがありましたので参考にしてみてはいかがでしょう。

参考URL:http://hp.vector.co.jp/authors/VA016117/date.html
    • good
    • 0
この回答へのお礼

ありがとうございました。無事解決しました。感謝しいたします!

お礼日時:2005/11/29 23:06

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!