#pragma twice

KAB-studio > プログラミング > #pragma twice > 259 Version 13.23 日時の取得

#pragma twice 259 Version 13.23 日時の取得

前のページへ 表紙・目次へ 次のページへ

 Version 13.23
日時の取得

今回は、おさらいも含めて、日時の取得について見ていきます
一度 Version 7.20 ( No.140 ) でやったんだもんね
あのときはとりあえずの説明だったからね。アルゴリズムに使う場合には
とりあえずじゃまずいから
はーい
でもとりあえずはとりあえず

void OutputDate()
{
    // まずはのべ秒を取得。
    time_t lTime_t;
    time( &lTime_t );
    TRACE( "%u秒\n", lTime_t );
    // 1083123673秒

    // 次にローカル時間に変換します。
    tm *pstTm;
    pstTm = localtime( &lTime_t );
    TRACE
        ( "%d年%d月%d日%d曜日%d時%d分%d秒\n"
        , pstTm->tm_year
        , pstTm->tm_mon
        , pstTm->tm_mday
        , pstTm->tm_wday
        , pstTm->tm_hour
        , pstTm->tm_min
        , pstTm->tm_sec
        );
    // 104年4月6日4曜日12時52分36秒

    // 再変換します。
    time_t lTime_t2;
    lTime_t2 = mktime( pstTm );
    TRACE( "%u秒\n", lTime_t2 );
    // 1083123934秒
}

ランタイムで時間取ってくるのね
一番手軽で標準的だからね。まず

    time_t lTime_t;
    time( &lTime_t );

この time() 関数で、世界標準時の1970年1月1日0時0分0秒から
現在時刻までの【のべ秒】を取得します
のべ秒って微妙に不思議……
基本的には、日時はこののべ秒で扱った方がいいから。計算や比較が簡単
だし、最初に取得するのはこれだしね
なにわともあれ基本中の基本ってとこね
でも、これは世界標準時だし、秒だし、というわけで全然使えません。そ
こで、年月日時分秒に変換します

    tm *pstTm;
    pstTm = localtime( &lTime_t );

またランタイムね
 localtime() はその地域の日時、わかりやすく言うと日本の日時を取得
するランタイムです
ってことは、外国の日時も取得できるの?
一応ね。 _tzset() っていうラインタイムや SetTimeZoneInformation()
っていう API を使わなきゃいけないんで少し面倒だけど。あと、標準時が
取得した場合には gmtime() を使えばいいから
でもたぶん使わないね……
それと重要なこと。この関数、他のとちょっと違うところない?
違うところ……
戻り値とか
戻り値、構造体のポインタ……? ポインタが戻り値って変くない? 普
通ポインタ返したら free() で解放したりとかしなきゃいけないとか、もう
使えなくなってるとか
そう、実は localtime() は tm 構造体の変数をひとつ持っていて、その
ポインタを常に返してるんです

ようするに、何度呼んでも同じポインタが返ってくるってこと

    tm *pstTm;
    pstTm = localtime( &lTime_t );
    TRACE( "%X\n", pstTm );
    // 422250
    tm *pstTm2;
    pstTm2 = localtime( &lTime_t );
    TRACE( "%X\n", pstTm2 );
    // 422250

あ、アドレスが同じだ
つまり同じ変数のポインタを返してるってことです。これはとても重要。
この例で、1度目の localtime() と2度目の localtime() の間に time()
を呼んで lTime_t を変えていたら?
んー、 pstTm と pstTm2 の中身って変わるよね……?? でも、このふ
たつはポインタは同じだから、同じ変数が変えられる……???
そう、同じ変数が変えられるから、見た目的には pstTm の中身が勝手に
変えられちゃうことになるんです
げ!
だから、もし前に取得した localtime() の戻り値をずっと使いたい場合
には、別に tm 構造体の変数を作って、そこにコピーする必要があります
めんどい……
確かにね。引数で tm 構造体のポインタ受けるようにすればいいだけなん
だけどね。ランタイムは設計が古いから
うー
さて、 localtime() にはまだまだ問題があります。まずは中の数値

    TRACE
        ( "%d年%d月%d日%d曜日%d時%d分%d秒\n"
        , pstTm->tm_year
        , pstTm->tm_mon
        , pstTm->tm_mday
        , pstTm->tm_wday
        , pstTm->tm_hour
        , pstTm->tm_min
        , pstTm->tm_sec
        );
    // 104年4月6日4曜日12時52分36秒

これは 2004 年 5 月 6 日 12 時 52 分 36 秒に実行した結果です
まず年が違うね
この年は、西暦4桁の年から 1900 を引いた数
なんでわざわざ?
たぶん昔は型が小さかったんじゃないかな、 unsigned char とか
そか、それだと 2004 は入らないね
昔はコンピューターの性能が悪かったから、そういうところで切りつめら
れてたからね。月も同じような理由も含まれてるかな
月? あ、この前言ってたね、1ヶ月ずれてるんだよね
そう、1月は 0 、12月は 11 
そのまま使うとずれちゃう……
この月で〈1月のみの処理〉とかしたり、あとファイルや画面、エディッ
トボックスとかの入出力に使うと問題になるから
どうすればいいの?
変換用の関数や比較用の関数を使ったり

    const int JANUARY = 0;
    const int FEBRUARY = 1;
//...
    const int DECEMBER = 11;

みたいに定数値を用意しておいてそれで比較したり
これはわかりやすいね
あと同じく曜日もこういうふうに定義しておいた方がいいかも
うわ、なんか数字が出てる……
文字列変換には strftime() っていうランタイムがあるからそれを使うの
もいいかも

    setlocale( LC_ALL, "japanese" );
    char pchTime[256];
    strftime
        ( pchTime
        , 255
        , "%Y年%#m月%#d日%a曜日%H時%M分%S秒"
        , pstTm 
        );
    TRACE( "%s\n", pchTime );
    // 2004年5月6日木曜日12時52分36秒

おおっ! これはかなりちゃんとしてるね
年のちゃんとした西暦表示、月の +1 、曜日の漢字表示をしてくれるから
 %Y が年、 %#m が月…… printf() に似てるね
仕組みは同じだから、使いやすいと思うよ。ちなみに # は、これを付け
ると余分な 0 を取ってくれます
余分なゼロ?
たとえば、この例だと "%m月" って書いたら "05月" ってなります
あ、 # を付けなければ自動的に 0 入れてるくれるんだ
そういうこと。プログラム上でどちらがいいか判断して変えてください
はーい。あ、あと、 setlocale() ってなに?
これは、 strftime() の表記方法を変えるランタイム。これがないと
あ、木曜日が Thu になった
こうやって指定すれば日本語バージョンで表示されるから
曜日とか英語だとかなりめんどいものね……
さて、こうやって文字列化したものをまた tm 構造体に戻す場合、簡単な
方法はありません
やっぱ、ひとつずつ見ていって、 sscanf() とかで int に変換しなきゃ
いけないの?
それしかないんだけど、そのためには表記方法が統一されてないと

つまり、 "2004年5月6日" か "2004/5/6/" か "2004-5-6" とか
うわ、そっか、書き方っていっぱいあるんだ
全ての表記方法に対応することは不可能だから、どれかひとつだけ受け取
るような感じかな
受け取る?
そう、それも重要かな。たとえばダイアログで日時を受け取る場合には、
こういう自由に書けるような形じゃなくて、年、月、日、それぞれエディッ
トボックスを分けて入力してもらうのが楽
インターネットとかでも普通そうだよね
〈日時の文〉を元に日時を抜き出す、っていう処理はできる限り避けた方
がいいよ、ものすごくちゃんと詰めないとうまくいかないから
だよね……区切りもそうだし、 0 が入ってるかとか、スペースとか……
さて、今のは文字列から tm 構造体への変換の話だったけど、 tm 構造体
から〈のべ秒〉への変換は簡単にできます

    // 再変換します。
    time_t lTime_t2;
    lTime_t2 = mktime( pstTm );
    TRACE( "%u秒\n", lTime_t2 );
    // 1083123934秒

お、ホントだ
これはとても重要。 tm 構造体は文字列への変換や年月日時分秒単位の処
理には向いているんだけど、比較や計算には向いてないから
? 月の比較なら pstTm->tm_mon を比較、じゃいけないの?
そりゃ本当に月だけ比較するならいいけど……普通は日時全体で比較する
から、月の比較の前に年の比較をしないと
あ、年を比較して、そのあと月を……そか、ちゃんと比較するならそう
やって順番に全部の桁比較しなきゃいけないんだ。面倒……
だから秒に変換して比較するわけ
そっか! 秒に変換しちゃえばそれだけで比較できちゃうんだから
というわけで次回はその方法について説明します

/*
    Preview Next Story!
*/
なんか、細かいノウハウが多いね
日時関係はちょっと間違えると全然結果が違うからね
そういうのって怖いね
だからそう言ってるでしょ
はい……
というわけで次回
< Version 13.24 日時の作成 >
につづく!
次回もそういう注意点満載です
でもちょっと胃が痛くなる……
プログラミングっていうのはそういうもの
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。