views:

871

answers:

6

Hi, 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 starts from 1. It's proving to be very complex, and google doesn't turn up much,

Does anyone know of an algorithm which does this?

+3  A: 

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.

Brian R. Bondy
Why milliseconds? He only seems to want dates, not times, and certainly not millisecond accuracy. That even hints at accounting for leap seconds.
Steve314
+1  A: 

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.

Dirk Eddelbuettel
+5  A: 

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

Mark Ransom
Thanks, this is just what I was looking for, for some reason I couldn't find the algorithm while searching the net!
waitinforatrain
A: 

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.

Vlad
A: 

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.

Jason
A: 

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