C言語関係掲示板

過去ログ

No.1323 通算日から日付を取得

[戻る] [ホームページ]
No.17836

通算日から日付を取得
投稿者---7(2004/11/07 00:16:02)


こんばんは。今2004年の通算日が何月何日何曜日であるかという
プログラムを作っています。
まず、int c[]={31,29,31,30,31,30,31,31,30,31,30,31};のように
各月の日数を配列に格納しておきます。
そして、通算日を取得し、表示するというものです。
曜日などはやり方は思いついているのですが、何日であるかを得る方法が
うまくいきません。

私はscanfで int aを取得したとき、
a -= c[i];
i++;
でaが0以上の時はループさせようとしました。

たとえば、通算日が32日であれば、2月1日(日)を得ることができる
プログラムです。


No.17837

Re:通算日から日付を取得
投稿者---PSB(2004/11/07 00:42:26)


>私はscanfで int aを取得したとき、
>a -= c[i];
>i++;
>でaが0以上の時はループさせようとしました。

それでいいと思いますが。aが負の値になった後に直前に引いた値を
足せば月日は出ますよね。


No.17838

Re:通算日から日付を取得
投稿者---YuO(2004/11/07 01:07:26)


>こんばんは。今2004年の通算日が何月何日何曜日であるかという
>プログラムを作っています。

localtimeとmktime使えば簡単に取得できます。

const struct tm * yday_to_tm (int year, int yday)
{
    struct tm tmYday = { 0 };
    time_t timeYday;

    tmYday.tm_year = year - 1900;
    tmYday.tm_day = yday;

    timeYday = mktime(&tmYday);
    return localtime(&timeYday);
}

#夏時間を考慮していないので,場合によっては日付がずれるかも……。



No.17839

Re:通算日から日付を取得
投稿者---かずま(2004/11/07 02:00:34)


>   tmYday.tm_day = yday;

    tmYday.tm_mday = yday;

の間違いでしょう。



No.17840

Re:通算日から日付を取得
投稿者---rvrdriver(2004/11/07 14:26:51)


tm_ydayはmktimeの変換では無視されるので求めるとしたら、
1.tm構造体のメンバに2004年1月1日を設定
2.mktimeで2004年1月1日を暦時刻に変換
3.暦時刻に変換した値に通算秒(通算日を秒に変換)を
  加算
4.localtimeで時刻を求める

struct tm *yday_to_tm (int year, int yday)
{
    struct tm tmYday = { 0 };
    time_t timeYday;

    tmYday.tm_year = year - 1900;
    tmYday.tm_mon = 0;
    tmYday.tm_mday = 1;
    tmYday.tm_isdst = -1;

    timeYday = mktime(&tmYday);
    timeYday += (yday * 3600 * 24);
    
    return localtime(&timeYday);
}



夏時間を考慮に入れたい場合はtm_isdstをセットする必要があります。
unixの場合は-1をセットするとmktimeで夏時間を考慮した暦時刻に
変換されますが他の環境ではわかりません。

また、3600や24のマジックナンバーは#defineしたほうがいいですね。



No.17841

Re:通算日から日付を取得
投稿者---nop(2004/11/07 15:49:48)


>tm_ydayはmktimeの変換では無視されるので求めるとしたら、

tm_ydayではなくtm_mdayなので問題ないでしょう。


No.17842

Re:通算日から日付を取得
投稿者---rvrdriver(2004/11/07 16:35:00)


>tm_ydayではなくtm_mdayなので問題ないでしょう。

JIS X 3010 7.23.2.3 mktime 関数には、
構造体のtm_wday 要素及びtm_yday 要素の元の値は無視
すると記載されていますし、実際YuOさんのコードを
実行しても求められませんでした。

RedhatLinux9、gcc
WinXP、bcc

両方の環境で試しましたが求められませんでした。
nopさんはどのような環境で試されましたか?



No.17843

Re:通算日から日付を取得
投稿者---nop(2004/11/07 17:15:17)


>JIS X 3010 7.23.2.3 mktime 関数には、
>構造体のtm_wday 要素及びtm_yday 要素の元の値は無視
>すると記載されていますし、

「tm_wday」でも「tm_yday」でもなく「tm_mday」ですって…。

# tm_wday … 曜日
# tm_yday … 年初からの通算日数
# tm_mday … 日
#
# 読み変えると
#  「曜日」でも「年初からの通算日数」でもなく「日」



No.17845

Re:通算日から日付を取得
投稿者---rvrdriver(2004/11/07 17:47:36)


>「tm_wday」でも「tm_yday」でもなく「tm_mday」ですって…。

この根拠となるものは何でしょうか?
JIS X 3010(ANSI Cの日本語訳)よりもっと信頼性のある情報である
としたら大変興味ありますので教えてください。
或いはmktimeの項の誤訳であるということでしょうか?

また、先ほど質問しましたが動作確認はされてますか?

>
># tm_wday … 曜日
># tm_yday … 年初からの通算日数
># tm_mday … 日
>#
># 読み変えると
>#  「曜日」でも「年初からの通算日数」でもなく「日」

これはtm構造体の内容でmktimeの仕様を推定しているのでしょうか?
何を読み変えているのか良くわかりません。

質問ばっかりになってしまってすみません。



No.17846

Re:通算日から日付を取得
投稿者---かずま(2004/11/07 18:12:53)


> この根拠となるものは何でしょうか?
> JIS X 3010(ANSI Cの日本語訳)よりもっと信頼性のある情報である
> としたら大変興味ありますので教えてください。
> 或いはmktimeの項の誤訳であるということでしょうか?

JIS X 3010 の次の記述を読み落としていませんか?

: 構造体の tm_wday要素及び tm_yday要素の元の値は無視し,
: その他の要素の元の値は, 7.23.1 に示した値の範囲内でなくてもよい。
: 正常に動作が完了した場合, 構造体の tm_wday要素及び tm_yday要素の
: 値を適切に設定し, 他の要素は指定された暦時刻を表すように設定するが,
: それらの値は, 7.23.1 で示した範囲に強制的に設定する。

tm_mday は 1〜31 の範囲であるが、範囲外の 312 を指定して、
2004年 1月 312日を渡すと、2004年 11月 7日に強制的に設定されると
いうことです。


No.17847

Re:通算日から日付を取得
投稿者---rvrdriver(2004/11/07 18:29:56)


>tm_mday は 1〜31 の範囲であるが、範囲外の 312 を指定して、
>2004年 1月 312日を渡すと、2004年 11月 7日に強制的に設定されると
>いうことです。

すみません。自分の見落とし&勘違いでした。
ご指摘のとおり、規格を見落としていました。

また、最初にコンパイルができず、tm_dayを勘違いして
tm_ydayに書き換えていたのが原因でした。
皆さんがいっているとおりtm_mdayにすれば問題なく動作します。

いろいろお手数おかけしました。



No.17844

Re:通算日から日付を取得
投稿者---かずま(2004/11/07 17:38:46)


> 実際YuOさんのコードを実行しても求められませんでした。

YuOさんのコードは、struct tm にはない tm_day と書いているので
実行できません。tm_mday の間違いです。localtime も不要です。
#include <stdio.h>
#include <time.h>

int main(void)
{
    int yday;

    while (scanf("%d", &yday) == 1) {
        struct tm t = { 0 };
        t.tm_year = 2004 - 1900;
        t.tm_mday = yday;
        mktime(&t);
        printf("%d/%02d/%02d(%.3s)\n", t.tm_year+1900, t.tm_mon+1,
                t.tm_mday, "SunMonTueWedThuFriSat" + t.tm_wday*3);
    }
    return 0;
}