• ベストアンサー

日付と曜日から、1週間前(7日前)の日付を算出するプログラム

ツェラーの公式を用いて、日付(年月日)から曜日を算出する方法があります。 例えばY年M月D日の曜日は、下式で求められます。 (Y + Y/4 - Y/100 + Y/400 + (13*M + 8)/5 + D) % 7 *但し、1月・2月は、前年の13月・14月とする。 *答えは0=日曜~6=土曜 これを応用して(別に応用しなくても良いんですが・・・)日付と曜日から、1週間前の同一曜日の日付を求めるプログラムを考えております。 例) 入力:2005年9月21日、水曜日 出力(解):2005年9月14日 この例は非常に簡単に求められますが、完全汎用型のプログラムを考えております。 しかし、なかなか良い知恵が出ません!! どなたかご教示頂けると助かります。 よろしくお願いします。

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

  • ベストアンサー
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

yyyy年mm月dd日の 1週間前の日を求める, 手抜きな方法: 1. dd から 7 を引く 2. 1 の答が 0以下になったら mm から 1 を引き, (更新後の) その月の日数を dd に足す 3. mm が 0 になったら yyyy から 1 を引き mm を 12 にする 真面目にやると面倒なので, 一旦ユリウス通日にしてから 7 を引いて戻すのがよいかと.

black2005
質問者

お礼

ご回答ありがとうございます。 まず最初に、その方法を考えました。 やはり一番素直で簡素な回答ですよね? 月毎の末日はテーブルに入れておき、参照するようにすれば良いですね。 この方法でも試してみます。 ありがとうございました!

その他の回答 (3)

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.4

> 完全汎用型のプログラムを考えております。 完全汎用型というのはどんなものを想定していますか?一般的な意味で解釈すると、完全に汎用のものを作ることはかなり難しいと思います。 まず、グレゴリオ暦が採用されたのは(本能寺の変が起きた)1582年からですが、各国によって実際の導入時期はまちまちで、日本では1873年から導入されました。これを反映するには、ロケールに応じてユリウス暦とグレゴリオ暦を切り替えることになりますが、日本のように太陰太陽暦を用いていた国などではエラーにするしかないと思います。 また、曜日の概念が導入されたのは321年のコンスタンティヌス帝時代のローマですが、他の国の導入時期を正確に把握するのは困難です。 さらに、グレゴリオ暦(というより協定世界時)は、未来永劫修正なしで済ませられるほど、精度が高いわけでもありません。何万年後か知りませんが、必ず何らかの補正が必要になることでしょう。しかし、現在の我々には、未来の暦法を知るすべなどありません。 もし、単に最近の年代だけを扱えばよいのであれば、mktimeを使えば簡単にできます。 struct tm t; t.tm_year = -1900 + 2005; t.tm_mon = -1 + 9; t.tm_mday = 21; t.tm_hour = 0; t.tm_min = 0; t.tm_sec = 0; t.tm_isdst = -1; t.tm_mday -= 7; /* 1週間前 */ if (mktime(&t) == (time_t)-1)  fputs("エラー\n", stderr); puts(asctime(&t));

black2005
質問者

お礼

ご回答ありがとうございます。 すいません、完全汎用型というのは大袈裟な表現でした。 その時代まで遡って正常に動くものは考えておりません。 過去100年間程度正常に動くもの、と考えています。 他の方のも参考に、出来るような気がしてきました。 ありがとうございました!

  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.3

だいたいはNo.1の回答で説明されていますが、困っているのは「3月1日~3月7日の1週間前」だと思います。 この期間は、閏年の関係で「2月末日」が何日かを計算する必要がありますので。 閏年は、 「年を4で割って割り切れる年」かつ ←条件1 「但し、100で割って割り切れる場合は除外」かつ ←条件2 「但し、400で割って割り切れる場合は除外しない」 ←条件3 と言う判定を行って計算します。 ツェラーの公式の Y + Y/4 - Y/100 + Y/400 の部分が、この判定に相当します。 正しく判定出来たならば、 1896年 閏年 ←条件1に該当 1900年 通常年 ←条件2に該当 1904年 閏年  | 1996年 閏年 2000年 閏年 ←条件3に該当 2004年 閏年  | 2096年 閏年 2100年 通常年 2104年 閏年 と判定される筈ですので、ご自分で書かれた判定プログラムを試してみて下さい。 蛇足ですが、古い「カレンダーICチップ」の中には「年を4で割って割り切れる年が閏年」とだけ計算していて、2つの例外条件を無視しているICチップがあります。 なぜなら、その条件のみで「1901~2099年」の約200年間は正しく動くからです。 コストダウンの為だと思いますが「どうせ2100年が来る前に耐用年数を超して壊れるだろう」と言うのもあったのでしょう。

black2005
質問者

お礼

ご回答ありがとうございます。 閏年の判定方法をご教示頂き、感謝致します。 参考にさせて頂きます。 確かに常識的な期間だけ正常に動けばいいや!と考えますね(^◇^;) ありがとうございました!

回答No.2

回答と言うよりヒントですが…… まず、大抵の処理系には、「日付・時刻」を管理するクラスがあります。これまた大抵、「日付の連番」と「年月日それぞれの値」が使えますので、 ・年月日→連番に変換 ・連番になった状態で、7日分をマイナス ・それをさらに、年月日に戻す。 という手があります。 No.1 の形の回答にある、ユリウス通日に戻すのも同じ考え方です。 標準のCのライブラリの範囲では、time.h というヘッダに、一式関数が入っていますので、じっくり眺めれば使えると思います(使ったことはありません・いつも、処理系についているクラスを使っているので)

参考URL:
http://wisdom.sakura.ne.jp/programming/c/c60.html
black2005
質問者

お礼

ご回答ありがとうございます。 連番でやる方法もあるんですねー。 全く考えもしませんでした。 面白そうなので、ヒントを参考に考えてみます。 組み込み機器のプログラムなのでライブラリは極めて少なく、 かつコードをスリム化するために使用出来ないのです(>_<) 言葉足らずで申し訳ありませんでした!

関連するQ&A

専門家に質問してみよう