2015-07-17 13 views
5

Quello che mi piacerebbe fare con il mio semplice programma è calcolare una differenza in secondi tra due date.Come calcolare le differenze di orario in C++ con time_t prima dell'epoca?

time_t referenceDate; 
time_t dateNow = time(0); 
struct tm referenceDateComponent = {0}; 
referenceDateComponent.tm_hour = 0; 
referenceDateComponent.tm_min = 0; 
referenceDateComponent.tm_sec = 0; 
referenceDateComponent.tm_year = 89; 
referenceDateComponent.tm_mon = 11; 
referenceDateComponent.tm_mday = 31; 
referenceDate = mktime(&referenceDateComponent); 
long seconds = difftime(dateNow, referenceDate); 

Pentecoste il codice precedente l'applicazione funziona bene, ma se tenta di impostare tm.year negativo (per costruire una data prima del 1900) la mktime() funzione di ritorno -1

so che time_t tipo di gestire solo le date a partire dal 1 gennaio 1970 UTC secondo la documentazione:

Per motivi storici, viene generalmente implementato come valore integrale che rappresenta il numero di secondi trascorsi dalle 00:00 ore, Gen 1, 1970 UTC (cioè un timestamp unix). Sebbene le librerie possano implementare questo tipo utilizzando rappresentazioni temporali alternative.

So che ci sono anche le librerie Boost ma non è una soluzione utilizzabile per me.

Quindi la mia domanda sarebbe, c'è un modo per fare la differenza in pochi secondi dalle date che iniziano prima del 1970?

+0

Puoi migliorare il tuo titolo? Non descrive la tua domanda in alcun modo utile. –

+1

Qual è il caso d'uso effettivo per una data precedente al 1900 sul computer? È il compleanno di una persona molto anziana, o peggio di quella ... Transizione gregoriana/giuliana avvenuta nel XX secolo in Russia. Quindi ** modifica la tua domanda ** per dare contesto e motivazione e ulteriori spiegazioni –

+1

[Questo non è affatto semplice] (https://www.youtube.com/watch?v=-5wpm-gesOY). – nwp

risposta

1

Hai già risposto a questa domanda. time_t rappresenta un numero di secondi dall'epoca UNIX, non un numero di secondi da un tempo arbitrario precedente. Quello che stai cercando di fare fondamentalmente non ha senso.

Se sei bloccato su C++ 03, indipendentemente dalle tue affermazioni ambigue su ciò che puoi o non puoi usare, dovrai utilizzare Boost.DateTime.

In caso contrario, la libreria standard presenta alcune funzioni di indicazione dell'ora moderne in <chrono>.

+1

* "So che ci sono anche le librerie Boost ma non è una soluzione utilizzabile per me." * – CoryKramer

+0

OP ha dichiarato che non può usare Boost! –

8

Si consiglia di utilizzare lo spazio dei nomi C++ 11 std::chrono e le intestazioni standard <chrono> e le funzioni e le classi standard al loro interno.

Si potrebbe anche considerare difftime dallo standard C e localtime & mktime

e ci sono un sacco di buoni altri motivi per l'aggiornamento a C++11 almeno (o C++14 se potete). Diversi buoni ultimi compilatori software libero GCC e Clang/LLVM supporto che standard (compilare con -std=c++11 o -std=gnu++14 se si desidera estensioni GNU & C++ 14)

BTW, la sua domanda è molto più complesso di quanto si creda. I calendari sono cambiati. Julian/Gregorian transizione di calendario avvenuta nel XX ° secolo in Russia. La mia defunta madre nacque nel 1919, durante l'emigrazione e la guerra civile, in un villaggio russo il cui sistema legale fu contestato in quel momento (la rivoluzione russa non avvenne all'istante). Aveva alcuni documenti che menzionavano il 13 th dicembre 1919, e altri documenti che menzionavano il 26 th dicembre 1919, riferendosi alla stessa data in due calendari diversi. Come si risolverebbe il tuo software? Non sono nemmeno sicuro che il fuso orario sia sufficiente!

BTW, non sono sicuro che Boost o C++ 11 <chrono> può affidabile affrontare tali questioni di calendario.

nwp menzionato in un commento molto buono computerphile video: Problem with Time & Timezones.

1

Quando si sta tentando di eseguire l'aritmetica del calendario utilizzando time_t, è naturalmente necessario preoccuparsi del tipo e della rappresentazione di time_t, che è ovviamente definito dall'implementazione. È quasi sempre un tipo integrale e firmato. Su Unix e sui moderni sistemi MacOS sono secondi dal 1970, e per compatibilità penso che potrebbe essere usato in questo modo anche su Windows. Tende ad essere 32 bit. Mettendo tutto insieme, in genere può rappresentare date tra il 13 dicembre 1901 e il 18 gennaio, 2038.

E infatti quando ho cambiato la linea tm_year nel codice per

referenceDateComponent.tm_year = 60; 

il codice ha funzionato e stampato 1.721.200,226 mila , che è circa 19921 giorni o 54,5 anni, che è esattamente la differenza tra il 31 dicembre 1960 e oggi.

Ma se si imposta tm_year in modo negativo, si chiederebbe una data prima del 1900, e non funzionerà con la definizione tipica di time_t di cui abbiamo discusso.

(È vero che ci sono altre possibilità per time_t. Potrebbe essere in virgola mobile.Potrebbe essere unsigned invece di firmato.Potrebbe essere un tipo a 64-bit, il che significa che avrebbe una gamma di quasi 600.000.000.000 anni, che è incidentalmente più di un 32-bit tm_year può contenere.)

Quindi anche se ci sono molti oppositori qui che ti dicono di non farlo, e anche se ci sono certamente molte difficoltà oscure che hanno a che fare con fusi orari e secondi e calendari bisestili altro rispetto a Gregorian, di solito è meglio usare time_t per fare calcoli matematici di base per le date nel 20 ° secolo e in questo secolo fino al 2038, quando il famigerato "Y2.038K problem" sta per colpire. (Sarà, temo, un po 'peggiore del non così infame Y2K problem, ma questa è un'altra storia.)

Come ho già detto, il tuo codice ha funzionato per me per date precedenti al 1970. Ecco cosa consiglierei di usare per semplici calcoli time_t data basati (e con avvertimenti come già detto):

time_t makedate(int year, int month, int day) 
{ 
    struct tm tm = {0}; 
     tm.tm_hour = 12; 
    tm.tm_min = tm.tm_sec = 0; 
    tm.tm_year = year - 1900; 
    tm.tm_mon = month - 1; 
    tm.tm_mday = day; 
    tm.tm_isdst = -1; 
    return mktime(&tm); 
} 

int main() 
{ 
    long int d = difftime(makedate(2015, 7, 17), makedate(2015, 6, 1)); 
    printf("%ld sec = %ld days = %.2f years\n", d, d/86400, d/86400./365.25); 

    d = difftime(makedate(2015, 7, 17), makedate(2014, 7, 17)); 
    printf("%ld sec = %ld days = %.2f years\n", d, d/86400, d/86400./365.25); 

    d = difftime(makedate(1975, 7, 17), makedate(1965, 7, 17)); 
    printf("%ld sec = %ld days = %.2f years\n", d, d/86400, d/86400./365.25); 

    d = difftime(makedate(1950, 1, 11), makedate(1925, 1, 1)); 
    printf("%ld sec = %ld days = %.2f years\n", d, d/86400, d/86400./365.25); 

    d = difftime(makedate(2030, 12, 31), makedate(2025, 12, 31)); 
    printf("%ld sec = %ld days = %.2f years\n", d, d/86400, d/86400./365.25); 
} 

Proprio come il tuo codice, questo sfrutta la sorprendentemente potente funzione di mktime, e può fare tutto ciò che può fare. Gestisce gli anni bisestili, nessun problema. Non gestisce i secondi bisestili o le modifiche del calendario.

E se, come dici tu, ti interessano le date prima del 1900, temo che tu non abbia fortuna. time_t semplicemente non può rappresentare quelle date sulla maggior parte dei sistemi, quindi dovrai perseguire qualche altra soluzione.