awk で epoch time を YYYY/MM/DD HH:MM:SS に変換する

最近 JavaScript を使っていると awk に比較的近いため、今後の教育用言語は JavaScript に移っていくのではないかと思ったりしています。 awk は gawk になるまで日付関係の関数が用意されていなかったわけですが、そう考えるとJavaScriptでepoch timeをYYYY/MM/DD HH:MM:SSに変換するに書かれているもので十分ではないでしょうか。 もっとも、最近の gawk は strftime() 関数が用意されていますので、非常に簡単に求めることができます。

そこで、ここでは gawk の strftime() 関数を用いたものと、nawk, mawk などでも使える srand() の戻り値から Epoch 時間を求め、そこから計算させるものと両者で求めます。 後者は nawk で時刻取得に一度掲載したものを少し修正しています。

#! /usr/bin/gawk -f
# epocktime2readable.awk

BEGIN {
    epoch_time = systime();

    # gawk の場合
    print strftime("%Y/%m/%d %H:%M:%S");

    # nawk, mawk の場合
    print get_time();
}

# get_time() - get time and date
function get_time() {

    # set Time Zone
    split(ENVIRON["TZ"], arr_tz, /[-+]/);
    time_zone = arr_tz[2] * 3600;

    # set short name of week
    split("Sun Mon Tue Wed Thu Fri Sat", week_name, " ");
    # set short name of month
    split("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec", month_name, " ");
    # set length of month
    split("31 28 31 30 31 30 31 31 30 31 30 31 31 29 31 30 31 30 31 31 30 31 30 31",
          month_length, " ");

    # get elapsed seconds from epoc time
    srand();
    system_time = srand() + time_zone;

    second   = system_time % 60;
    minute   = int(system_time / 60) % 60;
    hour     = int(system_time / 3600) % 24;
    day      = int(system_time / (3600 * 24));
    week_num = (day + 4) % 7 + 1;

    year     = 1970;                    # initial year

    for (++day;;) {

        # check leap year
        if ((year % 4) == 0 && (year % 100) != 0 || (year % 400) == 0) {
            leap = 12;
        } else {
            leap = 0;
        }

        # set days of the year
        if (leap != 0) {
            year_days = 366;
        } else {
            year_days = 365;
        }

        if (day < year_days) {
            break;
        }

        ++year;
        day -= year_days;
    }

    for (month = 1; month_length[month + leap] + 0 <= day + 0; ++month) {
        day -= month_length[month + leap];
    }

    return sprintf("%04d/%02d/%02d %02d:%02d:%02d",
                    year, month, day, hour, minute, second);
}

実行してみましょう。

$ gawk -f epocktime2readable.awk
2008/10/11 23:19:08
2008/10/11 23:19:08

当然ですが、同じ値が取得できました。 もちろん、タイミングによっては 1 秒ほど狂ってしまうケースがあります。

tag_nawk.pngtag_nawk.pngtag_nawk.pngtag_nawk.png