• ベストアンサー

カレンダープログラム、曜日の出力について。

西暦、月、日(1900年1月1日以降対象)を入力して、曜日を求めるプログラムを考えています。 過去の質問なども参考にしたんですが、プログラムがうまく動かず困っています。 プログラム中コメントの日数を変える辺りに不備があるかと思い色々試しましたが、曜日がずれてしまいますし開始1900年1月1日も月曜なのに水曜と出力されます。 forやifの条件の記述がおかしいのでしょうか? なにか根本的な所が欠如しているのでしょうか、回答をよろしくお願いします。 始めのgetsの所はあえてです。 #include<stdio.h> #include<stdlib.h> int main(void) { char ss[9],cop1[5],cop2[3],cop3[3]; int year,manth,day,aa,cc,i,f; gets(ss); ss[8] = 0; cop1[4] = 0; cop2[2] = 0; cop3[2] = 0; for(i = 0;i <= 3;i++){ cop1[i] = ss[i]; } for(i = 0;i <= 1;i++){ cop2[i] = ss[i+4]; } for(i = 0;i <= 1;i++){ cop3[i] = ss[i+6]; } year = atoi(cop1); manth = atoi(cop2); day = atoi(cop3); printf("%d年%d月%d日",year,manth,day); for(f = 1900; f <= year; f++){  //閏年か平年で日数を変える if((year%4) == 0 && year != 1900){ aa += 366; } else{ aa += 365; } } if((year%4) == 0 && manth >= 3 ){//閏年かつ3月以降日数+1 aa += 1; } switch(manth){ case 1: cc = (aa + day)%7; break; case 2: cc = (aa + 31 +day)%7; break; case 3: cc = (aa + 59 +day)%7; break; case 4: cc = (aa + 90 +day)%7; break; case 5: cc = (aa + 120 +day)%7; break; case 6: cc = (aa + 151 +day)%7; break; case 7: cc = (aa + 181 +day)%7; break; case 8: cc = (aa + 212 +day)%7; break; case 9: cc = (aa + 243 +day)%7; break; case 10: cc = (aa + 273 +day)%7; break; case 11: cc = (aa + 304 +day)%7; break; case 12: cc = (aa + 334 +day)%7; break; } switch(cc){ case 1: printf(" (月)"); break; case 2: printf(" (火)"); break; case 3: printf(" (水)"); break; case 4: printf(" (木)"); break; case 5: printf(" (金)"); break; case 6: printf(" (土)"); break; case 0: printf(" (日)"); break; } return 0; }

質問者が選んだベストアンサー

  • ベストアンサー
  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.9

★追記。 ・質問者さんのソースを元に書き直してみました。  参考にして下さい。 #include <stdio.h> // break 付きのキーワード #define CASE  break;case #define DEFAULT  break;default // 西暦から閏年の判定 int FuncIsLeapYear( int year ) {  if ( !(year % 3200) ) return 0;  // 平年(3200で割れる年)  if ( !(year % 400) ) return 1;  // 閏年(400で割れる年)  if ( !(year % 100) ) return 0;  // 平年(100で割れる年)  if ( !(year % 4) ) return 1;  // 閏年(4で割れる年)  return 0;       // 平年(それ以外の年) } // メイン関数 int main( void ) {  static const char *table[] = { "日", "月", "火", "水", "木", "金", "土" };  // 宣言  int year = 0;  int month = 0;  int day = 0;  int week = 0;  // カウンタ  int days;  int i;    // 年月日の入力  scanf( "%04d/%02d/%02d", &year, &month, &day );  // 1900年以降の日数を数える  for ( days = 0, i = 1900 ; i < year ; i++ ){   days += (FuncIsLeapYear(i) ? 366 : 365);  }  // 1月1日から日数を加える  switch ( month ){   CASE 1: days += 0;   CASE 2: days += 31;   CASE 3: days += 31 + 28;   CASE 4: days += 31 + 28 + 31;   CASE 5: days += 31 + 28 + 31 + 30;   CASE 6: days += 31 + 28 + 31 + 30 + 31;   CASE 7: days += 31 + 28 + 31 + 30 + 31 + 30;   CASE 8: days += 31 + 28 + 31 + 30 + 31 + 30 + 31;   CASE 9: days += 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31;   CASE 10: days += 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30;   CASE 11: days += 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31;   CASE 12: days += 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30;  }  // 3月以降で閏年なら+1日  if ( (month >= 3) && FuncIsLeapYear(year) ){   days++;  }  // 入力した日付を加える  days += day;  // 曜日の計算  week = (days % 7);  // 表示  printf( "year = %d\n", year );  printf( "month = %d\n", month );  printf( "day = %d\n", day );  printf( "week = %s\n", table[week] );  return 0; } 以上。

その他の回答 (8)

  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.8

★アドバイス >過去の質問なども参考にしたんですが、プログラムがうまく動かず困っています。  ↑  この質問を参考にしたのでしょうか?  URL を貼り付けて欲しかったな。 ・私も回答とかで過去に多数ソースを載せています。  次のリンクを参考になると思いますけど。  http://oshiete1.goo.ne.jp/qa3085731.html→『簡素で美しく記述するには・・・・』  私の回答は No.2 です。  閏年の判定関数は No.3 さんの方が見やすいです。 ・この過去質問に  (1)FuncIsLeapYear():西暦から閏年の判定関数  (2)FuncGetDays():年月日から1月1日からの日数を取得  の2つがあります。  これを利用すれば楽に出来ますけど。  下のそのサンプルを載せておきます。 サンプル: // メイン関数 int main( void ) {  // 宣言  int year;  int month;  int day;  int week;    // 年月日の入力  scanf( "%04d/%02d/%02d", &year, &month, &day );  // 曜日の計算  week = FuncGetDays( year, month, day );  week %= 7;  // 表示  printf( "year = %d\n", year );  printf( "month = %d\n", month );  printf( "day = %d\n", day );  printf( "week = %s\n", &"日\0月\0火\0水\0木\0金\0土"[week * 3] );  return 0; } その他: ・上記のサンプルの FuncIsLeapYear()、FuncGetDays() 関数は  http://oshiete1.goo.ne.jp/qa3085731.html→『簡素で美しく記述するには・・・・』  の回答 No.2 の載せた関数です。コピー&ペーストしてソースに取り込んで下さい。 ・あとサンプルでは 1900年1月1日以降かどうかの判定はしていません。  単純に西暦1年1月1日からの通算日数を FuncGetDays() 関数で求めてから 7 で  割ったあまりが曜日の 0~6 になるから問題はない。 ・ただし西暦1年1月1日を入力しても正しい曜日は返らない。  これは回答者 No.6 さんの回答でちょっと書かれていますが、ユリウス暦、グレゴリオ暦  を判断して曜日を計算していないからです。  このため FuncGetDays() 関数で求めた通算日数は西暦1年1月1日からの日数ですが  今のグレゴリオ暦に合わせているためにユリウス暦での曜日は正しく計算できないのです。 ・また、日本と海外の国ではユリウス暦からグレゴリオ暦に切り替わった年代が異なっています。  このためユリウス暦に完全対応するには『国』を指定する必要があります。もしくは日本限定。 ・以上。今後のカレンダー・プログラムの参考に。

参考URL:
http://oshiete1.goo.ne.jp/qa3085731.html
  • noocyte
  • ベストアンサー率58% (171/291)
回答No.7

#6 です.ちょっと訂正します. > // dayNumber ← グレゴリオ暦0年3月1日を第1日とする通算日数 > dayNumber = (365 * year + nDaysSinceMarch1st[month - 3] + day) >       + floor((double)year / 4) >       - floor((double)year / 100) >       + floor((double)year / 400); これだと INT_MIN≦year≦INT_MAX の範囲をフルに使えないので, 次のように変更します.  dayNumber = nDaysSinceMarch1st[month - 3] + day        + 365.0 * year        + floor((double)year / 4)        - floor((double)year / 100)        + floor((double)year / 400);

  • noocyte
  • ベストアンサー率58% (171/291)
回答No.6

偶然ですが私も最近,昔考えた高速日付計算プログラムを 整理しているところなので参加します.(笑) 次のプログラムは紀元前 (年≦0) の日付でも計算できます. (ただし西暦0年=紀元前1年である点に注意.) 計算可能な日付の範囲は,INT_MIN≦年≦INT_MAX です. したがって int が32ビットならば,西暦 2,147,483,648 年問題 および西暦紀元前 2,147,483,649 年問題があります.(笑) #include <assert.h> #include <stdio.h> #include <math.h> /*-------------------------------------------------------------------------- 通日 (通算日数) の基準日 (epoch) を表す定数 (グレゴリオ暦0年3月1日(水)を第1日とする通日) --------------------------------------------------------------------------*/ // ユリウス日 (基準日時:-4713/11/24(月) 12:00 UTC) #define EPOCH_JD    (-1721118.5) // 12:00 UTC #define EPOCH_CJD   (-1721119)  // 00:00 UTC (Chronological Julian Day) // 修正ユリウス日 (基準日時:1858/11/17(水) 00:00 UTC) #define EPOCH_MJD   678882 // UNIX Time (C言語の time_t 型,基準日時:1970/01/01(木) 00:00 UTC) #define EPOCH_UNIXTIME 719469 // Microsoft Excel 日付のシリアル値 // 基準日は 1900/01/01(月) ということになっているが, // Excel では1900年 (平年) が閏年として扱われるため,事実上は次のとおり. #define EPOCH_19000101 693902 // 基準日:1900/01/01(月),1900年2月以前の日付の場合 #define EPOCH_18991231 693901 // 基準日:1899/12/31(日),1900年3月以後の日付の場合 /*-------------------------------------------------------------------------- 機能 :グレゴリオ暦 → 通日変換     グレゴリオ暦 year 年 month 月 year 日を,     所定の基準日を第0日とする通日 (通算日数) に変換する. 入力 :(1) (year, month, day):日付 (グレゴリオ暦).     (2) epoch:グレゴリオ暦0年3月1日(水)から基準日までの日数 (EPOCH_*). 戻り値:epoch を基準日とするグレゴリオ暦 year 年 month 月 year 日の通日. --------------------------------------------------------------------------*/ double DateToDayNumber(int year, int month, int day, double epoch) {  // 3月1日を第0日とする,3~14月1日の通算日数.  // (1~2月は前年の13~14月として扱う.)  static const unsigned short nDaysSinceMarch1st[12] = {   0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337  };  double dayNumber;  assert((1 <= month) && (month <= 12));  assert((1 <= day) && (day <= 31));  // 計算の都合上,year年1~2月は,(year-1)年13~14月として扱う.  if(month < 3) {   month += 12;   year--;  }  // dayNumber ← グレゴリオ暦0年3月1日を第1日とする通算日数  dayNumber = (365 * year + nDaysSinceMarch1st[month - 3] + day)        + floor((double)year / 4)        - floor((double)year / 100)        + floor((double)year / 400);  return dayNumber - epoch; } /*-------------------------------------------------------------------------- 機能 :通日から曜日を求める. 入力 :(1) dayNumber:通日.     (2) sunday:任意の日曜日の通日. 戻り値:dayNumber の曜日を表す文字列. --------------------------------------------------------------------------*/ const char *DayOfWeek(double dayNumber, double sunday) {  static const char * const dayOfWeek[7] = {   "日", "月", "火", "水", "木", "金", "土"  };  dayNumber -= sunday;  return dayOfWeek[(int)(dayNumber - floor(dayNumber / 7) * 7)]; } /*-------------------------------------------------------------------------- 機能 :DateToDayNumber() のテスト. --------------------------------------------------------------------------*/ void DateToDayNumberTest(void) {  double dayNumber;  int year, month, day;  char line[1024];  for(;;) {   fprintf(stderr, "year/month/day: ");   if(fgets(line, sizeof(line), stdin) == NULL) break;   if((sscanf(line, "%d/%d/%d", &year, &month, &day) != 3) ||     (month < 1) || (month > 12) || (day < 1) || (day > 31)) {    fprintf(stderr, "日付が無効です.\n");   } else {    dayNumber = DateToDayNumber(year, month, day, 0);    printf("%d/%02d/%02d(%s)\n",        year, month, day, DayOfWeek(dayNumber, (double)5));    printf(" 1900/01/01(月)の%.16G日後\n", dayNumber - EPOCH_19000101);    printf(" ユリウス日:%.16G\n", dayNumber - EPOCH_JD);    printf(" 修正ユリウス日:%.16G\n", dayNumber - EPOCH_MJD);    printf(" UNIX Time (time_t):%.16G\n",        (dayNumber - EPOCH_UNIXTIME) * (60 * 60 * 24));   }  } } /*-------------------------------------------------------------------------- --------------------------------------------------------------------------*/ int main(int argc, char *argv[]) {  DateToDayNumberTest();  return 0; }

参考URL:
http://www5d.biglobe.ne.jp/~noocyte/Programming/GregorianAndJulianCalendars.html
  • R32C
  • ベストアンサー率39% (115/290)
回答No.5

time.h系のCの標準ライブラリを使うべきですね。 Cygwinで確認しました。 まず、struct tm に年月日をいれて 次に time_t に変換(1900年年頭からの秒数) もいちど time_t から strut tm に戻せば 曜日が設定されます。 #include <time.h> #include <stdio.h> int main( void ) { struct tm when; time_t when_t; int input_year, input_month,input_day; printf("time_tの長さ%02d\n",sizeof(time_t)); //time_tのサイズを確認 memset(&when,0,sizeof(struct tm)); printf("年月日を8桁で入力してください:-->"); scanf("%04d%02d%02d",&input_year,&input_month,&input_day); when.tm_mday = input_day; when.tm_mon = input_month -1; when.tm_year = input_year - 1900; if ((when_t = mktime(&when)) != (time_t)-1) { localtime_r(&when_t,&when); switch(when.tm_wday) { case 0: printf("日曜日です。\n"); break; case 1: printf("月曜日です。\n"); break; case 2: printf("火曜日です。\n"); break; case 3: printf("水曜日です。\n"); break; case 4: printf("木曜日です。\n"); break; case 5: printf("金曜日です。\n"); break; case 6: printf("土曜日です。\n"); break; default: printf("入力ミスです\n"); } } else printf("入力ミスです\n"); } 実際には、2038年問題がないよう、64bit化されたtime_tの処理系で書き直したらよいと思います。

参考URL:
http://msdn2.microsoft.com/ja-jp/library/w4ddyt9h(VS.80).aspx
回答No.4

windowsなら GetLocalTime 現在のローカル日時を取得します。 VOID GetLocalTime( LPSYSTEMTIME lpSystemTime // システム日時 ); SYSTEMTIME構造体のメンバwDayOfWeekが曜日 Sunday = 0 Monday = 1 Tuesday = 2 Wednesday = 3 Thursday = 4 Friday = 5 Saturday = 6

  • asuncion
  • ベストアンサー率33% (2127/6289)
回答No.3

> 入力した年月日までの総日数 サンプルコードです。たぶん、合っていると思います。 #include <stdio.h> int isLeap(int y) {   // 閏年かどうかの判定   return y % 4 == 0 && y % 100 != 0 || y % 400 == 0; } int main(void) {   int y, m, d, yy, mm, days;   int mdays[2][13] = {     { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },     { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },   };      // 年月日の入力   do {     printf("年 > "), scanf("%d", &y);   } while (y < 1900);      do {     printf("月 > "), scanf("%d", &m);   } while (m < 1 || 12 < m);      do {     printf("日 > "), scanf("%d", &d);   } while (d < 1 || mdays[isLeap(y)][m] < d);      // 前年までの通算日数   for (days = 0, yy = 1900; yy < y; yy++)     days += 365 + isLeap(yy);      // 当年前月までの通算日数   for (mm = 0; mm < m; mm++)     days += mdays[isLeap(y)][mm];      // 当日までの通算日数   days += d;   printf("1900年1月1日~%d年%d月%d日の日数:%d\n", y, m, d, days);   return 0; } (注)インデントのため、全角空白を使っています。

b9b9b9b9
質問者

お礼

2次元配列を使ったり、do-whileにもこんな使い方があるんですね。 サンプルまで書いて頂いてありがとうございました。

  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.2

最初に日数を加算するループの終了条件が f <= year となっていますよね これだと 入力された年1年分を加算することになりませんか そうなると翌年の日付を算出となって食い違いますよね

b9b9b9b9
質問者

お礼

返信ありがとうございます。 (year - 1)という事でしょうか。。 参考にしてがんばります。

  • asuncion
  • ベストアンサー率33% (2127/6289)
回答No.1

「Zellerの公式」でググってみてください。

b9b9b9b9
質問者

お礼

返信、有難うございます。 先ほどから調べているおりに目にはしていたのですが、ここまで便利な公式だとは・・・。当然の様にプログラムは動いてくれました。 ただ、ツェラーの公式で求める事の出来た入力した年月日までの総日数を(閏年も考慮して)自分で計算したいのです方法は沢山あるきもしたのですが、力及ばずなにか簡潔な方法があれば、助言頂きたいと質問しています。 重ね重ねすいませんが、お願いします。

関連するQ&A