Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

year duration algorithm in c++

I'm making a program that needs the duration (in time_t) of a year.

In other ways, time_t of DD/MM/YYYY + duration = time_t of DD/MM/YYYY+1

So it may not always be 365 days (and 29/02/2012 will become 28/02/2013)

Here's the algorithm I came with :

if YEAR is leap than
    if we are before the 29th feb' than return 365+1 days
    else if we are the 29th feb' than return 365-1 days
    else return 365 days
else if YEAR+1 is leap than
    if we are before or the 28th feb' than return 365 days
    else return 365+1 days
else return 365 days

Here, a day is 60 * 60 * 24 seconds

This algorithm seems to work. But I was wondering if there were another way to do this without all theses conditions and only 2 possible return values, or just some "trick" to optimize the thing.

I tried to increment tm_year from the struct tm like this :

// t is the input time_t
struct tm Tm (*localtime(&t));
if (Tm.tm_mon == 2 && Tm.tm_mday == 29) --Tm.tm_mday;
++Tm.tm_year;
return mktime(&Tm) - t;

But the result isn't what I want, I got -1 hour, or -25...

I guess it's because a year is not exactly 365 * 24 * 60 * 60.

like image 866
perelo Avatar asked Jun 04 '12 08:06

perelo


Video Answer


2 Answers

I would use Boost for this, since it already implements what you are looking for:

#include <iostream>
#include <boost/date_time/gregorian/gregorian_types.hpp>
namespace date = boost::gregorian;

int main() {
   date::date_period dp(date::date(2012, 6, 4), date::date(2013, 6, 4));
   long days = dp.length().days();
   std::cout << "Days between dates: " << days << std::endl;

}

If you wanted more precision, then you could use posix_time from Boost too:

namespace ptime = boost::posix_time;

...

ptime::ptime t1(date::date(2012, 6, 4), ptime::hours(0));
ptime::ptime t2(date::date(2013, 6, 4), ptime::hours(0));

ptime::time_duration td = t2 - t1;
std::cout << "Milliseconds: " << td.total_milliseconds() << std::endl;

Typically time_t is measured in seconds. Therefore, you would just need to call to td.total_seconds() to obtain the value that you are looking for.

like image 167
betabandido Avatar answered Oct 10 '22 12:10

betabandido


if YEAR is leap than
    if we are before the 29th feb' than return 365+1 days
    else if we are the 29th feb' than return 365-1 days
    else return 365 days
else if YEAR+1 is leap than
    if we are before or the 28th feb' than return 365 days
    else return 365+1 days
else return 365 days

simplifies to:

if (YEAR is leap)
    if (< 29th Feb) return 365+1
    if (= 29th Feb) return 365-1
else if (YEAR+1 is leap)
    if (> 29th Feb) return 365+1

return 365

But why would you want to do this? It's much better to have readable code than "trick" optimizations.

As @betabandido has suggested, something like date(year+1, mon, day) - date(year, mon, day) would be much simpler, far more readable and able to handle leap years, leap seconds and September missing 11 days.

like image 35
aib Avatar answered Oct 10 '22 10:10

aib