2009-11-19 46 views
5

Tôi có một chuỗi có chứa một ngày local/thời gian và tôi cần phải chuyển nó sang một giá trị time_t (theo giờ UTC) - Tôi đã cố gắng này:Chuyển đổi chuỗi chứa localtime sang UTC trong C

char* date = "2009/09/01/00"; 
struct tm cal = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL}; 
strptime(date, "%Y/%m/%d/%H", &cal); 
time_t t = mktime(&cal); 

nhưng giá trị time_t mà tôi nhận được là giá trị mà tôi mong đợi nếu chuỗi đã được phân tích cú pháp dưới dạng UTC không phải giờ địa phương. Có lẽ tôi đã hiểu lầm những gì strptime là nghĩa vụ phải làm, nhưng trong múi giờ của tôi (Anh) vào ngày 01 tháng 9 chúng tôi đang sử dụng BST (tức là UTC + 1 giờ) vì vậy tôi mong đợi giá trị tôi kết thúc với được 1 giờ trước UTC .

Có cách nào để diễn giải chuỗi là giờ địa phương, tự động tính đến khoản bù trừ UTC có thể có hiệu lực vào ngày đó không? Lưu ý rằng tôi cần giá trị time_t không phải là cấu trúc tm, trong ví dụ trên tôi muốn giá trị time_t tương ứng với 2009-09-01 01:00:00 GMT

Trả lời

0

Tôi nghĩ rằng tôi đã nứt nó bây giờ, nhờ Andomar - mã này làm những gì tôi cần và dường như làm việc bất kể của trạng thái DST hiện tại (Tôi đã thay đổi đồng hồ trên PC của mình để kiểm tra điều này):

#include <time.h> 
#include <assert.h> 

time_t parseLocalDate(char* date){ 
    struct tm cal = {0, 0, 0, 0, 0, 0, 0, 0, -1, 0, NULL}; 
    strptime(date, "%Y/%m/%d/%H", &cal); 
    return mktime(&cal); 
} 

int main(int argc, char *argv[]){ 
// DST is effect, Local Time = GMT+1 
    assert(1251759600 == parseLocalDate("2009/09/01/00")); // Mon, 31 Aug 2009 23:00:00 GMT 
    assert(1254351600 == parseLocalDate("2009/10/01/00")); // Wed, 30 Sep 2009 23:00:00 GMT 
// DST not in effect, Local Time = GMT 
    assert(1257033600 == parseLocalDate("2009/11/01/00")); // Sun, 01 Nov 2009 00:00:00 GMT 
} 
5

Bạn có thể sử dụng mktime để diễn giải cấu trúc tm trong múi giờ địa phương. Khi bạn làm như vậy, hãy cẩn thận để đặt cờ tm_isdst. Đó là 0 cho mùa hè, 1 cho mùa đông và -1 để có mktime tìm ra. Dưới đây là một số mã ví dụ:

void main() 
{ 
    char* date = "2009/09/01/00"; 
    struct tm cal = {}; 
    // Read string into struct tm 
    strptime(date, "%Y/%m/%d/%H", &cal); 
    // Tell mktime to figure out the daylight saving time 
    cal.tm_isdst = -1; 
    printf("%20s: %s", "Before mktime", asctime(&cal)); 
    // Convert struct tm to time_t 
    time_t t = mktime(&cal); 
    // Convert time_t to localtime 
    struct tm localcal = *localtime(&t); 
    printf("%20s: %s", "Local time", asctime(&localcal)); 
    printf("%20s: %i\n", "Local DST", localcal.tm_isdst); 
    // Convert time_t to GMT 
    struct tm gmcal = *gmtime(&t); 
    printf("%20s: %s", "GM time", asctime(&gmcal)); 
    printf("%20s: %i\n", "GM DST", gmcal.tm_isdst); 
} 

in này (Tôi sống ở GMT + 1, và đó là mùa đông bây giờ):

Before mktime: Tue Sep 1 00:00:00 2009 
     Local time: Tue Sep 1 00:00:00 2009 
     Local DST: 1 
     GM time: Mon Aug 31 22:00:00 2009 
      GM DST: 0 

Dường như mktime chuyển đổi một ngày vào tháng dựa trên các khoản tiết kiệm ánh sáng ban ngày hiện tại thời gian. Đó là tháng mười một, vì vậy nó thực sự là một giờ nghỉ. Tôi đã không tìm được cách để sửa nó.

+0

cảm ơn, nhưng giá trị time_t mà tôi quan tâm - nếu tôi làm mktime() trên 'localcal' struct trong mã của bạn nó mang lại cho tôi kết quả tương tự như làm mktime() trên ' cal '. Tôi cần một số cách để tạo ra một giá trị time_t tương đương với '2009-09-01 01:00 GMT' – codebox

+1

Quy ước C là lưu trữ time_t như số giây từ 1970-01-01 trong UTC. Nó đã thay đổi nó thành giờ địa phương chỉ để giải thích hoặc hiển thị. Nếu bạn muốn giới thiệu rob_t làm biến thể cục bộ, bạn có thể tính số giây giữa gmtime() và localtime() và thêm số đó vào time_t của bạn. :) – Andomar

+0

ok, nhưng tôi muốn giải thích chuỗi là giờ địa phương, không tạo ra thời gian tương đương cục bộ của chuỗi thời gian UTC. Trong ví dụ của chúng tôi, giả định rằng chúng ta đang sống trong GMT + 1, chuỗi "2009/09/01/00" là giờ địa phương của chúng tôi, và vì vậy nó tương đương với "2009/09/01/01" trong GMT, và vì vậy mã phải trả về giá trị time_t tương ứng với "2009/09/01/01". Điều đó có ý nghĩa? – codebox

0

Đây là phiên bản của tôi, sử dụng tm_gmtoff. Hy vọng rằng, thư viện sẽ chăm sóc của thời gian tiết kiệm ánh sáng ban ngày ...

#define _BSD_SOURCE 
#define _XOPEN_SOURCE 
#include <stdio.h> 
#include <time.h> 

int gmtoffset(void) { 
    struct tm *dummy; 
    time_t t = 0; 
    dummy = localtime(&t); 
    return dummy->tm_gmtoff; /* _BSD_SOURCE */ 
} 

int main(void) { 
    int off; 
    const char *date = "2009/09/01/00"; 
    struct tm cal = {0}; 
    time_t t; 

    off = gmtoffset(); 

    strptime(date, "%Y/%m/%d/%H", &cal); /* _XOPEN_SOURCE */ 
    t = mktime(&cal); 
    printf("t  --> %s", ctime(&t)); /* ctime includes a final '\n' */ 
    t -= off; 
    printf("t-off --> %s", ctime(&t)); 
    return 0; 
} 
 
$ /usr/bin/gcc ptime.c 
 
$ ./a.out 
t  --> Tue Sep 1 01:00:00 2009 
t-off --> Tue Sep 1 00:00:00 2009 
+0

'struct tm' bạn chuyển tới' mktime' có 'tm_isdst' được đặt thành 0, vì vậy thời gian được đọc mà không có DST. Sau đó, bạn chuyển nó đến 'ctime', điều này đúng với DST bằng cách thêm 1 giờ. Tiếp theo bạn trừ đi phần bù đắp, điều này cũng gây nhầm lẫn 1 giờ, để có được thời gian ngẫu nhiên. Công cụ này làm cho quay đầu của tôi nhưng tôi muốn nhận được để dưới cùng của nó :) – Andomar

+0

DST này là kinh doanh hài hước.Tôi vừa nhận ra rằng DST không có hiệu lực, nhưng vào ngày 1 tháng 9! Hmmm ... Tôi đoán không có cách nào để thư viện "biết" khi DST bắt đầu và kết thúc tại một địa điểm cụ thể. Tôi nghĩ bạn phải quản lý DST bằng tay (http://timeanddate.com/time/dst2009.html) – pmg

Các vấn đề liên quan