4

外部プログラム (制御できない) によって記録されたデータ ファイルを解析するアプリケーションを C で作成しています。バイナリ データを格納します。その 1 つのフィールドは、標準 UNIX の「エポック」形式 (UTC の 1970 年 1 月 1 日からの秒数) の時間です。

もう 1 つのフィールドはタイムゾーンで、UTC からの秒単位のオフセットとして保存されます。

いいですね、記録されたタイムゾーンでその情報を表す日付/時刻文字列を作成するために必要なものはすべて揃っていますよね? うーん...そうではないようです、および/またはそれを行う方法がわかりません。

私はかなり単純なテストケースに物事を煮詰めました:

#include <stdio.h>
#include <time.h>

int main(void)
{
    time_t t;
    struct tm *tm;
    char buf[BUFSIZ];

    int offset = 4980; /* slightly bizarre, just to test this - an hour
                        * and 23 minutes ahead of UTC */

    t = time(NULL);
    tm = localtime(&t);

    strftime(buf, BUFSIZ, "%FT%T%z", tm);
    printf("before: %s\n", buf);

    /* since we're not telling localtime anything different,
     * compensate here (by subtracting applied offset, and adding
     * desired one): */
    t += offset - tm->tm_gmtoff;
    tm = localtime(&t);

    tm->tm_zone = "XYZ"; // not used -- but it was in an earlier version
    tm->tm_gmtoff = offset;

    // on macos, I used to also have %+, which referenced tm_zone
    strftime(buf, BUFSIZ, "%FT%T%z", tm);
    printf("after:  %s\n", buf);

    return 0;
}

これを MacOS X 10.6 で実行すると、次のようになります。

before: 2011-02-23T00:53:04-0800
after:  2011-02-23T10:16:04-0800

私が期待する(そして実際にLinuxボックスで得られる)のは次のとおりです。

before: 2011-02-23T00:53:04-0800
after:  2011-02-23T10:16:04+0123

TZ環境変数を変更する必要がありますか (おそらく を呼び出しますtzset)? データ構造を操作して正しいものを取得する方法があるはずですが、上記は確かに機能していません (とにかく MacOS X 10.6 では -- Linux ではうまく機能します)。

回避策として、フォーマット文字列から %z を削除して、その部分を自分で作成できると思います。

ただし、理想的には、 my の変更struct tm、または使用できる他の関数呼び出し (strftime のように、追加のパラメーターまたは何か、または代わりに localtime の代替形式を使用) のいずれかが必要です。物事を正しく行う。

Linux は動作しているように見えるので (それでも、上記の解決策は理想的ではありません。なぜなら、私は自分のtime_t値をstruct tmごまかしているからです。 MacOSに対するバグとして?

あるいは、サードパーティ (GNU 関係者の何か、私が想像している) ライブラリが必要になったとしても、呼び出すことができるライブラリ ルーチンの別のセットはありますか? ObjC または C++ のオプションを検討しますが、私は C のままにしたいと思います。

4

3 に答える 3

3

mktime()値を変更する代わりに使用することを好みtime_tます。ただし、これはTZ(ソリューションと同様に) オフセットを適用するlocaltime()ため、mkgmtime()実装が必要です。

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

static void set_timezone(char *tz)
{
  static char var[1024];

  snprintf(var, sizeof(var), "TZ=%s", tz);
  putenv(var);
  tzset();
}

static time_t mkgmtime(struct tm *tm)
{
  char var[1024];
  time_t t;

  snprintf(var, sizeof(var), "%s", getenv("TZ") ? getenv("TZ") : "");

  set_timezone("GMT0");

  t = mktime(tm);

  set_timezone(var);

  return t;
}

int main(void)
{
  time_t t;
  struct tm tm;
  char buf[BUFSIZ];
  int offset = 4980; /* slightly bizarre, just to test this - an hour
                      * and 23 minutes ahead of UTC */

  t = time(NULL);
  tm = *localtime(&t);
  strftime(buf, BUFSIZ, "%FT%T%z", &tm);
  printf("before: %s\n", buf);

  tm = *gmtime(&t);
  tm.tm_sec += offset;
  mkgmtime(&tm);

  strftime(buf, BUFSIZ, "%FT%T%z", &tm);
  printf("after:  %s\n", buf);

  return 0;
}
于 2011-02-25T14:03:19.407 に答える
0

最善のアプローチは

  1. time_t値を変数に読み込みます。

  2. これらのガイドラインに従って TZ 環境変数を設定します。TZ の指定方法については、このページも参照してください。

  3. 呼び出すlocaltime()

MacOS プラットフォームでテストすることはできませんが、これは動作することが保証されています。

于 2011-02-23T09:57:58.513 に答える
-1

個人的には、bash コードに小さな Python スクリプトを埋め込むのが好きです。Python には、必要な機能のために、すぐに使用できる強力なライブラリが多数あります。

次のように、Python コードを bash スクリプトに埋め込むことができます(Python がインストールされていると仮定します) 。

python << END
from pytz import timezone    

south_africa = timezone('Africa/Johannesburg')
sa_time = datetime.now(south_africa)
print sa_time.strftime('%Y-%m-%d_%H-%M-%S')
END

異なるタイムゾーンで表示したい場合は、タイムゾーン設定を変更できます。詳細については、http://pytz.sourceforge.net/をご覧ください。

于 2012-10-02T16:19:49.397 に答える