How safe is it to assume time_t is in seconds? - c++

I'm doing a lot of calculations with times, building time objects relative to other time objects by adding seconds. The code is supposed to run on embedded devices and servers. Most documentations say about time_t that it's some arithmetic type, storing usually the time since the epoch. How safe is it to assume that time_t store a number of seconds since something? If we can assume that, then we can just use addition and subtraction rather than localtime, mktime and difftime.
So far I've solved the problem by using a constexpr bool time_tUsesSeconds, denoting whether it is safe to assume that time_t uses seconds. If it's non-portable to assume time_t is in seconds, is there a way to initialize that constant automatically?
time_t timeByAddingSeconds(time_t theTime, int timeIntervalSeconds) {
if (Time_tUsesSeconds){
return theTime + timeIntervalSeconds;
} else {
tm timeComponents = *localtime(&theTime);
timeComponents.tm_sec += timeIntervalSeconds;
return mktime(&timeComponents);
}
}

The fact that it is in seconds is stated by the POSIX specification, so, if you're coding for POSIX-compliant environments, you can rely on that.
The C++ standard also states that time_t must be an arithmetic type.
Anyway, the Unix timing system (second since the Epoch) is going to overflow in 2038. So, it's very likely that, before this date, C++ implementations will switch to other non-int data types (either a 64-bit int or a more complex datatype). Anyway, switching to a 64-bit int would break binary compatibility with previous code (since it requires bigger variables), and everything should be recompiled. Using 32-bit opaque handles would not break binary compatibility, you can change the underlying library, and everything still works, but time_t would not a time in seconds anymore, it'd be an index for an array of times in seconds. For this reason, it's suggested that you use the functions you mentioned to manipulate time_t values, and do not assume anything on time_t.

If C++11 is available, you can use std::chrono::system_clock's to_time_t and from_time_t to convert to/from std::chrono::time_point, and use chrono's arithmetic operators.
If your calculations involve the Gregorian calendar, you can use the HowardHinnant/date library, or C++20's new calendar facilities in chrono (they have essentially the same API).

There is no requirement in standard C or in standard C++ for the units that time_t represents. To work with seconds portably you need to use struct tm. You can convert between time_t and struct tm with mktime and localtime.

Rather than determine whether time_t is in seconds, since time_t is an arithmetic type, you can instead calculate a time_t value that represents one second, and work with that. This answer I wrote before explains the method and has some caveats, here's some example code (bad_time() is a custom exception class, here):
time_t get_sec_diff() {
std::tm datum_day;
datum_day.tm_sec = 0;
datum_day.tm_min = 0;
datum_day.tm_hour = 12;
datum_day.tm_mday = 2;
datum_day.tm_mon = 0;
datum_day.tm_year = 30;
datum_day.tm_isdst = -1;
const time_t datum_time = mktime(&datum_day);
if ( datum_time == -1 ) {
throw bad_time();
}
datum_day.tm_sec += 1;
const time_t next_sec_time = mktime(&datum_day);
if ( next_sec_time == -1 ) {
throw bad_time();
}
return (next_sec_time - datum_time);
}
You can call the function once and store the value in a const, and then just use it whenever you need a time_t second. I don't think it'll work in a constexpr though.

My two cents: on Windows it is in seconds over time but the time it takes for one second to increment to the next is usually 18*54.925 ms and sometimes 19*54.925. The reason for this is explained in this post.

(Answering own question)
One answer suggests that as long as one is using posix, time_t is in seconds and arithmetic on time_t should work.
A second answer calculates the time_t per second, and uses that as a factor when doing arithmetic. But there are still some assumptions about time_t made.
In the end I decided portability is more important, I don't want my code to fail silently on some embedded device. So I used a third way. It involves storing an integer denoting the time since the program starts. I.e. I define
const static time_t time0 = time(nullptr);
static tm time0Components = *localtime(&time0);
All time values used throughout the program are just integers, denoting the time difference in seconds since time0. To go from time_t to this delta seconds, I use difftime. To go back to time_t, I use something like this:
time_t getTime_t(int timeDeltaSeconds) {
tm components = time0Components;
components.tm_sec += timeDeltaSeconds;
return mktime(&components);
}
This approach allows making operations like +,- cheap, but going back to time_t is expensive. Note that the time delta values are only meaningful for the current run of the program. Note also that time0Components has to be updated when there's a time zone change.

Related

What is the proper way to process milliseconds in C++11

I'm trying to update the basic dev library of my project from C++98 to C++11.
In the dev library, there are many functions about time, such as
uint64_t getCurrentMSTime()
{
struct timeval stv;
gettimeofday(&stv, NULL);
uint64_t ms = stv.tv_sec ;
ms = ms * 1000 + stv.tv_usec / 1000;
return ms;
}
I'm trying to change it with std::chrono of C++11.
For now it seems that I have two choices, one is to return time_point, the other is to return immediately std::chrono::milliseconds::rep
std::chrono::time_point<std::chrono::system_clock> getCurrentTime1() {
return std::chrono::system_clock::now();
}
std::chrono::milliseconds::rep getCurrentTime2() {
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
}
Well, I know that the first one is more flexible because it returns a time_point, which means that we can convert it into milliseconds, nanoseconds, seconds etc, whereas the second one is return only milliseconds.
But let's say that the developers use ONLY milliseconds so we can ignore the flexible issue.
In this case, which one is better?
BTW, the developers would do something like this: std::map<std::string, ???> mp;. So my code will decide the ??? part.
std::map<std::string, std::chrono::time_point<std::chrono::system_clock>> mp{std::string("abc"), getCurrentTime1()};
vs
std::map<std::string, std::milliseconds::rep> mp{std::string("abc"), getCurrentTime2()};.
Which one is better? Or are they almost the same?
I agree with the currently accepted answer that you should value type-safety, and not return an integral type. However I disagree that returning milliseconds is best.
Type safety applies to the difference between time points and time durations as well. For example it makes perfect sense to add two time durations. But it is nonsensical to add two time points, though you can subtract them yielding a time duration.
Since the meaning of getCurrentTime() is to return the current point in time, one should return a std::chrono::time_point. One can easily choose to return a time_point based on system_clock with milliseconds precision:
std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>
getCurrentTime()
{
return std::chrono::time_point_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now());
}
In C++20, there's a convenience type alias for this type to make it a little easier to spell. You could create such a type alias for yourself if you would like to get a head start on things:
std::chrono::sys_time<std::chrono::milliseconds>
getCurrentTime()
{
return std::chrono::time_point_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now());
}
Or you can create an even shorter name for use within your application, perhaps:
using MSTime = std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>;
...
MSTime
getCurrentMSTime()
{
return std::chrono::time_point_cast<MSTime::duration>(
std::chrono::system_clock::now());
}
You certainly don't want to throw away the type information that <chrono> offers. If you convert the time_point you get from the system clock into an integral value right away, you can equally well keep the legacy function as it is.
Instead, decide upfront whether you want to handle points in time relative to the epoch or not. The old function suggests that you want this, so your function should look like this;
std::chrono::milliseconds getDurationSinceEpoch()
{
return std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch());
}
But let's say that the developers use ONLY milliseconds so we can ignore the flexible issue
Don't. What you get is here is for free. Whenever this requirement changes, and some developer mixes getDurationSinceEpoch() return values with durations in whatever resolution, it becomes quite brittle. By baking the correct units into your functions, you guard against future bugs.
Last, you want your map to have this signature:
std::map<std::string, std::chrono::milliseconds>

How do I set a C++ time_t object to the epoch?

This question is similar to the following:
convert epoch to time_t
Converting time_t to int
but I don't quite have my answer there.
If you want to get the current date/time you can call time(0) or time(NULL) like in the following standard example:
// current date/time based on current system
time_t now = time(0);
I want to define a function which will return a time_t and allows the client to pass an optional default return value in the event of an error. Further, I want to set a default on that "default" argument. This provides symmetry within a library I have with one-to-one counter parts across several languages, so I'm not looking to redesign all that.
My thought was to set the default return to the epoch. Then, a client could in theory easily evaluate that return, and decide that an epoch coming back was more than likely (if not always) an indication of it being invalid. I can think of some alternatives, but nothing clean, that also fits my existing patterns.
Is there a short and sweet way to make my function signature have a default value for this object equal to the epoch? For instance
...myfunc(...., const time_t &defVal=time(0) );
would be perfect if 0 meant the epoch rather than the current date/time!
The function std::time() returns the number of seconds since the epoch as a std::time_t. Therefore to find zero seconds after the epoch set std::time_t to zero:
std::time_t t = 0;
So you could do something like:
void myfunc(const std::time_t& defVal = 0)
What is wrong with using 0? (time_t)0 represents the epoch itself (if you want to find the actual epoch date/time, pass (time_t)0 to gmtime() or localtime()).
time_t myfunc(...., time_t defVal = 0 );
Or, you could use (time_t)-1 instead, which is not a valid time, as time() returns (time_t)-1 on error, and time_t represents a positive number of seconds since the epoch.
time_t myfunc(...., time_t defVal = (time_t)-1 );
Either way provides the user with something that is easily compared, if they don't provide their own default value.

How to properly convert a unix timestamp string to time_t in C++11?

Lets say we have a text file and read some timestamp from there into a local variable "sTime":
std::string sTime = "1440966379" // this value has been read from a file.
std::time_t tTime = ? // this instance of std::time_t shall be assigned the above value.
How do I convert this string properly into std::time assuming:
We may use STL means only (no boost).
We use the C++11 standard
We don't know which CPU architecture/OS we're using (it should work cross plattform)
We can not make any (static) assumptions on how time_t is internally defined. Of course we know that in most cases it will be an integral type, probably of 32 or 64 bit length, but according to cppreference.com the actual typedef of time_t is not specified. So atoi, atol, atoll, strtoul ... etc. are out of question at least until we have made sure by other means that we actually did pick the correct one out of those possible candidates.
This will keep your time in a standards-approved format:
Need #include <chrono>
std::string sTime = "1440966379"; // this value has been read from a file.
std::chrono::system_clock::time_point newtime(std::chrono::seconds(std::stoll(sTime)));
// this gets you out to a minimum of 35 bits. That leaves fixing the overflow in the
// capable hands of Misters Spock and Scott. Trust me. They've had worse.
From there you can do arithmetic and compares on time_points.
Dumping it back out to a POSIX timestamp:
const std::chrono::system_clock::time_point epoch = std::chrono::system_clock::from_time_t(0);
// 0 is the same in both 32 and 64 bit time_t, so there is no possibility of overflow here
auto delta = newtime - epoch;
std::cout << std::chrono::duration_cast<std::chrono::seconds>(delta).count();
And another SO question deals with getting formatted strings back out:
How to convert std::chrono::time_point to std::tm without using time_t?

Get seconds since epoch in Linux

Is there cross-platform solution to get seconds since epoch, for windows i use
long long NativesGetTimeInSeconds()
{
return time (NULL);
}
But how to get on Linux?
You're already using it: std::time(0) (don't forget to #include <ctime>). However, whether std::time actually returns the time since epoch isn't specified in the standard (C11, referenced by the C++ standard):
7.27.2.4 The time function
Synopsis
#include <time.h>
time_t time(time_t *timer);
Description
The time function determines the current calendar time. The encoding of the value is unspecified. [emphasis mine]
For C++, C++11 and later provide time_since_epoch. However, before C++20 the epoch of std::chrono::system_clock was unspecified and therefore possibly non-portable in previous standards.
Still, on Linux the std::chrono::system_clock will usually use Unix Time even in C++11, C++14 and C++17, so you can use the following code:
#include <chrono>
// make the decltype slightly easier to the eye
using seconds_t = std::chrono::seconds;
// return the same type as seconds.count() below does.
// note: C++14 makes this a lot easier.
decltype(seconds_t().count()) get_seconds_since_epoch()
{
// get the current time
const auto now = std::chrono::system_clock::now();
// transform the time into a duration since the epoch
const auto epoch = now.time_since_epoch();
// cast the duration into seconds
const auto seconds = std::chrono::duration_cast<std::chrono::seconds>(epoch);
// return the number of seconds
return seconds.count();
}
In C.
time(NULL);
In C++.
std::time(0);
And the return value of time is : time_t not long long
The native Linux function for getting time is gettimeofday() [there are some other flavours too], but that gets you the time in seconds and nanoseconds, which is more than you need, so I would suggest that you continue to use time(). [Of course, time() is implemented by calling gettimeofday() somewhere down the line - but I don't see the benefit of having two different pieces of code that does exactly the same thing - and if you wanted that, you'd be using GetSystemTime() or some such on Windows [not sure that's the right name, it's been a while since I programmed on Windows]
The Simple, Portable, and Proper Approach
#include <ctime>
long CurrentTimeInSeconds()
{
return (long)std::time(0); //Returns UTC in Seconds
}

Replacing time() and localtime() with user-independent equivalents

I have a program that uses time() and localtime() to set an internal clock, but this needs to be changed so that the internal clock is independent of the user and the "real" time. I need to be able to set any reasonable starting time, and have it count forward depending on a timer internal to the program. Any ideas on the best way to approach this? Here's the excerpt:
#define ConvertToBCD(x) ((x / 10) << 4) | (x % 10);
time_t tm;
time(&tm);
struct tm *tm_local= localtime(&tm);
tm_local->tm_year %= 100;
tm_local->tm_mon++;
timedata[0] = ConvertToBCD(tm_local->tm_year);
timedata[1] = ConvertToBCD(tm_local->tm_mon);
timedata[2] = ConvertToBCD(tm_local->tm_mday);
timedata[3] = (tm_local->tm_wday + 6) & 7;
if (!(TimeStatus & 0x02)) tm_local->tm_hour %= 12;
timedata[4] = ((tm_local->tm_hour < 12) ? 0x00 : 0x40) | ConvertToBCD(tm_local->tm_hour);
timedata[5] = ConvertToBCD(tm_local->tm_min);
timedata[6] = ConvertToBCD(tm_local->tm_sec);
A time_t, under POSIX complient systems, is just the number of seconds since the epoch, 1 Jan 1970 0:00:00.
Just add a (possibly negative) value to a time_t to change the time, ensuring that the value doesn't overflow, then use localtime as usual.
If you only need whole second resolution, then time() can be used; if you need sub-second resolution, use gettimeofday().
However, if you want to be able to control the values returned, then you will need to define yourself a surrogate for time() (or gettimeofday()). Most libraries are designed along the lines described in Plauger's The Standard C Library, and you can often provide a function called time() that behaves as you want, replacing the standard version. Alternatively, and more safely, you can revise your code to call a function of your own devising, perhaps called simulated_time(), where for production work you can have simulated_time() call the real time() (possibly via an inline function in both C99 and C++) but it can be your own version that schedules time to change as you need.
You don't need to alter your use of localtime(); it simply converts whatever time_t value you give it into a struct tm; you want it to give answers just as it always did.
The way I understand it is that you want an internal clock which gets updated according to the progress the real clock makes.
So then you would create something like this:
struct myTime
{
time_t userStart;
time_t systemStart;
time_t curTime;
};
void initTtime(struct myTime *t, time_t time)
{
t->userStart=time;
t->systemStart=time(NULL);
}
time_t getTime(struct myTime *t)
{
t->curTime = t->userStart + time(NULL)-t->systemStart;
return t->curTime;
}
so using initTime you set the current time you want to have, this gets linked to the system time at that moment in time. When you call getTime using that struct, it updates the starting point with the amount of time progressed. (Note, i haven't tested the code and you can either use the struct directly if you want).
For subsecond precision replace time() and time_t by the gettimeofday equivalent. And for conversion, ascii arting, breakdown to anything else than a second counter you can still use the unix function.