Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Which boost class should I use to store a human age

Tags:

c++

boost

I have to store an age (years, months, days....possibly hours, minutes, seconds) of the user. I'm working with C++ and boost.

I'm not sure wich class of boost::posix_time (or boost::date_time) I should use.

I tried boost::posix_time::time_duration, but it's not obvious because there is no constructor taking a year count, it's only hours, so I did:

boost::posix_time::time_duration age = boost::posix_time::hours(24*365*ageInYears);

But I'm not sure that's a good strategy because all years does not have 365 days ;-)

I also tried boost::gregorian::date, but that's tricky because this one does not allow to store a year before 1400 (and this stores a date, not a duration).

  • I don't want to store user date of birth because I need to store its age when my program ran (medical data).
  • I don't want to store a regular int because it's not accurate enough (24 years old + 11 months is almost 25).
  • I don't want to store a float because I don't want to reinvent the wheel with float to age conversion I would have to do...

Is there really no class making it easy to store a number of years and optionally a number of month and days in boost?

Ideally, for a guy of 30 years old and a half, I'd like to be able to create an object like that: boost::....... theAge( 30, 6, 0 ); and then:

  • Have a function to get age in years: theAge.years() returning 30 (ignoring months)
  • Possibly have a conversion to float that would give me 30.5 as an age
like image 303
jpo38 Avatar asked Dec 16 '15 08:12

jpo38


2 Answers

There are indeed duration types in boost::gregorian, specifically:

  • boost::gregorian::date_duration (aka boost::gregorian::days) - a count of days
  • boost::gregorian::months - a count of calendar months
  • boost::gregorian::years - a count of calendar years
  • boost::gregorian::weeks - a count of 7 days

These would be ideal for storage i.e. store a tuple of (years, months, days).

Note though that arithmetic using in particular months and years can have unexpected results, as they provide a snap-to-end-of-month behavior:

months single(1); // 1 month duration
date(2005,Feb,28) + single; // => 2005-Mar-31

Edit from OP owner: There's actually a an existing boost struct to store year/month/day objects (boost::date_time::date_time::year_month_day_base).

Here is an implementation perfect to answer the OP:

class age : public date_time::year_month_day_base<years, months, days>
{
    typedef date_time::year_month_day_base<years, months, days> baseClass;
public:
    age( int yearsCount, int monthsCount = 0, int daysCount = 0 ) : 
        baseClass( boost::gregorian::years(yearsCount), 
                   boost::gregorian::months(monthsCount), 
                   boost::gregorian::days(daysCount) )
    {
    }

    inline int years() const { return year.number_of_years().as_number(); }
    inline int months() const { return month.number_of_months().as_number(); }
    inline int days() const { return day.days(); }

    float getAsFloat() const
    {
        float age = static_cast<float>(years());
        age += months()/12.0f;
        age += days()/365.25f;
        return age;
    }
};

Then, age(30).years() == 30 and age(30,6,8).getAsFloat() == 30.521902

like image 31
ecatmur Avatar answered Nov 12 '22 01:11

ecatmur


boost::posix_time::time_duration really is one way to do this properly. Another way (which I personally would prefer) is to store the birth date and the "as-of date" both, and subtract them when you need to find the age as-of that date.

In any case you don't need a constructor taking a number of years--you can simply subtract birth_date from today--if you do that using date_time objects, you'll get a time_duration.

like image 115
John Zwinck Avatar answered Nov 12 '22 00:11

John Zwinck