2012-08-25 27 views
9

Tôi đang thực thi mã bên dưới.Hành vi gây nhầm lẫn của hàm mktime(): tăng tm_hour đếm theo

int main() 
{ 
struct tm storage={0,0,0,0,0,0,0,0,0}; 
char *p = NULL; 
p = (char *)strptime("2012-08-25 12:23:12","%Y-%m-%d %H:%M:%S",&storage); 
char buff[1024]={0}; 
strftime(buff,1024,"%Y-%m-%d %H:%M:%S",&storage); 
cout << buff << endl; 
storage.tm_sec += 20; 
strftime(buff,1024,"%Y-%m-%d %H:%M:%S",&storage); 
cout << buff << endl; 
mktime(&storage); 
strftime(buff,1024,"%Y-%m-%d %H:%M:%S",&storage); 
cout << buff << endl; 
return 0; 
} 

Nếu ở trên Chương trình được thực thi, Nó in '2012-08-25 13:23:32' thay vì '2012-08-25 12:23:32'. Xin vui lòng giúp, tại sao nó tăng tm_hour giá trị. Điều này hoạt động chính xác nếu tôi đặt ngày đầu vào là '2012-02-25 12:23:32' trong chương trình, điều này gây nhầm lẫn.

Output ->

[[email protected] root]$ ./a.out 
2012-08-25 12:23:12 
2012-08-25 12:23:32 
2012-08-25 13:23:32 
[[email protected] root]$ 

ngày Thông tin trên hệ thống của tôi, ->

[[email protected] root]$ date 
Sat Aug 25 08:28:26 EDT 2012 
+0

Mã không cho biết giờ đang tăng.Để làm điều đó, hiển thị kết quả đến từ 'strptime' cũng như kết quả đến từ cuộc gọi đến' mktime'. Điều đó sẽ giúp pin xuống những gì thực sự xảy ra. –

+0

Xin lỗi, tôi không thể phân tích cú pháp đó. Nó có ba kết quả đầu ra thay vì một, nhưng không có dấu hiệu cho thấy chúng xuất phát từ đâu. Vui lòng cập nhật mã mẫu để khớp với đầu ra. –

Trả lời

11

gì xảy ra

Ngày mà bạn chỉ định có tiết kiệm ánh sáng ban ngày có hiệu lực nhưng khi gọi mktime, storage.tm_isdst là zero. mktime nhìn thấy điều này và nghĩ rằng "hey, họ đã cho tôi một ngày với một lá cờ tiết kiệm ánh sáng ban ngày không chính xác, cho phép sửa chữa nó". Sau đó, nó đặt tm_isdst thành 1 và thay đổi tm_hour.

Xem thêm câu hỏi this.

Để khắc phục nó

  • sử dụng timegm thay vì mktime
  • thiết lập múi giờ UTC trước khi gọi mktime (xem thêm ví dụ từ timegm):
    setenv("TZ", "", 1); 
    tzset(); 
    mktime();
  • sử dụng một date- tốt thư viện thời gian (như boost::locale::date_time/boost::date_time, nhưng đọc phần Q & Phần trên trang boost::locale::date_time trước khi chọn một)
+1

Cảm ơn, Nó đã giúp và giải thích cho tôi sự nghi ngờ của tôi. Bây giờ tôi cần phải chạy đoạn mã của tôi trên cả hai loại hệ thống (DST on & off). ví dụ. Nếu tôi đặt tm_isdst = 1 trong mã trước khi gọi đến mktime(), nó sẽ cho kết quả không chính xác trên hệ thống mà DST bị tắt (nó sẽ kết thúc giảm tm_hour bởi một). Có cách nào khác để thêm giây vào ngày cụ thể không? (Có thể là "tránh sử dụng mktime()" hoặc "Sử dụng thông minh mktime() sẽ bỏ qua cờ tm_isdst") –

+0

@DhirajNeve: Tôi đã thêm một vài bản sửa lỗi. Nếu bạn cần làm nhiều thứ liên quan đến ngày tháng/thời gian, tôi nghĩ bạn nên sử dụng thư viện ngày/giờ C++ tốt. – rve

+0

Không chỉ là 'timegm' POSIX? – stackptr

4

Wow, có chỉ là không có cách nào xung quanh nó. Nó phải là một lỗi trong việc triển khai mktime của hệ thống của bạn (3). mktime (3) không nên thay đổi struct tm * truyền cho nó.

Tôi khuyên bạn nên kiểm tra giá trị storage.tm_isdst. Hãy thử đặt nó thành 0 để đảm bảo nó không bị nhầm lẫn về DST. Nếu điều đó không hiệu quả, hãy thử đặt nó thành -1 để cho phép nó tự động xác định giá trị thích hợp.

mktime - convert broken-down time into time since the Epoch

Một giá trị tích cực hay 0 cho tm_isdst gây mktime() để đoán ban đầu rằng Daylight Savings Time, tương ứng, là hay không có hiệu lực đối với thời gian quy định. Giá trị âm cho tm_isdst gây ra mktime() để cố xác định xem Thời gian tiết kiệm ánh sáng ban ngày có hiệu lực trong khoảng thời gian đã chỉ định hay không.


tôi đã sai về mktime (3) không thay đổi struct tm *. Đó là hành vi đúng để bình thường hóa giá trị.

+0

Theo 'man mktime' (http://linux.die.net/man/3/mktime) nó có thể (và không) thay đổi' stuct tm'. Nó bình thường hóa các giá trị của nó và điền vào các trường bị thiếu. – rve

+0

@ có vẻ như bạn đã đúng. Tôi đã hiểu lầm từ ngữ. Tôi nghĩ rằng nó đã được bình thường hóa cho mục đích thiết lập time_t. –

+0

Có, việc triển khai không đúng ... –