Which boost class should I use to store a human age - c++

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

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.

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

Related

Getting the day info only from a date int C/C++ [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I have a program that is getting a date from some protocol, in format of DD/MM/YYYY.
The Problem is that I need to know the info of that day(day of the week, day in the year...) and I don't know how to do it.
Usually, when I want to get a day info, I am using time(time_t*) and convert the result to tm struct using localltime_r(tm*, time_t*) and then I have everything i need.
But in this case, this is not the current time(so I can not use time(time_t*)) and I don't have nothing except the date.
I can create a new tm struct and fill only tm_year, tm_mon, tm_mday and use mktime(tm*), but I am not sure if this will give me the right detail's of the desired date.
You might consider using Howard Hinnant's free, open-source date/time library. It works with C++11 and later, ported to gcc, clang and VS. It has been accepted into the C++20 draft specification.
Example code:
#include "date/date.h"
#include <iostream>
#include <sstream>
int
main()
{
using namespace std;
using namespace date;
istringstream in{"09/07/2018"};
sys_days sd;
in >> parse("%d/%m/%Y", sd);
cout << "Day of the week is " << weekday{sd} << '\n';
cout << "Day of the year is " << sd - sys_days{year_month_day{sd}.year()/1/0} << '\n';
}
Output:
Day of the week is Mon
Day of the year is 190d
If you would rather do the computations yourself, here are extremely efficient non-iterative public domain algorithms for calendrical computations. The library referenced above is nothing but a type-safe wrapper around these algorithms with more pleasant syntax.
In case you wanted to get write methods which get the day of week/year as opposed to using a library, here's what I would do.
You're going to need to take leap years into account. For any given year, determine whether or not it is a leap year. Something like this would work (using a formula found here: https://en.wikipedia.org/wiki/Leap_year#Algorithm:
bool isLeapYear(short year)
{
bool leapYear = false;
if (((year % 4 == 0 && year % 100 != 0)) || (year % 400 == 0))
leapYear = true;
return leapYear;
}
From this, calculating the day of the year is straightforward. Simply add up all the days for each month, if it is a leap year, add 29 days onto your tally for day of year if you come across February.
As for finding the day of the week, it really helps if you start with some lower bound for the year (in this case LOWYEAR = 1760) and start with the first day of that year (STARTDAYOFWEEK = 2). Each day of the week is corresponds to a number (0-6) where Sunday is 0, Monday is 1, etc.
int DayOfWeek(void)
{
//jan 1 1760 was tuesday (2)
short dayCount = STARTDAYOFWEEK;
for (unsigned i = LOWYEAR; i < year; i++)
{
if (isLeapYear(i))
dayCount += 2;
else
dayCount++;
}
return (dayCount + dayOfYear) - 1) % DAYSINWEEK;
}
Finding the day of week is now really easy, after calculating dayCount, the day of week is found by adding dayCount with dayOfYear and modding by DAYSINWEEK (6).
The resulting number will correspond to the day of week (0-6).

Find the date given the year, the month and the "nth" occurrance of day within the month C/C++

In order that a device (with limited memory) is able to manage its own timezone and daylight savings, I'm trying to calculate daylight savings triggers for 85 time zones based on a simplified description of each timezone. I have access to minimal C and C++ libraries within the device. The format of the timezone (inc. DST) description for each time zone is as follows:
UTC - the base time and date from system clock
GMTOffsetMinutes - offset from GMT with DST inactive
DSTDeltaMinutes - modifier to above with DST active (as applicable to TZ)
DSTStartMonth - month in which DST becomes active
DSTStartNthOccurranceOfDay - the nth occurrence of the day name in month
DSTDayOfWeek - Sun = 0 through to Sat = 6
DSTStartHour - hour at which DST becomes active
DSTStartMinute - minute at which DST becomes active
and corresponding EndMonth, EndNth..., EndHour, EndMinute
I have found numerous examples going the other way, i.e. starting with the date, but they involve using the modulus, keeping the remainder and dropping the quotient hence I have been unable to transpose the formula to suit my needs.
I also tried to reuse the standard "Jan = 6, Feb = 2, Mar = 2, Apr = 5, May = 0, etc. modifier table and year modifiers from the "tell me what day the 25th of June, 2067 is?" party trick and developed the following algorithm.
Date = DayOfWeek + ((NthOccuranceOfDay - 1) x 7 ) - MonthCode - YearCode
This worked for the first 6 random test dates I selected but then I started to see dates for which it failed. Is it possible that the basic algorithm is sound but I'm missing a further modifier or maybe that I'm applying the modifiers incorrectly?
Is there another solution I could utilize?
Using this open source, cross platform date library, one can write:
#include "date.h"
#include <iostream>
int
main()
{
using namespace date;
year_month_day us_daylight_starts = sys_days(sun[2]/mar/2015);
year_month_day us_daylight_ends = sys_days(sun[1]/nov/2015);
std::cout << us_daylight_starts << '\n';
std::cout << us_daylight_ends << '\n';
}
which will output:
2015-03-08
2015-11-01
The formulas this library is based on are in the public domain and documented here.
The algorithms paper has very complete unit tests validating the date algorithms over a range of millions of years (a far larger range than is necessary).
Sometimes daylight savings rules are written in terms of the last weekday of a month. That is just as easily handled:
year_month_day ymd = sys_days(sun[last]/nov/2015);
std::cout << ymd << '\n'; // 2015-11-29
That formula will be off by one week (or even two weeks) if MonthCode + YearCode is greater than or equal to DayOfWeek, because in that case you will be counting NthOccurenceOfDay from a negative date.
As an alternative, with no tables, you can compute the day of week of the first of the month using, for example, Zeller's algorithm:
int NthOccurrence(int year, int month, int n, int dayOfWeek) {
// year is the current year (eg. 2015)
// month is the target month (January == 1...December == 12)
// Finds the date of the nth dayOfWeek (Sun == 0...Sat == 6)
// Adjust month and year
if (month < 3) { --year, month += 12; }
// The gregorian calendar is a 400-year cycle
year = year % 400;
// There are no leap years in years 100, 200 and 300 of the cycle.
int century = year / 100;
int leaps = year / 4 - century;
// A normal year is 52 weeks and 1 day, so the calendar advances one day.
// In a leap year, it advances two days.
int advances = year + leaps;
// This is either magic or carefully contrived,
// depending on how you look at it:
int month_offset = (13 * (month + 1)) / 5;
// From which, we can compute the day of week of the first of the month:
int first = (month_offset + advances) % 7;
// If the dayOfWeek we're looking for is at least the day we just
// computed, we just add the difference. Otherwise, we need to add 7.
// Then we just add the desired number of weeks.
int offset = dayOfWeek - first;
if (offset < 0) offset += 7;
return 1 + offset + (n - 1) * 7;
}

Find the difference between the dates and group it under some category

I have a start date and an end date. I need to find the difference between these dates and group it under the following categories.
< 1 year, < 2 year and so on till X years.
I'm trying to write a unix C++ program for this problem.
I can easily find the unix time difference between start and end date and compare with the 1 year's time stamp (12 * 30 * 20 * 60 * 60) and so on.
Is there any C++ function that returns the difference in years given the start and end date? Also let's say, the difference is 8 years, I suppose I have to write conditions like this,
if((end_date - start_date) < 12 * 30 * 24 * 60 * 60)
group = " less than 1 year"
...
...
Until what point do I stop at, as I won't know what the maximum difference is between the dates?
Is there any easy way to compute this?
I know i'm confusing here, but i ve put all my efforts to explain the problem here. Thanks in advance.
Also note, this is not a assignment or anything.
Assuming "precise years" (in other words, all years are 365 days long) is not an issue, I would do something like this (counting the number of times each year happens in this case - since the original question doesn't really say WHAT to do with each year)
const int MAX_YEARS = 10;
const int YEAR_IN_SECONDS = 365 * 24 * 60 * 60;
std::array<int, MAX_YEARS+1> bins;
int years = static_cast<int>(difftime(end_date - start_date) / YEAR_IN_SECONDS);
// Outside of range, put it at the end of range...
// We could discard or do something else in this case.
if (years > MAX_YEARS)
{
years = MAX_YEARS;
}
bins[years]++; // Seen one more of "this year".
Obviously, what you do with "bins", and what/how you store data there really depends on what you actually are trying to achieve.
An alternative solution would be to use const double YEAR_IN_SECONDS = 365.25 * 24 * 60 * 60;, which would slightly better cover for leap-years. If you want to be precise about it, you'd have to find out if you are before or after each of the leapday in a particular year that is divisible by 4 (and keep in mind that there are special cases for years divisible by 100 and other rules at 400).
#include <chrono>
using years = std::chrono::duration<std::chrono::system_clock::rep, std::ratio<365 * 24 * 60 * 60, 1>>;
std::chrono::system_clock::time_point end_date = std::chrono::system_clock::now();
std::chrono::system_clock::time_point start_date = end_date - years(2);
years how_many = std::chrono::duration_cast<years>(end_date - start_date);
int how_many_as_int = how_many.count();
std::cout << how_many_as_int << std::endl;
std::unordered_map<int, std::list<whatever>> m;
m[how_many_as_int].push_back(...);

How to create arbitrary date and add days to it - c++

I am trying to write an application for an assignment and I am new to c++. A small portion of the application requires me to store a date and add an arbitrary number of days as an offset from the date. I know how I would accomplish this with Java or C# but I have been unable to find anything for c++. My professor alluded to ctime but after many searches all the examples I found had to do with the current system time. How do I create a ctime::tm struct and set it to an arbitrary date? Is it possible to add a number of days using ctime to obtain another date? For example, if I added 40 days to January 1, 2001 I would expect February 10, 2001 not January 41, 2001.
To be an example of usage
#include <stdio.h>
#include <time.h>
int main ()
{
time_t currentTime;
time(&currentTime);
struct tm * tmDate;
int day, month, year;
tmDate = localtime (&currentTime);
tmDate->tm_year = 99;
tmDate->tm_mon = 11;
tmDate->tm_mday = 10;
mktime ( tmDate );
printf("now: %d-%d-%d %d:%d:%d\n", tmDate->tm_year + 1900, tmDate->tm_mon + 1, tmDate->tm_mday, tmDate->tm_hour, tmDate->tm_min, tmDate->tm_sec);
return 0;
}
as you can see on
tmDate->tm_year = 99;
tmDate->tm_mon = 11;
tmDate->tm_mday = 10;
you can set, sub, add months, years, days .. to date.
For example simply you can add 1 month to date with
tmDate->tm_mon++;

C++ DateTime class

I have my own C++ DateTime class defined as:
class DateTime
{
public:
int year;
int month;
int day;
int hour;
int min;
int sec;
int millisec;
};
I have 2 DateTime which I need to compare to see which one is greater than (more recent) the other.
Is there any freely available C++ DateTime class that I can use to
Convert my DateTime class to their DateTime class
Their class should provide < , > , <= , >= operators for comparison
If a concrete example could be provided that would be great. Note that I need to compare down to millisecond.
I was thinking about Boost or Qt. Preferred Boost though.
See Boost Date Time library
And your class looks very much like struct tm
EDIT:
You're right that struct tm doesn't support millisecond precision.
Take a look at a Boost example. Does that help?
You may want to check out QDateTime from Qt, wich has the required operators and ms accuracy.
Conversion from your class could be done via
class DateTime
{
public:
int year;
int month;
int day;
int hour;
int min;
int sec;
int millisec;
QDateTime toQDateTime() {
return QDateTime(QDate(year, month, day), QTime(hour, min, sec, millisec));
}
};
The other way around is similar ;-)
I don't know of any off the top of my head. But I'd consider rewriting your date class to hold a single 64-bit integer describing milliseconds since the conventional epoch (1970 is it?). Then you are free to simply divide by 1000 and use the normal CRT functions for formatting as a string, plus you can take the value modulo 1000 to get the millisecond part.
Comparison operators then become easy..
I ditch storing dates in gregorian ages ago.
I store dates as an 32bit integer (sort of like a Julian date).
So the date is composed as (Year * 1000) + DOY (DOY is day of year).
I.e.
- 2009001 Is Jan 1 2009
- 2009365 is Dec 31 2009
My date class of course provides methods for getting the Year, Month and Day, adding, subtracting, incrementing and decrementing, comparing, getting the number of days between dates etc..
For date and time, I use 64bit float where the integer portion of the real number is the same as integer (Julian like) dates described above, and the fraction represents the time in fraction of a day.
I.e.
2009001.04166666666~ is Jan 1,2009 1:00am
2009001.06249999999~ is Jan 1,2009 1:30am
2009001.95833333333~ is Jan 1,2009 11:00pm
If you only need minute accuracy, you can use 32bit float
for date and time but you can't adequately accurately
store seconds and milliseconds.
The advantages of storing dates (and time) in this manner are:
You only need 8bytes to represent the data and time
as compared to 28bytes (assuming 32bit integers)
used by the DateTime class in the question.
Compared with dates stored as seconds from an epoch,
when looking at the number (for example in the debugger)
you can more or less identify from
the number the year and the day of year, and the approximate time of day
(to get the hour, minute, second
after midnight simply mulitply by 24, 1440, 86400 respectively).
Comparing dates is trivial, simply compare the numbers
(A single CPU operation compared to the several it
would take for the example DateTime).
Fewer comparison operations to do date arithmetic.
The disadvange of this (for time time) is a slight loss of accuracy (this is practically a mute point) and you have to do some simple rounding to get nice integer values when convering to integer values of hours minutes and seconds.
Okay, here's the final code snippet that answers my own question. I thought of sharing this in case it might helpful to some other people in the future. Thanks to Fred Larson for pointing the Boost example.
I chose Boost to do the DateTime calculation because my application already makes use of Boost somewhere else. I think I might have been able to use Qt as well, though I cant completely confirm.
Assuming DateTime is defined as:
class DateTime
{
public:
int year;
int month;
int day;
int hour;
int min;
int sec;
int millisec;
};
To do a simple DateTime comparison
bool DateTime::operator < (const DateTime& dt_)
{
using namespace boost::posix_time;
using namespace boost::gregorian;
ptime thisTime( date(this->year,this->month,this->day),
hours(this->hour) +
minutes(this->min) +
seconds(this->sec) +
boost::posix_time::millisec(int(this->millisec)) );
ptime thatTime( date(dt_.year,dt_.month,dt_.day),
hours(dt_.hour) +
minutes(dt_.min) +
seconds(dt_.sec) +
boost::posix_time::millisec(int(dt_.millisec)) );
return thisTime < thatTime;
}
To add 2 DateTime together to return a new DateTime
DateTime DateTime::operator + ( const DateTime& dt_ )
{
using namespace boost::posix_time;
using namespace boost::gregorian;
date thisDate( this->year, this->month, this->day );
date newDate = thisDate + years(dt_.year) + months(dt_.month) + days(dt_.day);
ptime newDateTime( newDate,
hours(this->hour) + hours(dt_.hour) +
minutes(this->min) + minutes(dt_.min) +
seconds(this->sec) + seconds(dt_.sec) +
boost::posix_time::millisec(int(this->millisec)) +
boost::posix_time::millisec(int(dt_.millisec))
);
DateTime dateTime;
date t1_date = newDateTime.date();
dateTime.year = t1_date.year();
dateTime.month = t1_date.month();
dateTime.day = t1_date.day();
time_duration t1_time = newDateTime.time_of_day();
dateTime.hour = t1_time.hours();
dateTime.min = t1_time.minutes();
dateTime.sec = t1_time.seconds();
dateTime.millisec = t1_time.fractional_seconds()/1000.0f;
return dateTime;
}
What's wrong with using the content of <time.h> for implementing your class? It's standard C90.
GNU R uses a struct tm replacement with microsecond precision -- instead of (integer) seconds since the epoch, it now uses a floating point number. That is really really useful. For many of my applications, I just past doubles around and yet get the time conversions.
See R-2.9.1/src/main/datetime.c in the current R sources.
Having that in a standalone C++ class would be handy though.
Look at
MFC datetime classes CTime and COleDateTime classes
More at http://www.codeproject.com/KB/datetime/datetimedisc.aspx