2012-12-27 58 views
1

我試圖使用C++獲取不同時區(PST)中的時間。Unix C++:在不同區域獲取時間

#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小時(例如,現在,時間有3AM上午),減去8小時從它不工作!

在Unix的不同時區獲取時間的正確方法是什麼?

+0

http://stackoverflow.com/questions/1657305/how-do-i-use-the-c-date-and-time-functions-on -unix – favoretti

+0

不要在分號中加分號#define';這幾乎是不可避免的一個錯誤! –

+0

你的代碼也返回一個由局部變量'temp'派生的指針,這個變量在調用函數獲得返回值時被銷燬......這不是幸福的祕訣。 –

回答

6

既然你說過「UNIX」,這就使用TZ,但是,TZ=[what goes here]你需要在你的系統上找出[這裏發生了什麼]。它可能是「America/LosAngeles」或PST中的其他幾個字符串之一。 如果您的系統是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. 
+0

thankyou that works :) –

4

我有以下C代碼藏起來處理問題。效率是不是彈簧想到(兩次調用setenv(),兩次調用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時間值和時區偏移量(以小時和分鐘爲參數)。儘管我的電腦默認運行在美國/太平洋(或America/Los_Angeles)時區,但我測試的TZ設置爲不同的值(包括US/Eastern,IST-05:30),並獲得了正確的值;基於過去的經驗,我相當確信計算是正確的。

我有另一個程序試圖解剖從mktime()返回的-1是否是由於錯誤或由於經轉換的時間對應於(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; 
} 
2

這裏是這樣做的更清潔的方式(本實施例中得到GMT時間包括DST偏差):

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; 
} 
+0

這是一個很好的答案,但在錯誤的問題上,因爲問題是關於Unix,這是Windows特定的。 (也許你可以找到一個特定於窗口的問題並將它移動到那裏?) –