2010-02-26 20 views
15

Ich versuche eine Date-Klasse zu schreiben, um C++ zu lernen.Algorithmus zum Hinzufügen oder Entfernen von Tagen aus einem Datum?

Ich versuche, einen Algorithmus zu finden Tagen zu einem Datum zu addieren oder subtrahieren, wo Tag beginnt ab 1 und Monat beginnt ab 1. Es erweist sich als sehr komplex, und Google nicht viel erscheinen,

Kennt jemand einen Algorithmus, der das tut?

+0

Ich bin erstaunt diese Frage existiert ohne eine begleitende "Use Boost" Antwort mit einem Link zur Dokumentation. – jww

Antwort

16

Der einfachste Weg besteht darin, zwei Funktionen zu schreiben, eine, die den Tag in eine Anzahl von Tagen ab einem bestimmten Startdatum umwandelt, und eine andere, die wieder in ein Datum konvertiert. Sobald das Datum als eine Anzahl von Tagen ausgedrückt wird, ist es trivial, es hinzuzufügen oder zu subtrahieren.

können Sie die Algorithmen finden Sie hier: http://alcor.concordia.ca/~gpkatch/gdate-algorithm.html

+0

Danke, das ist genau das, was ich gesucht habe, aus irgendeinem Grund konnte ich den Algorithmus nicht finden, während ich das Netz suche! – bcoughlan

+0

leider sind diese Funktionen nicht sehr präzise ... oder zumindest wenn ich meine Ergebnisse mit Wolfram Alpha verglichen habe, war ich um einen Tag oder so aus. – aimango

+0

Hier: http://home.roadrunner.com/~hinnant/date_algorithms.html sind Algorithmen, die präzise sind. Ihre Gültigkeit wurde auf einem proleptischen Gregorianischen Kalender im Bereich von +/- 5,8 Millionen Jahren mit 32-Bit-Arithmetik getestet. Sie zählen Tage vor oder nach 1970-01-01. –

3

Ich gehe davon aus, dass dies für eine Art Übung ist, sonst würden Sie eine Zeitklasse verwenden, die Ihnen bereits zur Verfügung gestellt wird.

Sie könnten Ihre Zeit als die Anzahl der Millisekunden seit einem bestimmten Datum speichern. Und dann können Sie den entsprechenden Wert hinzufügen und von diesem bis zum Datum beim Aufruf der Accessoren Ihrer Klasse konvertieren.

+0

Warum Millisekunden? Er scheint nur Daten zu haben, nicht Zeiten und sicherlich nicht Millisekunden. Das deutet sogar auf die Berücksichtigung von Schaltsekunden hin. – Steve314

1

Ein Ansatz besteht darin, das Datum der julianischen Nummer des Datums zuzuordnen, Ihre ganzzahligen Operationen auszuführen und dann zurück zu transformieren.

Sie finden viele Ressourcen für die julianischen Funktionen.

0

Ich würde vorschlagen, zunächst eine Routine zu schreiben, das umwandelt Jahr-Monat-Tag in eine Anzahl der Tage seit dem Fixtermin, sagen wir, seit 1.01.01. Und eine symmetrische Routine, die es zurückkonvertieren würde.

Vergessen Sie nicht Schaltjahre richtig zu verarbeiten!

Mit diesen beiden wäre Ihre Aufgabe trivial.

2

Hier ist eine Skizze eines sehr einfachen Ansatzes. Zur Vereinfachung der Ideen werde ich davon ausgehen, dass d, die Anzahl der Tage hinzuzufügen, positiv ist. Es ist einfach, das Folgende auf Fälle zu erweitern, in denen d negativ ist.

Entweder d weniger als 365 oder d größer oder gleich 365.

Wenn d weniger als 365:

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

Wenn d größer als 365:

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

Alternativ können Sie das Datum in sagen, Julian form und dann füge einfach dem Julianischen Formular hinzu und konvertiere zum ymd-Format.

+0

funktioniert für mich, danke! – aimango

7

Sie brauchen nicht wirklich einen Algorithmus als solcher (zumindest nicht etwas, das den Namen verdient), die Standardbibliothek kann die meisten schweren Arbeiten erledigen; Kalenderberechnungen sind bekanntlich knifflig.Solange Sie keine Termine müssen früher als 1900, dann gilt:

#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) ; ; 
} 

Anwendungsbeispiel:

#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

Danke für das Posten. Sehr hilfreich. – ForeverLearning

+0

Werden Schaltsekunden diese Berechnung durcheinander bringen? – vargonian

+0

@vargonian: Eine gute Frage; Die UNIX-Zeitepoche stammt vom 1. Januar 1970 und zählt keine Schaltsekunden. Die Festlegung der nominalen Tageszeit bis zur Mittagszeit wird jedoch ein potenzielles Problem für mehrere Zehntausende von Jahren vermeiden. – Clifford

1

diese Funktion versuchen. Es berechnet Additionen oder Subtraktionen korrekt. Das dateTime-Argument muss im UTC-Format sein.

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); 
} 

Und es gibt Beispiel für die Verwendung:

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

Ich weiß, dass dies eine sehr alte Frage, aber es ist eine interessante und einige gemeinsame ein, wenn es um die Arbeit mit Daten und Zeiten kommt. Also dachte ich daran, Code zu teilen, der das neue Datum berechnet, ohne eingebaute Zeitfunktionen in C++ zu verwenden.

#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 
Verwandte Themen