C言語関係掲示板

過去ログ

No.358.YYYYmmdd形式の日付を、曜日 月 日 年(Thu Aug 8 2002)に変換

[戻る] [ホームページ]

No.2335

YYYYmmdd形式の日付を、曜日 月 日 年(Thu Aug 8 2002)に変換
投稿者---淳(2002/08/08 11:36:14)


20020808とか、2002.08.08等いう様になっている日付を
曜日と月が英語の省略形した文字列形式の日付、例えば
「Thu Aug 8 2002」にしたのですが、どうすればよい
のですか。

変換する元の日付は、コマンドラインから任意で入力し、
また、月の日付は、1桁の場合は、前にスペースを入れた
いです。

どうしたらよいのですか。

No.2336

Re:YYYYmmdd形式の日付を、曜日 月 日 年(Thu Aug 8 2002)に変換
投稿者---かずま(2002/08/08 13:40:50)


#include <stdio.h>

int get_ymd(const char *s, int *yp, int *mp, int *dp)
{
    int n;  char c;

    n = sscanf(s,  "%4d%2d%2d %c", yp, mp, dp, &c);
    if (n == 3) return 1;
    n = sscanf(s,  "%d %*c%d %*c%d %c", yp, mp, dp, &c);
    if (n == 3) return 1;
    return 0;
}

char *week[] = {
    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};

char *month[] = { "",
    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};

int dow(int y, int m, int d)
{
    static char t[] = { 0, 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 };
    y -= m < 3;
    return (y + y/4 - y/100 + y/400 +t[m] + d) % 7;
}

int main(int argc, char **argv)
{
    int y, m, d, i;  char buf[1024], *p = buf;

    for (i = 1; i < argc; i++)
        p += sprintf(p, " %s", argv[i]);
    if (get_ymd(buf, &y, &m, &d) && m>=1 && m<=12)
        printf("%s %s %d %d\n", week[dow(y, m, d)], month[m], d, y);
    return 0;
}

mktime なんかを使うと、私のような年寄りの誕生日が扱えないので、
こんなプログラムを書いてみました。

No.2338

Re:ソースコードについて教えてください。
投稿者---淳(2002/08/08 17:41:39)


int get_ymd(const char *s, int *yp, int *mp, int *dp)
{
int n; char c;

n = sscanf(s, "%4d%2d%2d %c", yp, mp, dp, &c);
if (n == 3) return 1;
n = sscanf(s, "%d %*c%d %*c%d %c", yp, mp, dp, &c);
if (n == 3) return 1;
return 0;
}
sscanfなのですが、cは何を求めているのですか。
また、2回目のsscanfは何をしているのですか。
「%*c%d」はどういう意味なのでしょうか。


int dow(int y, int m, int d)
{
static char t[] = { 0, 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 };
y -= m < 3;
return (y + y/4 - y/100 + y/400 +t[m] + d) % 7;
}
の処理が分かりません。
t[]には、何が設定されているのですか。
「y -= m < 3」は何をしているのですか。
returnにて返却する値を求めているいる式の意味を教えてください。


No.2340

Re:ソースコードについて教えてください。
投稿者---かずま(2002/08/08 18:30:02)


> n = sscanf(s, "%4d%2d%2d %c", yp, mp, dp, &c);
> sscanfなのですが、cは何を求めているのですか。

200201001 のような間違った入力を検出するためです。
これは、1月0日? 1月1日? 10月1日?

なお、"%4d%2d%2d" で、20020808 も 2002 8 8 も読み込めます。


> n = sscanf(s, "%d %*c%d %*c%d %c", yp, mp, dp, &c);
> 「%*c%d」はどういう意味なのでしょうか。

"%d"   0個以上の空白を読み飛ばし、10進数を読み込む。

" "    0個以上の空白を読み飛ばす。

"%*c"  1文字読み飛ばす。

"%d %*c%d %*c%d" で、2002.08.08 も 2002/8/8 も読み込めます。


> int dow(int y, int m, int d)
> の処理が分かりません。

http://www.st.rim.or.jp/~phinloda/cqa/cqa15.html

No.2371

日付から曜日を求める方法
投稿者---理解できない人(2002/08/13 18:46:59)


>http://www.st.rim.or.jp/~phinloda/cqa/cqa15.html
の日付から曜日の求め方を見たのですが、

簡単なところで、
(y + C) % 7;
でなぜ、曜日が求められるのですか。
ここで言っている定数のCには「1」が入る

うるどしを考慮した場合、加算・減算するのは何故。
(y + y/4 + C) % 7;
(y + y/4 - y/100 + y/400 + C) % 7;

static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
が、2プラスされて
int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
とりますが何故2を加えるのか。

No.2373

Re:日付から曜日を求める方法
投稿者---TDa(2002/08/13 20:31:59)


>>http://www.st.rim.or.jp/~phinloda/cqa/cqa15.html
>の日付から曜日の求め方を見たのですが、

>簡単なところで、
> (y + C) % 7;
>でなぜ、曜日が求められるのですか。

>うるどしを考慮した場合、加算・減算するのは何故。

この辺の疑問はすべてフィンローダさんがあなたのおっしゃるページで解説されています。よってあなたの勉強すべきはC言語ではなく国語か中学生レベルくらいの数学でしょう。

ちなみにこのコードはツェラーの公式という有名なものです。



No.2374

Re:日付から曜日を求める方法
投稿者---かずま(2002/08/13 21:09:05)


>>http://www.st.rim.or.jp/~phinloda/cqa/cqa15.html
> の日付から曜日の求め方を見たのですが、

> 簡単なところで、(y + C) % 7; でなぜ、曜日が求められるのですか。

2000年8月13日は 0曜日(日)。
2001年8月13日は 1曜日(月)。
2002年8月13日は 2曜日(火)。
2003年8月13日は 3曜日(水)。

y年8月13日は、((y + 2) % 7)曜日 (C は 2) と定義できる。
1年は 365日で、これは 52週と 1日だから、1年後の同じ日は、
曜日が 1日ずれる。

ところが、2004年8月13日は 5曜日(金)。
なぜなら、2004年は「うるう年」で、2月が29日まであるから。

そこで、
y年8月13日は、((y + y/4 + 6) % 7)曜日 (C は 6) と定義できる。

y % 4 == 0 の年は、うるう年。しかし、
y % 100 == 0 の年は、うるう年ではない。さらに、
y % 400 == 0 の年は、うるう年。

したがって、
y年8月13日は、((y + y/4 - y/100 + y/400 + 0) % 7)曜日 (C は 0)。

次に、y年m月13日がどうなるか考えることにしよう。

2002年8月13日は 2曜日(火)。
2002年9月13日は 5曜日(金)。
2002年10月13日は 0曜日(日)。
2002年11月13日は 3曜日(水)。

8月は 31日だから、4週と 3日。だから、9月の曜日は、3日ずれる。
9月は 30日だから、4週と 2日。だから、10月の曜日は、2日ずれる。

y年8月13日は、((y + y/4 - y/100 + y/400 + 0) % 7)曜日 (C は 0)。
y年9月13日は、((y + y/4 - y/100 + y/400 + 3) % 7)曜日 (C は 3)。
y年10月13日は、((y + y/4 - y/100 + y/400 + 5) % 7)曜日 (C は 5)。

y年m月13日は、((y + y/4 - y/100 + y/400 + t[m]) % 7)曜日 (C は t[m])。

  m =  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12

t[] = {0, 6, 2, 1, 4, 6, 2, 4, 0, 3,  5,  1,  3};

最後に、
y年m月d日は、((y + y/4 - y/100 + y/400 + t[m] + d + 1) % 7)曜日(C は 1)。
この 1 は、t[] に押し込めてしまえばいいから、
t[] = {0, 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};

いい忘れましたが、1月と、2月は、前の年の 12月からのずれで計算することで、
2月29日のことを特別扱いしなくて済みます。

No.2376

Re:日付から曜日を求める方法で言っている定数
投稿者---理解できない人(2002/08/14 00:52:46)


すいません、C言語のプログラミングとはかけはなれていることを訊ねまして。
しかし、理解していない使い方や仕組みもわからないコードを使っても駄目
ですから。
>y年8月13日は、((y + 2) % 7)曜日 (C は 2) と定義できる。
Cはなぜ2となるのですか。
y年8月15日とするとCが2ではできないのですが。

また、うるう年とかの説明で、Cが6とか0とかに定義できると
あるのでがなぜですか。
Cに定義さえる値はどう解釈すればよいのでしょうか。


No.2378

Re:日付から曜日を求める方法で言っている定数
投稿者---TDa(2002/08/14 01:43:27)


>>y年8月13日は、((y + 2) % 7)曜日 (C は 2) と定義できる。
>Cはなぜ2となるのですか。

逆にあなたに質問しましょう。
2002/08/14は私のところでは水曜日です。たぶん全国的に水曜日でしょう。
なぜ水曜日になるんですか。


No.2382

Re:日付から曜日を求める方法で言っている定数
投稿者---TDa(2002/08/14 12:45:10)


返って混乱したかもしれないので補足。

>>y年8月13日は、((y + 2) % 7)曜日 (C は 2) と定義できる。
>Cはなぜ2となるのですか。

そういう風に定義したからです。「定義」とはそういう意味です。
円周の直径に対する比の値を円周率と定義する。
直線とは幅のない長さである。

別に望むのなら-1曜日、123曜日、hoge曜日、風曜日、カレー曜日と定義してもよいのですよ。


No.2384

Re:日付から曜日を求める方法で言っている定数
投稿者---かずま(2002/08/14 14:25:06)


>>y年8月13日は、((y + 2) % 7)曜日 (C は 2) と定義できる。
>Cはなぜ2となるのですか。
>y年8月15日とするとCが2ではできないのですが。
>
> >y年8月13日は、((y + 2) % 7)曜日 (C は 2) と定義できる。
> Cはなぜ2となるのですか。
> y年8月15日とするとCが2ではできないのですが。

> また、うるう年とかの説明で、Cが6とか0とかに定義できると
> あるのでがなぜですか。
> Cに定義さえる値はどう解釈すればよいのでしょうか。

y年m月d日が w曜日であるとすると、w は、y と m と d の関数です。
(数学ではこれを、w = f(y, m, d) と書くが、これは気にしなくていい)
とにかく、y と m と d の値が決まると、w の値も決まります。
y と d と m の値が変わると w の値も変わります。もちろん、w は 0〜6 の
範囲の値なので、変わらない場合もありますが、とにかく、y と m と d の
値が決まると、w の値も決まるから、w は y と m と d の関数です。

3つも変数のある関数を考えるのは大変なので、とりあえず、m と d を固定し
てみましょう。たとえば、m = 8, d = 13 としてみると、あとは y が決まれば
w も決まり、y を 2000〜2003 と変えてみると、w は 0〜3 と変わります。

2000年8月13日は 0曜日(日)。
2001年8月13日は 1曜日(月)。
2002年8月13日は 2曜日(火)。
2003年8月13日は 3曜日(水)。

y が 1 増えると、w も 1 増えます。でも、w は、6 の次は 0 に戻ります。
そこで、w = y % 7 と仮定してみましょう。これで、
y が 1 増えると、w も 1 増えます。さらに、w は、6 の次は 0 に戻ります。
でも、これだと、y = 2000 のとき、w = 5 となって、実際の値と合いません。
y が 1 増えると、w も 1 増えて、さらに、w が 6 の次に 0 に戻る式は、
w = (y + C) % 7 とも書けます。ここで、C の値を 2 にすると、実際の値と
合います。C = 9 でも C = 16 でもいいんだけど、一番簡単な 2 を採用するこ
とにします。

C って何でしょう。m と d を固定したから、決まった定数です。
m と d を変えれば、C も変わります。

次に、うるう年の問題です。
4年に 1度、w が余分に 1 増えるように、式を修正しないといけません。
このために y/4 を足します。y を 2000〜2009 と変えてみると、y/4 は、
500, 500, 500, 500, 501, 501, 501, 501, 502, 502 と変わります。
確かに、2004年と 2008年に 1 増えています。では、
w = (y + y/4 + 2) % 7 でいいでしょうか。
4年に 1度、w が余分に 1 増えるよう修正したつもりですが、500という値を
余分に足してしまいました。500 = 7*71 + 3 ですから、w は 3 だけ大きい値
になってしまいます。これを補正するには、3 を引くか、4 を足すことです。
それで、w = (y + y/4 + 6) % 7 となります。C は 6 ということになりました。

これ以降の考え方も同様です。うるう年の補正を加えるたびに C の値は変わっ
ていきます。さらに、m を可変にする、d を可変にするという変更により C の
値は変わっていきます。

No.2396

Re:日付から曜日を求める方法で言っている定数
投稿者---理解できない人(2002/08/15 02:11:11)


すみません。
C言語のプログラムとは全然関係ないことを訊ねまして。

>y が 1 増えると、w も 1 増えます。でも、w は、6 の次は 0 に戻ります。
>そこで、w = y % 7 と仮定してみましょう。これで、
>y が 1 増えると、w も 1 増えます。さらに、w は、6 の次は 0 に戻りま。
>でも、これだと、y = 2000 のとき、w = 5 となって、実際の値と合いません。
>y が 1 増えると、w も 1 増えて、さらに、w が 6 の次に 0 に戻る式は、
>w = (y + C) % 7 とも書けます。ここで、C の値を 2 にすると、実際の値と
>合います。C = 9 でも C = 16 でもいいんだけど、一番簡単な 2 を採用すこ
>とにします。
y=2000のとき、w=5なのですか。?
w = y % 7 にあてはめると、w=7だと思うのですが。
また、w = y % 7 に Cがついているのは。

うる年
(y + y/4 - y/100 + y/400 + C) % 7ですが、
y/4の値を加算しているのは、4で割れるのが何回あったかで、その回数日分
増えいるからですか。
y/100の値を減算していのは、100で割れた場合はうるう年とみないので、
その回数日数分が余分なのでひいているからですか。
y/400の値を加算しているのは、400で割れるのが何回あったかで、その回数
日分増えいるからですか。




No.2397

Re:日付から曜日を求める方法で言っている定数
投稿者---かずま(2002/08/15 11:17:49)


> y=2000のとき、w=5なのですか。?
> w = y % 7 にあてはめると、w=7だと思うのですが。

2000 を 7 で割って余りを求めるという計算ができないのですね。

No.2399

Re:日付から曜日を求める方法で言っている定数
投稿者---正従量(2002/08/15 18:41:01)


>> y=2000のとき、w=5なのですか。?
>> w = y % 7 にあてはめると、w=7だと思うのですが。
>
>2000 を 7 で割って余りを求めるという計算ができないのですね。
2000を7で割ると、285.714・・・になりますね。
あまりは、7ですね。
う5とはどこから。

No.2401

Re:日付から曜日を求める方法で言っている定数
投稿者---TDa(2002/08/15 19:01:42)


>2000を7で割ると、285.714・・・になりますね。
>あまりは、7ですね。
>う5とはどこから。

中学生レベルじゃなくて小学生の算数を勉強し直してください。
2000 ÷ 7 = 商285 余り5

だいたい何で7で割って余り7なの?
ふざけているだけですか?


No.2409

Re:日付から曜日を求める方法で言っている定数
投稿者---とおりすがり(2002/08/17 11:20:15)


>>2000を7で割ると、285.714・・・になりますね。
>>あまりは、7ですね。
>>う5とはどこから。
>
>中学生レベルじゃなくて小学生の算数を勉強し直してください。
>2000 ÷ 7 = 商285 余り5
>
>だいたい何で7で割って余り7なの?
>ふざけているだけですか?

たしかにふざけているととられてもおかしくないでね。
2000 ÷ 7 = 285.71428 は電卓で計算したのではないかと思います。
だから、余りが合わないといっているのではないでしょうか。
算数とC言語の割算とか余りの考え方は違いますからね。
それも知らずに質問しているとは思えませんが。それじゃないと....
質問するまえに、このサイトで勉強してからの方がいいと思います。
かまずさんみたいに親切に答えてくくれるばかりではなりませんから。
また、お礼は必ずしよう。



No.2417

Re:日付から曜日を求める方法で言っている定数
投稿者---長月葵(2002/08/19 01:11:25)


>たしかにふざけているととられてもおかしくないでね。
>2000 ÷ 7 = 285.71428 は電卓で計算したのではないかと思います。
>だから、余りが合わないといっているのではないでしょうか。
>算数とC言語の割算とか余りの考え方は違いますからね。
>それも知らずに質問しているとは思えませんが。それじゃないと....

えと、すみません、ここで言う算数の除算とは商と乗余を求める物ですよね?
もし小数点以下まで計算する物をおっしゃっているなら、算数の除算とC言語の除算にどういう違いがあるかお教えいただけませんか?
後者の場合知らないとはまりそうで不安です(汗)

No.2377

こういう方法も。
投稿者---小生(2002/08/14 01:01:19)


ここで、書かれている方法の他に、

if (month == 1 || month == 2) {
year--;
month += 12;
}
return (year + year/4 - year/100 + year/400 + (13*month+8)/5 + day) % 7;

の方法もあったのですが、
曜日を求めている式の解釈がわかりません。
お願いします。

No.2379

Re:こういう方法も。
投稿者---TDa(2002/08/14 01:45:41)


>ここで、書かれている方法の他に、

ほかじゃなくて全く同等です。ツェラーの公式です。