1

C++ を使用して別のタイムゾーン (PST) で時刻を取得しようとしています。

#define PST (-8);
char* Time::getSecondSystemTime() {
    time_t rawtime;
    struct tm * timeinfo;
    char buffer[80];

    time(&rawtime);
    timeinfo = gmtime(&rawtime);

    timeinfo->tm_hour = timeinfo->tm_hour + PST;

    strftime(buffer, 80, "%I:%M %p", timeinfo);


    std::string temp = std::string(buffer); // to get rid of extra stuff
    std::string extraInfo = " Pacific Time ( US & Canada )";

    temp.append(extraInfo);

    return (char*) (temp.c_str());

}

ここでの問題は、GMT 時間が 8 時間未満の場合 (たとえば、現在午前 3 時)、そこから 8 時間を減算しても機能しないことです!

Unixで別のタイムゾーンの時間を取得する適切な方法は何ですか?

4

3 に答える 3

6

「UNIX」と言ったので、これはTZを使用TZ=[what goes here]しますが、システムで[ここに何が入るか]を調べる必要があります。「America/LosAngeles」またはPSTの他のいくつかの文字列の1つである可能性があります。システムがPOSIXの場合:TZ=PST8PSTが機能することが保証されています。しかし、それは最適ではないかもしれません。

プリミティブな非実動コードは、TZが現在使用されていないことを前提としています。タグがCであったため、これはCであり、C++ではありません。

setenv("TZ", "PST8PST", 1);   // set TZ
tzset();                // recognize TZ
time_t lt=time(NULL);   //epoch seconds
struct tm *p=localtime(&lt); // get local time struct tm
char tmp[80]={0x0};
strftime(tmp, 80, "%c", p);  // format time use format string, %c 
printf("time and date PST: %s\n", tmp); // display time and date
// you may or may not want to remove the TZ variable at this point.
于 2012-12-27T04:16:00.173 に答える
4

この問題に対処するために、次の C コードを隠しておきました。効率という言葉が最初に頭に浮かぶわけではありませんが ( への 2 回の呼び出し、 へsetenv()の 2 回の呼び出しtzset())、標準の C ライブラリでは効率を向上させることは容易ではありません。

#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");
}

元のコードでは、時間オフセットを変更した後の時間構造の正規化について心配する必要があります。関数でそれを行うことができますmktime()。問題の関数に基づくプログラムを次に示します。これは純粋な C であり、ローカル変数へのポインターを返す問題 (および#defineセミコロンで終わる問題) を回避します。

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

#define PST (-8)

extern int getSecondSystemTime(char *buffer, size_t buflen);

int getSecondSystemTime(char *buffer, size_t buflen)
{
    time_t rawtime = time(0);;
    struct tm *timeinfo;
    char t_buff[32];

    timeinfo = gmtime(&rawtime);
    timeinfo->tm_hour = timeinfo->tm_hour + PST;

    time_t pst_time = mktime(timeinfo);
    assert(pst_time != (time_t)-1);
    int len = strftime(t_buff, sizeof(t_buff), "%Y-%m-%d %H:%M:%S", timeinfo);
    assert(len != 0);

    int rv = snprintf(buffer, buflen, "%ld = %s (%s)", (long)rawtime, t_buff, 
                      "Pacific Time (US & Canada)");
    assert(rv > 0);
    return rv;
}

int main(void)
{
    char buffer[128];

    getSecondSystemTime(buffer, sizeof(buffer));
    printf("%s\n", buffer);
    return(0);
}

明らかに、より優れたインターフェイスでは、UTC 時間の値とタイム ゾーン オフセット (時間と分) を引数として渡します。私のコンピューターはデフォルトで米国/太平洋 (またはアメリカ/ロサンゼルス) タイム ゾーンで動作しているにもかかわらず、TZ をさまざまな値 (米国/東部、IST-05:30 を含む) に設定してテストし、正しい値を取得しました。過去の経験から、計算が正しいと確信しています。

-1返された frommktime()がエラーのためなのか、変換された時間が に対応するためなのかを分析しようとする別のプログラムがあり(time_t)-1ます。

/* Attempt to determine whether time is really 1969-12-31 23:59:59 +00:00 */
static int unix_epoch_minus_one(const struct tm *lt)
{
    printf("tm_sec = %d\n", lt->tm_sec);
    if (lt->tm_sec != 59)
        return(0);
    printf("tm_min = %d\n", lt->tm_min);
    /* Accounts for time zones such as Newfoundland (-04:30), India (+05:30) and Nepal (+05:45) */
    if (lt->tm_min % 15 != 14)
        return(0);
    /* Years minus 1900 */
    printf("tm_year = %d\n", lt->tm_year);
    if (lt->tm_year != 69 && lt->tm_year != 70)
        return(0);
    printf("tm_mday = %d\n", lt->tm_mday);
    if (lt->tm_mday != 31 && lt->tm_mday != 1)
        return(0);
    /* Months 0..11 */
    printf("tm_mon = %d\n", lt->tm_mon);
    if (lt->tm_mon != 11 && lt->tm_mon != 0)
        return(0);
    /* Pretend it is valid after all - though there is a small chance we are incorrect */
    return 1;
}
于 2012-12-27T04:38:21.890 に答える
2

これを行うよりクリーンな方法を次に示します (この例では、DST バイアスを含む GMT 時間を取得します)。

struct STimeZoneFromRegistry
{
   long  Bias;
   long  StandardBias;
   long  DaylightBias;
   SYSTEMTIME StandardDate;
   SYSTEMTIME DaylightDate;
};



static SYSTEMTIME GmtNow()
{
   FILETIME UTC;
   GetSystemTimeAsFileTime(&UTC); 

   SYSTEMTIME GMT;

   TIME_ZONE_INFORMATION tz = {0};
   STimeZoneFromRegistry binary_data;
   DWORD size = sizeof(binary_data);
   HKEY hk = NULL;
   TCHAR zone_key[] = _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\GMT Standard Time");
   if ((RegOpenKeyEx(HKEY_LOCAL_MACHINE, zone_key, 0, KEY_QUERY_VALUE, &hk) == ERROR_SUCCESS) &&
      (RegQueryValueEx(hk, "TZI", NULL, NULL, (BYTE *) &binary_data, &size) == ERROR_SUCCESS))
   {
      tz.Bias = binary_data.Bias;
      tz.DaylightBias = binary_data.DaylightBias;
      tz.DaylightDate = binary_data.DaylightDate;
      tz.StandardBias = binary_data.StandardBias;
      tz.StandardDate = binary_data.StandardDate;
   }

   SystemTimeToTzSpecificLocalTime(&tz, &UTC, &GMT);

   return GMT;
 }
于 2013-09-23T17:48:54.390 に答える