Representing dates before epoch - c++

We have a bespoke datetime C++ class which represents time in number of seconds passed since epoch. This is stored as int64. This class provides number of helper functions to read and write various types of datetime formats.
Unfortunately it cant handle dates before epoch because its methods rely on gmtime() and mktime() for many operations, which on our windows system does not support dates before epoch. Does anyone knows of replacement of gmtime and mktime which support negative values on windows.
An example of this limitation is our applicatio's inability to store birthdays before 1970, that is because every date has to use this class.
I amy not be clear on what I am asking, this is because of my limited knowledge of datetime implementation/use and my reluctance to understand that huge legacy class, so if you feel this question can be framed in another way or I might look for something different feel free to suggest.

You could use Boost.DateTime, or use the Win32 APIs directly rather than the CRT.
It's likely that you have a lot of testing ahead of you to ensure that handling of data does not change in your rework. Make sure you have exhaustive unit tests in place for the library as it stands before you begin any refactoring.
If you have to consider your values being valid across multiple different locations in the world, use UTC time as your canonical form and translate to/from local time as needed for sensible input/display.

Maybe you've solved this problem already since it was years ago, but you could also use ICU. Examples at: http://userguide.icu-project.org/datetime/calendar/examples

Coming soon to a std::lib implementation near you:
#include <chrono>
#include <iostream>
int
main()
{
using namespace std::chrono;
std::cout << "Valid range is ["
<< sys_days{year::min()/January/1} + 0us << ", "
<< sys_days{year::max()/December/31} + 23h + 59min + 59s + 999'999us
<< "]\n";
}
Output:
Valid range is [-32767-01-01 00:00:00.000000, 32767-12-31 23:59:59.999999]
Preview available here.

Related

Converting timezone offset from timezone name string in C/C++ in a thread-safe way

I'm trying to implement a function such that can convert a given timezone name string, which it does:
Accepts an input timezone string, for example, "Australia/Melbourne";
Checks host OS (assume it's a POSIX environment) timezone database;
Returns an integer of timezone offset in seconds (for Melbourne in DST, it's 36000).
It can be done by calling putenv("TZ=Australia/Melbourne") but this is may not be thread-safe.
Is there a way to do it without putenv() or somehow let it be thread-safe? Thanks in advance!
Since compilers don't yet support all the features of the C++20 std::chrono library, I will write a solution that's using Howard Hinnant's datehttps://github.com/HowardHinnant/date library. C++20 is introducing std::chrono::zoned_time which you can use to achieve what you want.
#include "date/tz.h"
#include <iostream>
int main()
{
auto current_time = std::chrono::system_clock::now();
auto la = date::zoned_time{"America/Los_Angeles", current_time};
auto sy = date::zoned_time{"Australia/Sydney", current_time};
std::cout << date::format("%T\n", sy.get_local_time() - la.get_local_time());
}
The above example will give you the difference between two time zones. Furthermore, if you want to obtain the current OS's time zone you could use something that, I hope, will be supported by compilers in future - std::chrono::time_zone::name.
In C++20, you will be able to use std::chrono::tzdb::locate_zone(), that will convert a given timezone name to a std::chrono::time_zone object that you can query to get the offset.
There is no standard C function that deals with time zones. There are POSIX.1-compliant functions, but they are indeed not thread-safe. However, depending on your operating system, you might be able to open the timezone database files and parse them manually. For example, on Linux you could open /usr/share/zoneinfo/Australia/Melbourne and parse it according to its specification in the tzfile(5) manpage.
In addition to OP's thread concerns, another consideration:
"timezone offset from timezone name string" is not sufficient in general as the offset differs depending on data/time throughout the year.
Even if no annual daylight adjustments occur in the select zone, the offset can vary due to the history of the zone.
long offset(tz_name) is not enough, long offset(tz_name, time_t t) is needed.

How should I work with day-since-epoch values before C++20 is approved?

I'm writing some code which uses days-since-some-epoch and year-month-day representations of dates, independently. edit: I should also mention that the years may theoretically be negative, and year 0 may or may not exist.
Now, C++20 will introduce an std::year_month_day class, which should be quite useful, both in itself and in interaction with my classes. For now, though, should I even use std::chrono for my dates at all, or is it too useless if I only ever add up and subtract day-resolution dates?
The extensions to <chrono> have been completely accepted. It looks to me that if you get a hold of a library containing them, it should not break when upgrading to C++20.
That said, the proposal refers to a working implementation by the author of that proposal. If it really does what you want, I suggest you use that as external library.
Important to note is that library should be able to handle all special cases you can think of related to time. Time zones, February 29 ...
Just so you don't have to consider them, I'd recommend using this class over an own implementation.
I've upvoted JVApen's answer and encourage you to accept that as the best answer. However I wanted to add just a little more information that might be helpful to you.
The C++20 proposal is set up to interoperate with multiple user-written calendars. Indeed, the working implementation that JVApen refers to actually implements several example user-written calendars. The key to having your custom calendar class interoperate with the std::chrono system is to have it do just one thing:
Implicitly convert to and from std::chrono::time_point<std::chrono::system_clock, std::chrono::duration<int, std::ratio<86400>>>.
The above awful-looking type has a more convenient name in C++20 which is just a typedef to the above type: sys_days. This is just a time_point using system_clock with a precision of days. Under the hood, this type holds nothing more than a count of days since (or before) 1970-01-01.
If your calendrical type can convert to and from this std::chrono type (which exists in C++11/14/17 except for the typedef), then you can use std::chrono to very efficiently do day-oriented arithmetic since it will literally just be adding/subtracting to an int under the hood.
And once you have this day-precision time_point, chrono makes it very easy to add "time of day" to it just by adding hours, minutes, seconds, milliseconds, whatever to it, for example:
system_clock::time_point tp = sys_days{2018y/June/3} + 14h + 15min + 36s + 123ms;
(sub in your calendrical system for 2018y/June/3)

Using std::chrono / date::gps_clock for converting a double gps timestamp to utc/tai

I get a timestamp from a GPS device in a gps_data struct as a double.
I'd like to convert this GPS timestamp to UTC and TAI times, something simple as:
void handle_gps_timestamp(double timestamp)
{
double utc = utc_from_gps(timestamp);
double tai = tai_from_gps(timestamp);
do_stuff(gps, utc, tai);
}
Luckily I found Howard Hinnant's date and timezone library (proposed for C++20) that seems to provide this exact functionality. Unfortunately, at least from what I can see, the date/tz/chrono library has no convenient methods that allow this simple usage.
I must first somehow "transfer" my double into a known chrono/date type. But OK, since I understand the overall concept, namely that the timepoint is defined as a duration after (or before) the epoch of a clock, and I think that this is a beautiful model.
Assumption
I should be able to very easily translate that model to fit my problem, right?
In my case, I have a timestamp that is a point in time, specified as the duration since the gps epoch. Now, there should be a class type of a clock that abstracts and handles all of this for me, I'd like to think. And yes! There is a date::gps_clock and a date::gps_time, which surely should do the work.
Problem
I cannot make it work for me. I'm sure the solution is trivial.
Question
Can someone give me a helping hand, showing how I should use Howard's date library applied to my problem?
It is difficult to answer this question precisely because the input to the problem is underspecified:
I get a timestamp from a GPS device in a gps_data struct as a double ... specified as the duration since the gps epoch.
Therefore I'm going to make some assumptions. I'll state all of my assumptions, and hopefully it will be clear how to alter my answer for other guesses/facts about what that double represents.
Let's say that the double is a non-integral count of milliseconds since the gps epoch. Let's furthermore assume that I want to capture the precision of this input down to microseconds.
#include "date/tz.h"
#include <cstdint>
#include <iostream>
int
main()
{
double gps_input = 1e+12 + 1e-3;
using namespace date;
using namespace std::chrono;
using dms = duration<double, std::milli>;
gps_time<microseconds> gt{round<microseconds>(dms{gps_input})};
auto utc = clock_cast<utc_clock>(gt);
auto tai = clock_cast<tai_clock>(gt);
std::cout << gt << " GPS\n";
std::cout << utc << " UTC\n";
std::cout << tai << " TAI\n";
}
I've arbitrarily created an example input and stored it in gps_input.
Some using directives make the code a lot less verbose.
A custom chrono::duration type that exactly matches the documented specification for what the double represents makes things much simpler, and lessens the chance for errors. In this case I've made a chrono::duration that stores milliseconds in a double and named that type dms.
Now you simply convert the double to dms, and then using round, convert the dms to microseconds, and store those microseconds in a gps time point with precision microseconds or finer. One could use duration_cast in place of round, but when converting from floating point to integral, I usually prefer round, which means round-to-nearest-and-to-even-on-tie.
Now that you have a gps_time, one can use the clock_cast function to convert to other times such as utc_time and tai_time.
This program outputs:
2011-09-14 01:46:40.000001 GPS
2011-09-14 01:46:25.000001 UTC
2011-09-14 01:46:59.000001 TAI
Adjust the milliseconds and microseconds units above as needed. For example if the input represents seconds, the easiest thing to do is to default the second template argument on dms:
using dms = duration<double>;
This library works with C++11/14/17. And with minor modifications it is now part of the official C++20 specification.
The other answer isn't bad but it does require you to have c++17, curl, run cmake, and acquire some custom libraries.
Something that is much easier to drop in as a .h and .cpp would be http://www.leapsecond.com/tools/gpsdate.c.
That doesn't handle the TAI conversion but that might also be on that list.

C++ date and time

I am developing an Appointment application in C++ and want to use some Date and Time features.
Is it easier to just use strings when talking about Date and Time, or should I write or get a Date/Time class?
I am wanting to code an appointment class that holds both the time and date of an appointment. Once I have coded the class file, I am wanting to integrate it into a forms application in C++ builder.
I see that there is a TMonthCalendar control. I would like to use this control when making the forms application. As such, what format for the date does this control use? I would like to use the same type as the control when making the class so that I can easily integrate it together.
UPDATE
I have found that it uses the TDateTime type. My question is this: What include statement do I need to use to use this in a console application?
C++11 includes convenience data types and functions for date/time representations, as well as their conversion to strings.
With that, you can do things like this (pretty self-explanatory, I think):
#include <iostream>
#include <iomanip>
#include <ctime>
int main()
{
std::time_t t = std::time(NULL);
std::tm tm = *std::localtime(&t);
std::cout << "Time right now is " << std::put_time(&tm, "%c %Z") << '\n';
}
In particular, there are data types std::time_t and std::tm, and a very nice IO manipulator std::put_time for pretty printing. The format strings used by it are well-documented at cppreference.
This is also supposed to work together well with locales, e.g. for a Japanese time/date format:
std::cout.imbue(std::locale("ja_JP.utf8"));
std::cout << "ja_JP: " << std::put_time(&tm, "%c %Z") << '\n';
The chrono library included in the C++11 standard library also allows you to do simple time/date arithmetic conveniently:
std::chrono::time_point<std::chrono::system_clock> now;
now = std::chrono::system_clock::now();
/* The day before today: */
std::time_t now_c = std::chrono::system_clock::to_time_t(
now - std::chrono::hours(24));
Unfortunately, not all of this is available in all compilers yet. In particular, the std::put_time function does not seem to be available in GCC 4.7.1 yet. To get the code I gave initially to work, I had to use the slightly less elegant std::strftime function:
#include <iostream>
#include <iomanip>
#include <ctime>
int main()
{
std::time_t t = std::time(NULL);
std::tm tm = *std::localtime(&t);
constexpr int bufsize = 100;
char buf[bufsize];
if (std::strftime(buf,bufsize,"%c %Z",&tm) != 0)
std::cout << "Time right now is " << buf << std::endl;
}
Is it easier to just use strings when talking about Date and Time?
No. Even simple things like calculating a duration if you have a meeting start and end date need to account for complex things such as leap years.
should I write or get a Date/Time class?
No. Writing a Date/Time Library seems simple, but it's rather difficult to get right and extremely easy to get wrong. Also, others have done it before - boost is a collection of free libraries with stellar reputation. So many others in fact, that it's become a cliche that newbie programmers want to write a Date/Time library, failing horribly at it.
I see that there is a TMonthCalendar control. [...] I have found that it uses the TDateTime type.
Relying on the same Date/Time class as your GUI framework is ok, but if you later change the GUI framework it can become an issue. Since it's not terribly hard to swap a sensible Date/Time library for another sensible Date/Time library later on, just use one that you find easy to use.

Is there a standard date/time class in C++?

Does C++ stl have a standard time class? Or do I have to convert to c-string before writing to a stream. Example, I want to output the current date/time to a string stream:
time_t tm();
ostringstream sout;
sout << tm << ends;
In this case I get the current date/time written out as a number without any formatting. I can use
c- runtime function strftime to format tm first, but that seems like it should not be necessary if the stl has a time class that can be instantiated from time_t value
Not part of STL but well known library is boost.
I would go the way of using boost::date. Here are some examples: http://www.boost.org/doc/libs/1_55_0/doc/html/date_time/date_time_io.html#date_time.io_tutorial.
If you did not try out boost yet I encourage you to do so as it saves you from a lot of nasty issues, as it masks most OS dependent things like threading for example. Many things in boost are header only (template libraries). However datetime requires a lib or dll.
EDIT
The standard "datetime" class is std::chrono::time_point since C++11. The code in the question should be roughly equivalent to
const auto now = std::chrono::system_clock::now();
const auto t_c = std::chrono::system_clock::to_time_t(now);
std::cout << std::put_time(std::localtime(&t_c), "%F %T.\n");
OLD ANSWER
Nitpicking: The STL being the Standard Template Library deals with generic container and algorithms etc. and is unlikely to incorporate classes for date handling and calculation even in the futureā€¦
The C++ Standard Library itself includes the STL and a previous version of the C standard library. The latter offers some date and time related functions via #include <ctime> which has already been mentioned above.
If wrapping (or simply using) these functions is sufficient (and quicker) than pulling in boost, go with these. There is nothing wrong with them.
C++ now has the chrono libraries for date and time.
This is documented on http://en.cppreference.com/w/cpp/chrono and http://www.cplusplus.com/reference/chrono/
There are get_time and put_time in <iomanip> header (i guess these came with C++11) which effectively does string formatting or parsing jobs.
There is also a ctime(&time_t) method which outputs string (char*).
OK. Here is closest I have found about directly writing time to a stream:
time_t t(time(NULL)); // current time
tm tm(*localtime(&t));
std::locale loc(""); // current user locale
ostringstream sout;
const std::time_put<TCHAR> &tput =
std::use_facet<std::time_put<TCHAR> >(loc);
tput.put(sout.rdbuf(), sout, _T('\0'), &tm, _T('x'));
sout << ends;
CString sTest(sout.str().c_str());
A very helpful guide is the Apache C++ Standard Library Reference Guide
http://stdcxx.apache.org/doc/stdlibref/time-put.html#sec13
Well, it's been a dozen years since this question was asked. And now (in C++20) it finally has a better answer.
Yes, there are several standard date/time classes in C++20 (not just one). Each serves different purposes in a strongly typed system. For example std::chrono::zoned_time represents a pairing of a std::chrono::time_zone and a std::chrono::time_point<system_clock, SomeDuration>, and represents the local time in some geographic area. Here is how you might create and print the local time in your current time zone to the finest sub-second precision your OS allows.
cout << zoned_time{current_zone(), system_clock::now()} << '\n';
If you need the local time somewhere else, that is just as easily obtained:
cout << zoned_time{"Africa/Casablanca", system_clock::now()} << '\n';
Unlike in previous C++ standards, time_points based on system_clock are now guaranteed to represent UTC, neglecting leap seconds (aka Unix Time). So to get the current time in UTC it is simply:
cout << system_clock::now() << '\n';
Though if you really wanted to use a zoned_time instead (for example the code may be generic), this also works:
cout << zoned_time{"UTC", system_clock::now()} << '\n';
See https://en.cppreference.com/w/cpp/chrono for many more standard date/time classes. All of them are thread-safe. And you are no longer limited to seconds precision.