我应该使用哪个boost类来存储人的年龄?

6

我需要存储用户的年龄(以年、月、日……甚至小时、分钟和秒为单位)。我正在使用C++和boost库。

我不确定应该使用boost::posix_timeboost::date_time中的哪个类。

我尝试过使用boost::posix_time::time_duration,但它并不明显,因为没有构造函数可以接受年份计数,只有小时数,所以我这样做:

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

但我不确定这是一个好策略,因为并非所有年份都有365天;-)

我也尝试了 boost::gregorian::date,但这很棘手,因为它不允许存储1400年之前的year(而这只存储日期,而不是持续时间)。

  • 我不想存储用户的出生日期,因为我需要在程序运行时存储其年龄(医疗数据)。
  • 我不想存储普通的int,因为它不够精确(24岁+11个月几乎是25岁)。
  • 我不想存储float,因为我不想重新发明轮子,需要进行浮点数转换...

在 boost 中真的没有使存储一定数量的年份、可选的月份和天数变得容易的类吗?

理想情况下,对于一个30岁半的人,我想创建这样一个对象:boost::....... theAge( 30, 6, 0 ); 然后:

  • 有一个函数可以获取年龄:theAge.years() 返回30(忽略月份)
  • 可能有一个转换为float的功能,将给我30.5作为年龄

我不想存储用户的出生日期,所以将其计算为 boost::posix_time::time_duration 的差值(当前时间 - 出生日期)。我认为对于医疗程序来说,1400 不是真正的限制。 - n. m.
问题在于我实际上不知道患者的出生日期...医生直接输入年龄作为输入。 - jpo38
如果医生输入了一个年龄,从中计算出出生日期。 - Martin Bonner supports Monica
如果你只有医生输入的年龄(以年为单位),那么就使用年龄乘以365.25乘以24。年龄通常会向下取整到最近的整数年(或对于非常小的儿童,取整到月份),所以你引入的误差(如果有误差的话)是完全微不足道的。 - n. m.
@jpo38 我知道你明确地询问了关于boost的问题,但我想指出一个备选的日期处理库:https://howardhinnant.github.io/date_v2.html。根据你的需求,这可能是一个更好的选择,例如当你需要处理时区或闰秒时(然后与https://howardhinnant.github.io/tz.html一起使用)。 - Jens
@Jens:不错的替代方案。谢谢。 - jpo38
2个回答

5

boost::posix_time::time_duration 是一种正确的方法。另一种方法(我个人更喜欢)是同时存储出生日期和“截至日期”,并在需要计算该日期年龄时将它们相减。

无论如何,您都不需要一个接受年数的构造函数——您可以从今天减去出生日期——如果您使用 date_time 对象执行此操作,您将得到一个 time_duration。


4
boost::gregorian 中确实有一些时间类型,具体如下:

这些类型非常适合于存储,例如存储一个 (年,月,日) 的元组。

需要注意的是,使用特别是monthsyears进行算术运算时可能会产生意想不到的结果,因为它们提供了以月底为结束点的行为。

months single(1); // 1 month duration
date(2005,Feb,28) + single; // => 2005-Mar-31
编辑者注:实际上,已经存在一个boost结构来存储年/月/日对象(boost::date_time::date_time::year_month_day_base)。

以下是一个完美回答原帖的实现:

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

然后,age(30).years() == 30age(30,6,8).getAsFloat() == 30.521902


不幸的是,这与使用 boost::gregorian::date 相同,因为 boost::gregorian::years 拒绝任何小于 1400 的值。 - jpo38
@jpo38 你具体是如何使用 boost::gregorian::years 的?它应该可以正常工作:http://coliru.stacked-crooked.com/a/478a0aa295da1c5a - ecatmur
我尝试了 boost::gregorian::greg_year_month_day patientAge(30,0,0); 这段代码,但是它会断言失败,因为年份必须大于 1400,月份必须在 1 到 12 之间,日期必须在 1 到 31 之间。所以我应该使用 boost::gregorian::greg_year_month_day patientAge(1430,1,1); 来表示一个 30 岁的年龄……这并不是很方便。 - jpo38
@jpo38 我并不建议使用 boost::gregorian::greg_year_month_day,我建议使用 boost::gregorian::yearsboost::gregorian::monthsboost::gregorian::days - 注意这里是复数形式。 - ecatmur
我在你的帮助下编辑了你的帖子,并写出了最终的类。谢谢! - jpo38

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接