web-dev-qa-db-de.com

Algorithmus zum Addieren oder Subtrahieren von Tagen von einem Datum?

Ich versuche, eine Date-Klasse zu schreiben, um C++ zu lernen.

Ich versuche, einen Algorithmus zu finden, mit dem Tage zu einem Datum hinzugefügt oder von diesem abgezogen werden können, wobei Tag ab 1 und Monat ab 1 beginnen.

Kennt jemand einen Algorithmus, der das macht?

19
bcoughlan

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

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

19
Mark Ransom

Sie brauchen eigentlich keinen Algorithmus (zumindest nicht etwas, das den Namen verdient), die Standardbibliothek kann den Großteil des Schwerhebens übernehmen. Kalenderberechnungen sind bekanntermaßen schwierig. Sofern Sie keine Daten vor 1900 benötigen, gilt Folgendes:

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

Verwendungsbeispiel:

#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 ;
}
8
Clifford

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

Sie können Ihre Zeit in Millisekunden seit einem bestimmten Datum speichern. Und dann können Sie den entsprechenden Wert hinzufügen und von diesem Wert zum Datum konvertieren, wenn Sie die Zugriffsmethoden Ihrer Klasse aufrufen.

3
Brian R. Bondy

Hier ist eine Skizze eines sehr einfachen Ansatzes. Der Einfachheit halber gehe ich davon aus, dass d die Anzahl der Tage, die hinzugefügt werden müssen, positiv ist. Es ist leicht, das Folgende auf Fälle auszudehnen, in denen d negativ ist.

Entweder ist d kleiner als 365 oder d ist größer oder gleich 365.

Wenn d kleiner als 365 ist:

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 ist:

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 beispielsweise in julianischer Form ausdrücken und dann lediglich die julianische Form hinzufügen und das ymd-Format verwenden.

2
jason

Versuchen Sie diese Funktion. Es berechnet korrekt Additionen oder Subtraktionen. Das dateTime-Argument muss im UTC-Format vorliegen.

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 Beispiele für die Verwendung von:

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

Ein Ansatz besteht darin, das Datum auf die julianische Zahl des Datums abzubilden, Ihre Ganzzahloperationen auszuführen und dann zurück zu transformieren.

Sie finden viele Ressourcen für die julianischen Funktionen.

1

Ich weiß, es ist eine alte Frage, die vor fast einem Jahrzehnt gestellt wurde. Aber ein paar Tage zuvor bin ich auf dasselbe für einen Auftrag gestoßen, und hier ist die Antwort wie in hier

// C++ program to find date after adding 
// given number of days. 
#include<bits/stdc++.h> 
using namespace std; 

// Return if year is leap year or not. 
bool isLeap(int y) 
{ 
    if (y%100 != 0 && y%4 == 0 || y %400 == 0) 
        return true; 

    return false; 
} 

// Given a date, returns number of days elapsed 
// from the beginning of the current year (1st 
// jan). 
int offsetDays(int d, int m, int y) 
{ 
    int offset = d; 

    switch (m - 1) 
    { 
    case 11: 
        offset += 30; 
    case 10: 
        offset += 31; 
    case 9: 
        offset += 30; 
    case 8: 
        offset += 31; 
    case 7: 
        offset += 31; 
    case 6: 
        offset += 30; 
    case 5: 
        offset += 31; 
    case 4: 
        offset += 30; 
    case 3: 
        offset += 31; 
    case 2: 
        offset += 28; 
    case 1: 
        offset += 31; 
    } 

    if (isLeap(y) && m > 2) 
        offset += 1; 

    return offset; 
} 

// Given a year and days elapsed in it, finds 
// date by storing results in d and m. 
void revoffsetDays(int offset, int y, int *d, int *m) 
{ 
    int month[13] = { 0, 31, 28, 31, 30, 31, 30, 
                    31, 31, 30, 31, 30, 31 }; 

    if (isLeap(y)) 
        month[2] = 29; 

    int i; 
    for (i = 1; i <= 12; i++) 
    { 
        if (offset <= month[i]) 
            break; 
        offset = offset - month[i]; 
    } 

    *d = offset; 
    *m = i; 
} 

// Add x days to the given date. 
void addDays(int d1, int m1, int y1, int x) 
{ 
    int offset1 = offsetDays(d1, m1, y1); 
    int remDays = isLeap(y1)?(366-offset1):(365-offset1); 

    // y2 is going to store result year and 
    // offset2 is going to store offset days 
    // in result year. 
    int y2, offset2; 
    if (x <= remDays) 
    { 
        y2 = y1; 
        offset2 = offset1 + x; 
    } 

    else
    { 
        // x may store thousands of days. 
        // We find correct year and offset 
        // in the year. 
        x -= remDays; 
        y2 = y1 + 1; 
        int y2days = isLeap(y2)?366:365; 
        while (x >= y2days) 
        { 
            x -= y2days; 
            y2++; 
            y2days = isLeap(y2)?366:365; 
        } 
        offset2 = x; 
    } 

    // Find values of day and month from 
    // offset of result year. 
    int m2, d2; 
    revoffsetDays(offset2, y2, &d2, &m2); 

    cout << "d2 = " << d2 << ", m2 = " << m2 
        << ", y2 = " << y2; 
} 

// Driven Program 
int main() 
{ 
    int d = 14, m = 3, y = 2015; 
    int x = 366; 

    addDays(d, m, y, x); 

    return 0; 
} 
0
siddiq

Ich würde vorschlagen, zuerst eine Routine zu schreiben, die das Jahr-Monat-Tag seit dem festgelegten Datum in eine Anzahl von Tagen umwandelt, beispielsweise seit 1.01.01. Und eine symmetrische Routine, die es zurückbringen würde.

Vergessen Sie nicht, Schaltjahre richtig zu verarbeiten!

Mit diesen beiden wäre Ihre Aufgabe trivial.

0
Vlad

Ich weiß, dass dies eine sehr alte Frage ist, aber es ist eine interessante und häufige Frage, wenn es darum geht, mit Datum und Uhrzeit zu arbeiten. Also dachte ich daran, etwas Code zu teilen, der das neue Datum berechnet, ohne die eingebaute Zeitfunktionalität 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
0
SajithP