6

Cには、time()関数によって返される時間を特定のタイムゾーンに変換するAPIがありますか?strftime()システムの現在のタイムゾーンに変換する機能があります。しかし、私が欲しいのは、関数入力は時間(によって返されるtime())とtimeZoneであり、特定のフォーマットされた時間を上記のタイムゾーン形式に変換します。

そのようなAPIはありますか?

4

2 に答える 2

7

POSIX では次のように指定されていますtzset()

このtzset()関数は、環境変数 TZ の値を使用して、 、 、 、および で使用される時間変換情報をctime設定localtimemktimeますstrftime。TZ が環境に存在しない場合、実装定義のデフォルトのタイムゾーン情報が使用されます。

したがって、理論的には、次のようなものを使用してt0(a time_t) を米国/東部時間に変換することができますが、それがデフォルトの TZ ではありません。

char old_tz[64];
strcpy(old_tz, getenv("TZ"));
setenv("TZ", "EST5", 1);
tzset();
struct tm *lt = localtime(&t0);
char buffer[64];
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", lt);
setenv("TZ", old_tz, 1);
tzset();

これにより、古いタイム ゾーンのコピーが保持され (このような作業を行っているときに変更されたり範囲外になったりすることはありません)、環境にターゲット タイム ゾーンが設定されます。次に、システムに $TZ を見て、それに応じてローカル タイム ゾーンを設定するように指示します。次に、指定time_tされた値を で分割されたローカル時間localtime()に変換し、文字列をフォーマットしてから、TZ 環境変数をリセットし、もう一度 でもう一度調べるようにシステムに指示しますtzset()

実際には、これは機能する場合と機能しない場合があります。それはシステムに依存します。

このようなもののスレッド セーフ バージョンが必要な場合は、より多くの作業を行う必要があります。書かれているように、これは断固としてスレッドセーフではありません。

サンプル コードでは、エラー チェックが省略されています。エラー チェックはありません。

これが簡単な方法だとは決して言いません。もっと良い方法があるはずです。

テストコード

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

static void time_convert(time_t t0, char const *tz_value)
{
    char old_tz[64];
    strcpy(old_tz, getenv("TZ"));
    setenv("TZ", tz_value, 1);
    tzset();
    char new_tz[64];
    strcpy(new_tz, getenv("TZ"));
    char buffer[64];
    struct tm *lt = localtime(&t0);
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", lt);
    setenv("TZ", old_tz, 1);
    tzset();
    printf("%ld = %s (TZ=%s)\n", (long)t0, buffer, new_tz);
}

int main(void)
{
    time_t t0 = time(0);
    char *tz = getenv("TZ");
    time_convert(t0, tz);
    time_convert(t0, "UTC0");
    time_convert(t0, "IST-5:30");
    time_convert(t0, "EST5");
    time_convert(t0, "EST5EDT");
    time_convert(t0, "PST8");
    time_convert(t0, "PST8PDT");
}

テスト出力

1335761328 = 2012-04-29 23:48:48 (TZ=CST6CDT)
1335761328 = 2012-04-30 04:48:48 (TZ=UTC0)
1335761328 = 2012-04-30 10:18:48 (TZ=IST-5:30)
1335761328 = 2012-04-29 23:48:48 (TZ=EST5)
1335761328 = 2012-04-30 00:48:48 (TZ=EST5EDT)
1335761328 = 2012-04-29 20:48:48 (TZ=PST8)
1335761328 = 2012-04-29 21:48:48 (TZ=PST8PDT)

EST および PST の文字列に夏時間コードが指定されていない場合は、1 つのタイム ゾーン オフセットが取得されることに注意してください。夏時間コード セット ("EST5EDT"または など"PST8PDT") があり、印刷される時刻が適切な時期 (4 月末など) である場合、EDT または PDT 時刻値が印刷されます。

また、タイム ゾーンの処理方法については ISO 規格が競合していることにも注意してください。ISO 8601 (日付/時刻の書式設定用) では、UTC (グリニッジ) より東のタイム ゾーンは正であり、UTC より西のタイム ゾーンは負であると規定されています。少なくとも他の標準 (SQL、ISO 9075 など) のいくつかは、同じ表記法を使用しています。一方、POSIX (別名 ISO 9945) は、コード例に示すように、TZ で反対の規則を使用します。紛争は、長年の前例があるという理由だけで受け入れられます。C 標準は、TZ 環境変数の形式 (または存在) について言及していません(strftimeただし、C99 §7.23.3.5関数は ISO 8601 を何度も参照しています)。

そして (なぜエラーチェックが良いアイデアなのかを思い出させるための念のため)、Mac OS X 10.7.3 では、私の環境には TZ が設定されていません (ただし、通常は US/Pacific、別名 Cupertino、別名 America/Los_Angeles です) 、 時間)。そのため、上記のコードgetenv()は null ポインターを返すとクラッシュします。TZ=CST6CDT出力の最初の行からわかるように、環境で実行しました。

于 2012-04-30T04:29:44.870 に答える
0

ここには、実際に 3 つのステップがあります。まず、 atime_tは絶対タイムスタンプを表します。少なくとも概念的には UTC タイムスタンプの順序です。(通常は) 特定のタイム ゾーンではありません。通常、あるエポック (多くの場合、1970 年 1 月 1 日の真夜中) からの秒数を表します。

これを に変換すると、struct tmそのタイム スタンプが実際の日付と時刻 (年、月、日、時、分、秒) に分割されます。この変換を行う関数が 2 つあります。 はgmtime、UTC スタイルの時刻 (つまり、グリニッジ タイム ゾーン) のままにします。もう 1 つはlocaltimeで、マシンの場所を表すように環境が構成されているタイム ゾーンに変換します。

次のステップは、strftimeそれを読み取り可能なものに変換するために使用することです。これは現在のロケールに基づいているため、(たとえば) これを書いているときは、「日曜日」と考えています。ただし、私のマシンがスペイン語用に構成されている場合、おそらく「Domingo」またはその順序で表示されます。

あなたは本当に2つのかなり異なる質問をしています。を 2 つのタイム ゾーンのいずれかの時間にのみ変換できtime_tます。「ローカル」タイム ゾーン (少なくとも、マシンが「ローカル」と見なすように構成されているものは何でも)、またはグリニッジ時間です。他のタイムゾーンが必要な場合は、GM 時間に変換してから、選択したタイムゾーンに調整するなどの方法でほとんど行き詰まっています。

フォーマットを調整するためのより多くの規定があります。デフォルトでは、ライブラリは常に "C" ロケールに変換されます。これは、米国英語のかなり簡略化されたバージョンです。また、名前のないロケール ("") を設定することもできます。これにより、マシンの構成方法に一致すると思われるロケールが得られます。3 番目の方法として、ほとんどのライブラリでは特定のロケールの名前を指定できます。そのため、カナダのフランス語圏の誰かが期待するように日付をフォーマットしたい場合は、ロケールを「French_Canada」のようなものに設定します。それが得られるものです(ただし、使用する文字列は標準ライブラリによって異なるため、代わりに「fr-can」などを使用する必要がある場合があります)。

于 2012-04-30T04:13:49.723 に答える