Boost :

Subject: Re: [boost] [gsoc 2013] chrono::date
From: Howard Hinnant (howard.hinnant_at_[hidden])
Date: 2013-04-25 23:18:16

On Apr 25, 2013, at 6:06 PM, Anurag Kalia <anurag.kalia_at_[hidden]> wrote:

> This example also proved invaluable. After tweaking it, I have a good idea now of how to use Julian Dates (+/- reasonable constant) to represent dates. Thank you!

typedef std::chrono::duration
<
std::int32_t, std::ratio_multiply<std::chrono::hours::period, std::ratio<24>>
> days;

which is a non-SI unit accepted for use with SI:

One can then, taking the current definition of the civil (gregorian) calendar, create several more units which can be quite useful:

There are exactly 7 days in a week:

typedef std::chrono::duration
<
std::int32_t, std::ratio_multiply<days::period, std::ratio<7>>
> weeks;

There are exactly 146097 days in 400 years, which could rightly be called an era:

typedef std::chrono::duration
<
std::int32_t, std::ratio_multiply<days::period, std::ratio<146097>>
> eras;

There are exactly 400 years in an era:

typedef std::chrono::duration
<
std::int32_t, std::ratio_divide<eras::period, std::ratio<400>>
> years;

And there are exactly 12 months in a year:

typedef std::chrono::duration
<
std::int32_t, std::ratio_divide<years::period, std::ratio<12>>
> months;

Now the definitions of years and months must be understood to be the average length, when converted to other units. But this is not so different than days being 24 hours: this is an average length of a day.

No one is concerned that an average month is precisely 2,629,746 seconds long. However being able to say:

assert(round<months>(jul/first/2013 - jan/first/2012).count() == 18);

is arguably quite useful. Many financial calculations are done by the month (e.g. loan interest), even though the unit of "month" isn't as precisely defined as say "second". But with a round function things could "just work".

template <class To, class Rep, class Period>
To
round(const std::chrono::duration<Rep, Period>& d)
{
To t0 = std::chrono::duration_cast<To>(d);
To t1 = t0;
++t1;
auto diff0 = d - t0;
auto diff1 = t1 - d;
if (diff0 == diff1)
{
if (t0.count() & 1)
return t1;
return t0;
}
else if (diff0 < diff1)
return t0;
return t1;
}

I'm not positive, but I believe the latest C++14 additions would allow us to mark round with constexpr, making it that much more useful. For example we could then:

static_assert(round<months>(jul/first/2013 - jan/first/2012).count() == 18, "Better be true!");

Howard