2008-11-21 11 views
16

Tôi có thời gian được biểu thị bằng số giây đã trôi qua kể từ nửa đêm, ngày 1 tháng 1 năm 1970, UTC (kết quả của cuộc gọi trước đó đến thời gian()). Làm cách nào để thêm một ngày vào thời điểm này?Cách thêm một ngày vào một thời điểm thu được từ thời gian()

Thêm 24 * 60 * 60 hoạt động trong hầu hết các trường hợp, nhưng không thành công nếu thời gian tiết kiệm ánh sáng ban ngày bật hoặc tắt ở giữa. Nói cách khác, tôi chủ yếu muốn thêm 24 giờ, nhưng đôi khi 23 hoặc 25 giờ.

Để minh họa - chương trình:

#include <time.h> 
#include <iostream> 

int main() 
{ 
    time_t base = 1142085600; 
    for(int i = 0; i < 4; ++i) { 
    time_t time = base + i * 24 * 60 * 60; 
    std::cout << ctime(&time); 
    } 
    return 0; 

}

Tạo:

Sat Mar 11 08:00:00 2006 
Sun Mar 12 09:00:00 2006 
Mon Mar 13 09:00:00 2006 
Tue Mar 14 09:00:00 2006 

Tôi muốn thời gian cho March 12, 13, ... để cũng được 08:00.


Câu trả lời được cung cấp bởi FigBug đã chỉ cho tôi đúng hướng. Nhưng tôi phải dùng localtime thay vì gmtime.

int main() 
{ 
    time_t base = 1142085600; 
    for(int i = 0; i < 4; ++i) { 
    struct tm* tm = localtime(&base); 
    tm->tm_mday += i; 
    std::cout << asctime(tm); 
} 
return 0; 
} 

Hãy cho tôi:

Sat Mar 11 08:00:00 2006 
Sat Mar 12 08:00:00 2006 
Sat Mar 13 08:00:00 2006 
Sat Mar 14 08:00:00 2006 

Đó là những gì tôi muốn. Sử dụng gmtime mang lại cho tôi thời gian lúc 14:00:00

Tuy nhiên, lưu ý rằng tất cả các ngày đều là Thứ Bảy. Ngoài ra, nó đi đến tháng 32, 33, vv Nếu tôi ném trong hàm mktime Tôi trở lại nơi tôi bắt đầu:

#include <time.h> 
#include <iostream> 

int main() 
{ 
    time_t base = 1142085600; 
    for(int i = 0; i < 4; ++i) { 
    struct tm* tm = localtime(&base); 
    tm->tm_mday += i; 
    time_t time = mktime(tm); 
    std::cout << asctime(tm); 
} 
return 0; 
} 

Cung cấp cho tôi:

Sat Mar 11 08:00:00 2006 
Sun Mar 12 09:00:00 2006 
Mon Mar 13 09:00:00 2006 
Tue Mar 14 09:00:00 2006 

tôi thiếu gì ???


OK, tôi đã cố gắng ra đề nghị mới nhất FigBug của đó là sử dụng:

std::cout << ctime(&time); 

thay vì asctime, nhưng tôi nhận được kết quả tương tự. Vì vậy, tôi đoán rằng thư viện của tôi và/hoặc trình biên dịch là sai lầm. Tôi đang sử dụng g ++ 3.4.4 trên Cygwin. Tôi đã sao chép các tập tin trên Solaris 5.8 và sử dụng g ++ 3.3 để biên dịch. Tôi nhận được kết quả chính xác ở đó! Trong thực tế tôi nhận được kết quả chính xác cho dù tôi sử dụng ctime hoặc asctime cho đầu ra:

Sat Mar 11 08:00:00 2006 
Sun Mar 12 08:00:00 2006 
Mon Mar 13 08:00:00 2006 
Tue Mar 14 08:00:00 2006 

Tôi cũng có được kết quả chính xác (với cả hai chức năng đầu ra) trên Red Hut Linux với g ++ 3.4.6.

Vì vậy, tôi đoán rằng tôi đã gặp một lỗi Cygwin.

Cảm ơn bạn cho tất cả sự giúp đỡ và tư vấn của bạn ....

+0

Tôi nghĩ bạn muốn sử dụng ctime không asctime trong phiên bản cuối cùng vì bạn muốn thời gian trong múi giờ địa phương của bạn. time() trả về UTC, localtime() chuyển đổi nó thành múi giờ của bạn. Thêm một ngày trong múi giờ của bạn, chuyển đổi thành UTC. In ra trong múi giờ của bạn với ctime(). Vì vậy, khó hiểu. –

+0

Một dòng khác: tm-> tm_wday = (tm-> tm_wday + i)% 7; –

+0

Bạn không cần phải lo lắng về điều đó: từ tài liệu mktime: Giá trị ban đầu của thành viên tm_wday và tm_yday của timeptr bị bỏ qua và phạm vi giá trị cho phần còn lại của thành viên không bị giới hạn ở giá trị bình thường của chúng (như tm_mday nằm trong khoảng từ 1 đến 31). –

Trả lời

18

sử dụng gmtime() để chuyển đổi time_t đến một tm struct

thêm một đến ngày ( tm_mday)

sử dụng mktime() để chuyển đổi struct tm quay lại số time_t

thấy time.h để biết thêm

Edit:

Tôi chỉ cố gắng, công trình này:

int main() 
{ 
    time_t base = 1142085600; 
    for(int i = 0; i < 4; ++i) { 
    struct tm* tm = localtime(&base); 
    tm->tm_mday += i; 
    time_t next = mktime(tm); 
    std::cout << ctime(&next); 
} 
return 0; 
} 
+0

Các từ có dấu gạch dưới không bị in nghiêng không? –

+0

sử dụng some_word_with_underscores thay vì * từ * – Jimmy

+0

Hoặc đặt dấu gạch chéo ngược ở phía trước dấu gạch dưới. –

3

tôi luôn luôn có kết quả tốt nhất với việc giữ timestamps UTC và chuyển đổi chúng sang múi giờ quy định (kể cả tiết kiệm ánh sáng ban ngày) khi bạn muốn hiển thị các giá trị .

Điều này tiết kiệm rất nhiều rắc rối như thế này (và làm cho chương trình của bạn độc lập với múi giờ.

+0

Dấu thời gian là UTC. –

5

Chỉ cần thêm 24 * 60 * 60. Nó không nên thất bại trong DST, vì UTC sẽ không bao giờ sử dụng DST.

Nếu không thành công, bạn không sử dụng UTC ở đâu đó trong mã của mình. Loại bỏ sự phụ thuộc múi giờ.

+1

Vấn đề là thêm một ngày để nói 3/31/2008 8:00:00 giờ địa phương sẽ cho tôi 4/1/2008 8:00:00 giờ địa phương ngay cả khi DST thay đổi tại địa phương qua đêm vào ngày 31/3. –

+0

Tôi không hiểu, bạn có đang sử dụng dấu thời gian unix trong UTC hay không? Dấu thời gian Unix không liên quan gì đến DST. – Pyrolistical

+1

Việc chuyển đổi từ UTC sang giờ địa phương là nơi mà giờ DST được thêm vào hoặc trừ đi - UTC không bị ảnh hưởng, như Pyrolistical nói. –

5

giải pháp FigBug sẽ làm việc gần mọi thời gian, nhưng nó cần DST sửa chữa: TM-> tm_isdst = -1

Một giá trị tích cực hay 0 cho tm_isdst nguyên nhân mktime() để đoán ban đầu Thời gian tiết kiệm ánh sáng ban ngày, tương ứng, là hoặc không có hiệu lực trong thời gian đã chỉ định. Giá trị âmcho tm_isdst sẽ gây ra mktime() thành cố gắng xác định xem Daylight Thời gian lưu có hiệu lực cho thời gian đã chỉ định hay không.

(trích dẫn từ mktime spec)

int main() 
{ 
    time_t base = 1142085600; 
    for(int i = 0; i < 4; ++i) { 
    struct tm* tm = localtime(&base); 
    tm->tm_mday += i; 
    tm->tm_isdst = -1;  // don't know if DST is in effect, please determine 
           // this for me 
    time_t next = mktime(tm); 
    std::cout << ctime(&next); 
} 
return 0; 
} 

Nếu không sẽ có một lỗi (ví dụ cho Moscow Daylight Saving Time mà bắt đầu ngày 29 tháng ba 2009 01:59:59):

int main() 
{ 
    // 28 March 2009 05:00:00 GMT (local - 08:00 (MSK)) 
    time_t base = 1238216400; 

    std::time_t start_date_t = base; 
    std::time_t end_date_t = base; 

    std::tm start_date = *std::localtime(&start_date_t); 
    std::tm end_date = *std::localtime(&end_date_t); 

    end_date.tm_mday += 1; 
// end_date.tm_isdst = -1; 

    std::time_t b = mktime(&start_date); 
    std::time_t e = mktime(&end_date); 

    std::string start_date_str(ctime(&b)); 
    std::string stop_date_str(ctime(&e)); 

    cout << " begin (MSK) (DST is not active): " << start_date_str; 
    cout << " end (MSD) (DST is active):  " << stop_date_str; 
} 

Đầu ra:

begin (MSK) (DST is not active): Sat Mar 28 08:00:00 2009 
end (MSD) (DST is active):  Sun Mar 29 09:00:00 2009 
2

Câu trả lời mới cho một câu hỏi rất cũ sự.

Lý do cho câu trả lời mới: Hiện có các công cụ tốt hơn để giải quyết vấn đề này, làm cho kết quả ít bị lỗi, dễ đọc hơn và hiệu quả hơn bằng cách giảm thiểu chuyển đổi trường < ->.

Câu trả lời mới yêu cầu C++ 11/14, <chrono>free, open source, timezone library này.

Dưới đây là các mã:

#include "tz.h" 
#include <iostream> 

int 
main() 
{ 
    using namespace std::chrono; 
    using namespace date; 
    auto base = make_zoned("Pacific/Easter", sys_seconds{1142085600s}); 
    for (int i = 0; i < 4; ++i) 
    { 
     std::cout << format("%a %b %d %T %Y %Z", base) << '\n'; 
     base = base.get_local_time() + days{1}; 
    } 
} 

này bắt đầu bằng cách tạo ra một zoned_time bằng cách ghép nối bất cứ điều gì là múi giờ mong muốn tại thời điểm trên Unix Time.

Định dạng được định dạng theo bất kỳ định dạng mong muốn nào.

Và việc bổ sung thêm 1 ngày được thực hiện trong hệ thống giờ địa phương của múi giờ, sẽ tính đến việc tiết kiệm ánh sáng ban ngày. Đầu ra là:

Sat Mar 11 09:00:00 2006 -05 
Sun Mar 12 09:00:00 2006 -06 
Mon Mar 13 09:00:00 2006 -06 
Tue Mar 14 09:00:00 2006 -06 

Khi nó xuất hiện, kết quả này không chính xác những gì OP đã nêu mong muốn (sản lượng được yêu cầu lúc 08:00:00 mỗi ngày). Tuy nhiên, tôi đã sử dụng thư viện này để điều tra toàn bộ thời gian chuyển tiếp của hành tinh vào ngày này. Và chỉ có một múi giờ có sự chuyển tiếp vào ngày này: Thái Bình Dương/Phục Sinh. Và quá trình chuyển đổi đó là di chuyển trở lại một giờ, không phải về phía trước. Đây là múi giờ được sử dụng cho Chile, ở bán cầu nam, trong đó rơi trở lại trong khung thời gian tháng 3.

Điều này có thể được chứng minh bằng cách thực hiện số học trong UTC thay vì theo giờ địa phương. Đây là một sự điều chỉnh nhỏ đối với chương trình trên trong một dòng:

 base = base.get_sys_time() + days{1}; 

Sử dụng base.get_sys_time(), như trái ngược với base.get_local_time(), làm cho số học được thực hiện trong "thời gian hệ thống" đó là UTC bỏ qua bước nhảy vọt giây. Và bây giờ đầu ra thay đổi thành:

Sat Mar 11 09:00:00 2006 -05 
Sun Mar 12 08:00:00 2006 -06 
Mon Mar 13 08:00:00 2006 -06 
Tue Mar 14 08:00:00 2006 -06