Algorithm to add or subtract days from a date?

后端 未结 10 1189
野的像风
野的像风 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:43

    You don't really need an algorithm as such (at least not something worthy of the name), the standard library can do most of the heavy lifting; calender calculations are notoriously tricky. So long as you don't need dates earlier than 1900, then:

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

    Example usage:

    #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 讨论(0)
  • 2020-12-01 14:44

    Here's a sketch of a very simple approach. For simplicity of ideas I will assume that d, the number of days to add, is positive. It is easy to extend the below to cases where d is negative.

    Either d is less than 365 or d is greater than or equal to 365.

    If d is less than 365:

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

    If d is greater than 365:

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

    Alternatively, you could express the date in, say, Julian form and then merely add to the Julian form and conver to ymd format.

    0 讨论(0)
  • 2020-12-01 14:45

    I'm assuming this is for some kind of an exercise, otherwise you would use a time class that's already provided to you.

    You could store your time as the number of milliseconds since a certain date. And then you can add the appropriate value and convert from that to the date upon calling the accessors of your class.

    0 讨论(0)
  • 2020-12-01 14:46

    I know it is an old question asked almost a decade before. But a few days before I came across the same for an assignment, and here is the answer as in here

    // 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 讨论(0)
  • 2020-12-01 14:47

    Don't know if this helps or not. I was working on a scheduling system which (in the first simple draft) calculated start date as due date - days lead time. I worked with seconds elapsed (since epoch) to allow greater precision in future drafts of the code.

    #include <iostream>
    #include <ctime>
    
    int main() {
      // lead time in days
      int lead_time = 20;
      // assign a due_date of (midnight on) 3rd November 2020
      tm tm_due_date = { 0, 0, 0, 3, 11, 2020-1900};
      // convert due_date to seconds elapsed (since epoch)
      time_t tt_due_date = mktime(&tm_due_date);
      // subtract lead time seconds
      tt_due_date -= 60 * 60 * 24 * lead_time;
      // convert back (to local time)
      tm *start_date = localtime(&tt_due_date);
      // otput the result as something we can readily read
      std::cout << asctime(start_date) << "\n";
    }
    
    0 讨论(0)
  • 2020-12-01 14:56

    I would suggest writing first a routine which converts year-month-day into a number of days since fixed date, say, since 1.01.01. And a symmetric routine which would convert it back.

    Don't forget to process leap years correctly!

    Having those two, your task would be trivial.

    0 讨论(0)
提交回复
热议问题