2010-02-26 15 views
15

Sto provando a scrivere una classe Date nel tentativo di imparare il C++.Algoritmo per aggiungere o sottrarre giorni da una data?

Sto cercando di trovare un algoritmo per aggiungere o sottrarre giorni a una data, in cui giorno parte da 1 e mese parte da 1. E 'dimostrando di essere molto complesso, e Google non si presenta molto,

Qualcuno sa di un algoritmo che fa questo?

+0

Sono stupito che queste domande esistano senza una risposta "Usa Boost" di accompagnamento con un collegamento alla documentazione. – jww

risposta

16

Il modo più semplice è di scrivere effettivamente due funzioni, una che converte il giorno in un numero di giorni da una determinata data di inizio, quindi un'altra che converte in una data. Una volta che la data è espressa in un numero di giorni, è banale aggiungere o sottrarre ad esso.

Potete trovare gli algoritmi qui: http://alcor.concordia.ca/~gpkatch/gdate-algorithm.html

+0

Grazie, questo è proprio quello che stavo cercando, per qualche motivo non riuscivo a trovare l'algoritmo durante la ricerca in rete! – bcoughlan

+0

sfortunatamente queste funzioni non sono molto precise ... o almeno quando ho confrontato i miei risultati con wolfram alpha, ero fuori da un giorno o due. – aimango

+0

Qui: http://home.roadrunner.com/~hinnant/date_algorithms.html sono algoritmi precisi. La loro validità è stata testata per essere precisi su un calendario gregoriano prolettoriale nell'intervallo di +/- 5,8 milioni di anni usando l'aritmetica a 32 bit. Contano giorni prima o dopo il 1970-01-01. –

3

Suppongo che questo sia per qualche tipo di esercizio, altrimenti useresti una lezione di tempo che ti è già stata fornita.

È possibile memorizzare l'ora come il numero di millisecondi da una certa data. E poi puoi aggiungere il valore appropriato e convertire da quello alla data chiamando gli utenti della tua classe.

+0

Perché millisecondi? Sembra solo che voglia le date, non i tempi, e certamente non la precisione millisecondo. Ciò suggerisce anche di tenere conto dei secondi bisestili. – Steve314

1

Un approccio consiste nel mappare la data al numero giuliano della data, eseguire le operazioni sui numeri interi e quindi eseguire il ripristino.

Troverete molte risorse per le funzioni julian.

0

Vorrei suggerire a scrivere prima una routine che converte anno-mese-giorno in un certo numero di giorni dalla data fissata, per esempio, dal 1.01.01. E una routine simmetrica che la riconvertirebbe.

Non dimenticare di elaborare correttamente gli anni bisestili!

Avendo questi due, il tuo compito sarebbe banale.

2

Ecco uno schizzo di un approccio molto semplice. Per la semplicità delle idee assumerò che d, il numero di giorni da aggiungere, sia positivo. È facile estendere quanto segue ai casi in cui d è negativo.

O d è inferiore a 365 o d è maggiore o uguale a 365.

Se d è inferiore a 365:

m = 1; 
while(d > numberOfDaysInMonth(m, y)) { 
    d -= numberOfDaysInMonth(m, y); 
    m++; 
} 
return date with year = y, month = m, day = d; 

Se d è maggiore di 365:

while(d >= 365) { 
    d -= 365; 
    if(isLeapYear(y)) { 
     d -= 1; 
    } 
    y++; 
} 
// now use the case where d is less than 365 

In alternativa, è possibile esprimere la data, ad esempio, Julian form e quindi semplicemente aggiungi al form di Julian e converti in formato ymd.

+0

funziona per me, grazie! – aimango

7

Non hai davvero bisogno di un algoritmo in quanto tale (almeno non qualcosa di degno del nome), la libreria standard può fare la maggior parte del sollevamento pesante; i calcoli del calendario sono notoriamente difficili.Fino a quando non hai bisogno di date precedenti al 1900, poi:

#include <ctime> 

// Adjust date by a number of days +/- 
void DatePlusDays(struct tm* date, int days) 
{ 
    const time_t ONE_DAY = 24 * 60 * 60 ; 

    // Seconds since start of epoch 
    time_t date_seconds = mktime(date) + (days * ONE_DAY) ; 

    // Update caller's date 
    // Use localtime because mktime converts to UTC so may change date 
    *date = *localtime(&date_seconds) ; ; 
} 

Esempio di utilizzo:

#include <iostream> 

int main() 
{ 
    struct tm date = { 0, 0, 12 } ; // nominal time midday (arbitrary). 
    int year = 2010 ; 
    int month = 2 ; // February 
    int day = 26 ; // 26th 

    // Set up the date structure 
    date.tm_year = year - 1900 ; 
    date.tm_mon = month - 1 ; // note: zero indexed 
    date.tm_mday = day ;  // note: not zero indexed 

    // Date, less 100 days 
    DatePlusDays(&date, -100) ; 

    // Show time/date using default formatting 
    std::cout << asctime(&date) << std::endl ; 
} 
+0

Grazie per aver postato questo. Molto utile. – ForeverLearning

+0

I secondi saltanti incasineranno questo calcolo? – vargonian

+0

@vargonian: una buona domanda; L'epoca temporale UNIX è del 1 ° gennaio 1970 e non conta i secondi bisestili. Tuttavia, l'impostazione dell'orario nominale del giorno a mezzogiorno eviterà qualsiasi potenziale problema per diverse decine di migliaia di anni. – Clifford

1

Prova questa funzione. Calcola correttamente aggiunte o sottrazioni. L'argomento dateTime deve essere nel formato UTC.

tm* dateTimeAdd(const tm* const dateTime, const int& days, const int& hours, const int& mins, const int& secs) { 
    tm* newTime = new tm; 
    memcpy(newTime, dateTime, sizeof(tm)); 

    newTime->tm_mday += days; 
    newTime->tm_hour += hours; 
    newTime->tm_min += mins; 
    newTime->tm_sec += secs;   

    time_t nt_seconds = mktime(newTime) - timezone; 
    delete newTime; 

    return gmtime(&nt_seconds); 
} 

E ci sono esempio di utilizzo:

time_t t = time(NULL); 
tm* utc = gmtime(&t); 
tm* newUtc = dateTimeAdd(utc, -5, 0, 0, 0); //subtract 5 days 
0

So che questa è una domanda molto vecchio ma è un interessante e alcuni comuni uno quando si tratta di lavorare con date e orari. Così ho pensato di condividere un codice che calcola la nuova data senza utilizzare alcuna funzionalità integrata in C++.

#include <iostream> 
#include <string> 

using namespace std; 

class Date { 
public: 
    Date(size_t year, size_t month, size_t day):m_year(year), m_month(month), m_day(day) {} 
    ~Date() {} 

    // Add specified number of days to date 
    Date operator + (size_t days) const; 

    // Subtract specified number of days from date 
    Date operator - (size_t days) const; 

    size_t Year() { return m_year; } 
    size_t Month() { return m_month; } 
    size_t Day() { return m_day; } 

    string DateStr(); 
private: 
    // Leap year check 
    inline bool LeapYear(int year) const 
     { return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); } 

    // Holds all max days in a general year 
    static const int MaxDayInMonth[13]; 

    // Private members 
    size_t m_year; 
    size_t m_month; 
    size_t m_day; 
}; 

// Define MaxDayInMonth 
const int Date::MaxDayInMonth[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 

//=========================================================================================== 
/// Add specified number of days to date 
Date Date::operator + (size_t days) const { 
    // Maximum days in the month 
    int nMaxDays(MaxDayInMonth[m_month] + (m_month == 2 && LeapYear(m_year) ? 1 : 0)); 

    // Initialize the Year, Month, Days 
    int nYear(m_year); 
    int nMonth(m_month); 
    int nDays(m_day + days); 

    // Iterate till it becomes a valid day of a month 
    while (nDays > nMaxDays) { 
     // Subtract the max number of days of current month 
     nDays -= nMaxDays; 

     // Advance to next month 
     ++nMonth; 

     // Falls on to next year? 
     if (nMonth > 12) { 
      nMonth = 1; // January 
      ++nYear; // Next year 
     } 

     // Update the max days of the new month 
     nMaxDays = MaxDayInMonth[nMonth] + (nMonth == 2 && LeapYear(nYear) ? 1 : 0); 
    } 

    // Construct date 
    return Date(nYear, nMonth, nDays); 
} 

//=========================================================================================== 
/// Subtract specified number of days from date 
Date Date::operator - (size_t days) const { 
    // Falls within the same month? 
    if (0 < (m_day - days)) { 
     return Date(m_year, m_month, m_day - days); 
    } 

    // Start from this year 
    int nYear(m_year); 

    // Start from specified days and go back to first day of this month 
    int nDays(days); 
    nDays -= m_day; 

    // Start from previous month and check if it falls on to previous year 
    int nMonth(m_month - 1); 
    if (nMonth < 1) { 
     nMonth = 12; // December 
     --nYear;  // Previous year 
    } 

    // Maximum days in the current month 
    int nDaysInMonth = MaxDayInMonth[nMonth] + (nMonth == 2 && LeapYear(nYear) ? 1 : 0); 

    // Iterate till it becomes a valid day of a month 
    while (nDays >= 0) { 
     // Subtract the max number of days of current month 
     nDays -= nDaysInMonth; 

     // Falls on to previous month? 
     if (nDays > 0) { 
      // Go to previous month 
      --nMonth; 

      // Falls on to previous year? 
      if (nMonth < 1) { 
       nMonth = 12; // December 
       --nYear;  // Previous year 
      } 
     } 

     // Update the max days of the new month 
     nDaysInMonth = MaxDayInMonth[nMonth] + (nMonth == 2 && LeapYear(nYear) ? 1 : 0); 
    } 

    // Construct date 
    return Date(nYear, nMonth, (0 < nDays ? nDays : -nDays)); 
} 

//=========================================================================================== 
/// Get the date string in yyyy/mm/dd format 
string Date::DateStr() { 
    return to_string(m_year) 
     + string("/") 
     + string(m_month < 10 ? string("0") + to_string(m_month) : to_string(m_month)) 
     + string("/") 
     + string(m_day < 10 ? string("0") + to_string(m_day) : to_string(m_day)); 
} 


int main() { 
    // Add n days to a date 
    cout << Date(2017, 6, 25).DateStr() << " + 10 days = " 
     << (Date(2017, 6, 25) /* Given Date */ + 10 /* Days to add */).DateStr() << endl; 

    // Subtract n days from a date 
    cout << Date(2017, 6, 25).DateStr() << " - 10 days = " 
     << (Date(2017, 6, 25) /* Given Date */ - 10 /* Days to subract */).DateStr() << endl; 

    return 0; 
} 

Output 
2017/06/25 + 10 days = 2017/07/05 
2017/06/25 - 10 days = 2017/06/15