Is There a Standard Date/Time Class in C++

A class for date and time representation in C++11

Since I cannot use C++20 I ended up with this C++11 minimal std::chrono based implementation:

utctime.h

#include <chrono>
#include <string>

struct UTCClock
{
typedef std::chrono::microseconds duration;
typedef duration::rep rep;
typedef duration::period period;
typedef std::chrono::time_point<UTCClock, duration> time_point;
static const bool is_steady = true;

//
// every time_point will be generated from here
//
static time_point fromDate(int year= 0, int month= 0, int day= 0,
int hour= 0, int min = 0, int sec= 0,
int usec= 0);
//
// convert time_point to a date/time representation
//
static void toDate(const time_point &tp,
int &year, int &month, int &day,
int &hour, int &min, int &sec,
int &usec);

// NOT Supported, we don't need current time. We only
// want to represent UTC DateTime
// static time_point now();
};

using UTCTime = std::chrono::time_point<UTCClock, std::chrono::microseconds>;

utctime.cpp

#include "utctime.h"
#include <ctime>

namespace chrono = std::chrono;
using chrono::duration_cast;
using chrono::time_point_cast;

namespace {

std::time_t to_time_t(const UTCClock::time_point &tp) noexcept
{
return std::time_t(
duration_cast<chrono::seconds>(tp.time_since_epoch()).count());
}

UTCClock::time_point from_time_t(std::time_t tt) noexcept
{
return time_point_cast<UTCClock::duration>(
chrono::time_point<UTCClock,chrono::seconds>(chrono::seconds(tt)));
}

} // namespace

UTCClock::time_point UTCClock::fromDate(
int year, int month, int day, int hour, int min, int sec, int usec)
{
std::tm tm = {0};
tm.tm_year = year - 1900;
tm.tm_mon = month - 1;
tm.tm_mday = day;
tm.tm_hour = hour;
tm.tm_min = min;
tm.tm_sec = sec;
tm.tm_isdst = -1;
std::time_t tt = timegm(&tm);
return from_time_t(tt) + chrono::microseconds(usec);
}

void UTCClock::toDate(const UTCClock::time_point &tp,
int &year,
int &month,
int &day,
int &hour,
int &min,
int &sec,
int &usec)
{
std::time_t tt = to_time_t(tp);
std::tm tm;
gmtime_r(&tt, &tm);
year = tm.tm_year + 1900;
month = tm.tm_mon + 1;
day = tm.tm_mday;
hour = tm.tm_hour;
min = tm.tm_min;
chrono::microseconds leftover =
tp - from_time_t(tt) + chrono::seconds(tm.tm_sec);
sec = duration_cast<chrono::seconds>(leftover).count();
usec = (leftover-chrono::seconds(sec)).count();
}

It can be used like this:

#include "utctime.h"
#include <iostream>

using namespace std::chrono;

int main(int argc, char* argv[])
{
//
// use UTCClock::fromDate to generate a UTCTime
//
UTCTime t1 = UTCClock::fromDate(1901, 1, 1, 0, 0, 0, 0);
UTCTime t2 = UTCClock::fromDate(1901, 1, 1, 1, 0, 0, 0);

//
// Then we can make use of std::chrono algebra like
// subtracting time_point
//
microseconds timeDiff = t2 -t1;

std::cout << "t2-t1 difference in microseconds " <<
timeDiff.count() << std::endl;
std::cout << "t2-t1 difference in hours " <<
duration_cast<hours>(timeDiff).count() << std::endl;

//
// ...or adding/subtracting a duration to a time_point
//
UTCTime t3 = t1 - minutes{3};
std::cout << "t3-t1 difference in minutes " <<
duration_cast<minutes>(t3-t1).count() << std::endl;

t3 = t1 + milliseconds{123};
std::cout << "t3-t1 difference in milliseconds " <<
duration_cast<milliseconds>(t3-t1).count() << std::endl;

//
// ...we can also compare time_points
//
if ( t3 > t1 ) std::cout << "t3 is greater than t1" << std::endl;

//
// We can get a date/time back from a time_point with UTCClock::toDate
//
int year, month, day, hour, min, sec, usec;
UTCClock::toDate(t3, year, month, day, hour, min, sec, usec);

//
// std::chrono is also type safe and doesn't allow to
// mix dates generated by different clocks
//
system_clock::time_point systp = system_clock::now();

// NO: doesn't compile
// auto tx = t1 - systp;

// NO: doesn't compile
// if (t1 < systp);

// NO: doesn't compile
// UTCClock::toDate(systp, year, month, day, hour, min, sec, usec);

return 0;
}

Output:

t2-t1 difference in microseconds 3600000000
t2-t1 difference in hours 1
t3-t1 difference in minutes -3
t3-t1 difference in milliseconds 123
t3 is greater than t1

How to get current time and date in C++?

Since C++ 11 you can use std::chrono::system_clock::now()

Example (copied from en.cppreference.com):

#include <iostream>
#include <chrono>
#include <ctime>

int main()
{
auto start = std::chrono::system_clock::now();
// Some computation here
auto end = std::chrono::system_clock::now();

std::chrono::duration<double> elapsed_seconds = end-start;
std::time_t end_time = std::chrono::system_clock::to_time_t(end);

std::cout << "finished computation at " << std::ctime(&end_time)
<< "elapsed time: " << elapsed_seconds.count() << "s"
<< std::endl;
}

This should print something like this:

finished computation at Mon Oct  2 00:59:08 2017
elapsed time: 1.88232s

C++ DateTime class

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?

Is there a standard way of representing uncertain dates in C#?

There are various academic papers on ways to represent approximate time,
e.g. http://www.musiccog.ohio-state.edu/Humdrum/representations/date.rep.html

If you want to handle the full scope of historical documents and the approximate knowledge you'll have for any of them it's not a simple bool / nullable operation with DateTime values.

I haven't seen a C# library to handle this yet. My own Natural Language Engine for C# can understand all kinds of date time phrases but was designed for a different problem - it can accept an imprecise question and query a database of exact values.

It has classes for a specific date, a range of dates, a known year (but no month/day), a known year+month (but no date), a half-infinite range (e.g. before or after a given date), ... and using these it can construct queries against databases or can enumerate all the possible ranges of dates that could be meant. e.g. you can ask it "who called last year on friday after 4pm" and it can generate the appropriate SQL query.

If you want to do this right it's not easy! If I were you, I would capture a string value with the original text in it alongside whatever representation you chose to use for the DateTime values. That way you can make the representation smarter over time to cover more cases, ultimately being able to handle something like "sometime between 1940 and September 16th 1945.

Initially you might want to store just the string representation and two DateTime values - earliest possible and latest possible date. That covers a majority of the cases you will see and it's really easy to query against. You can leave either Datetime value null or perhaps set it to maximum or minimum value to represent half-infinite ranges like "after 1900".

Why is it so convoluted to get the date and/or time in C++?

All of the tm stuff is inherited from C. C code work with functions with output parameters and return codes, so the code tends to be convoluted. Let's just take file I/O as an example:

FILE *file;
file = fopen("foo", "w");
fprintf(file, "%d", /* some number */);
fclose(file);

vs

std::ofstream ofs{"foo"};
ofs << /* some number */;

In this case, the C++ standard library just doesn't happen to contain the date functionalities, which is a shame ...


... until C++20, where Howard Hinnant's date library is voted into the standard library! The library is pretty lightweight, so don't wait until C++20 to try it out!
Here's the example in the README file:

#include "date.h"
#include <iostream>

int
main()
{
using namespace date;
using namespace std::chrono;
auto now = system_clock::now();
std::cout << "The current time is " << now << " UTC\n";
auto current_year = year_month_day{floor<days>(now)}.year();
std::cout << "The current year is " << current_year << '\n';
auto h = floor<hours>(now) - sys_days{January/1/current_year};
std::cout << "It has been " << h << " since New Years!\n";
}

(live demo)

C# like DateTime in C++

C++ doesn't have a date/time class in the standard library. But you can use Boost -

http://www.boost.org/doc/libs/1_40_0/doc/html/date_time.html

http://www.boost.org/doc/libs/1_40_0/doc/html/date_time/date_time_io.html#date_time.io_tutorial



Related Topics



Leave a reply



Submit