Algorithm to add or subtract days from a date?

后端 未结 10 1190
野的像风
野的像风 2020-12-01 14:10

I\'m trying to write a Date class in an attempt to learn C++.

I\'m trying to find an algorithm to add or subtract days to a date, where Day starts from 1 and Month s

相关标签:
10条回答
  • 2020-12-01 14:58

    I know this is a very old question but it's an interesting and some common one when it comes to working with dates and times. So I thought of sharing some code which calculates the new date without using any inbuilt time functionality 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
    
    0 讨论(0)
  • 2020-12-01 15:02

    The easiest way is to actually write two functions, one which converts the day to a number of days from a given start date, then another which converts back to a date. Once the date is expressed as a number of days, it's trivial to add or subtract to it.

    You can find the algorithms here: http://alcor.concordia.ca/~gpkatch/gdate-algorithm.html

    0 讨论(0)
  • 2020-12-01 15:05

    One approach is to map the date to the Julian number of the date, do your integer operations and then transform back.

    You will find plenty of resources for the julian functions.

    0 讨论(0)
  • 2020-12-01 15:07

    Try this function. It correctly calculates additions or subtractions. dateTime argument must be in UTC format.

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

    And there are example of using:

    time_t t = time(NULL);
    tm* utc = gmtime(&t);
    tm* newUtc = dateTimeAdd(utc, -5, 0, 0, 0); //subtract 5 days
    
    0 讨论(0)
提交回复
热议问题