0

I know that size_t is unsigned and hence negative values are not allowed, time_t is to the best of my knowledge signed, so I am allowed to assign -1 to a size_t. However, for time_t I'm not entirely sure. If I follow the definition through the header files I end up here:

typedef __time_t time_t;

, then here:

__STD_TYPE __TIME_T_TYPE __time_t;  /* Seconds since the Epoch.  */

and finally

#define __TIME_T_TYPE       __SYSCALL_SLONG_TYPE

I'm not too sure what a __SYSCALL_SLONG_TYPE is, but I guess it is a signed long. Unfortunately, even after doing this trace, I can only hope that other c++11 platforms have the same implementation. I'm still not sure that this will be legal and well-defined for all of them:

size_t foo = -1;

Of course it makes sense to make a time_t signed, since one can have negative time offsets, for example to model time zones. But on the other hand it makes sense to have it unsigned, because there are a lot of seconds to count after 1970. So common sense goes both ways :) Googling on time_t returned this:

"For historical reasons, it is generally implemented as an integral value representing the number of seconds elapsed since 00:00 hours, Jan 1, 1970 UTC (i.e., a unix timestamp). Although libraries may implement this type using alternative time representations."

Source: http://www.cplusplus.com/reference/ctime/time_t/

and on the same page: "Portable programs should not use values of this type directly, but always rely on calls to elements of the standard library to translate them to portable types."

So time_t is not at all well-defined on all systems, however, time() returns a time_t: so I wouldn't be the first to export it in an interface. What other type should I use?

I'm asking for these two reasons:

  • Speed: Using a struct, like struct tm is slow, as it has more bytes and hence copying it or comparing it with another struct tm will be slower than doing the same with a long.
  • Ordering: I want to have a fast data type for dates, which allows me to do a < b to figure out which of the dates a and b comes first.

Question: Since time_t is not a well-defined time representation on all platforms, what kind of data type that is (1) fast and (2) comparable can I use that is portable?

For example, regarding the ordering of time_t:

#include <iostream>
#include <ctime>
#include <cstring>

int main() {
    struct tm tm_a, tm_b;
    memset(&tm_a, 0, sizeof(struct tm));
    memset(&tm_b, 0, sizeof(struct tm));
    if(strptime("2014-01-01 12:00:00", "%Y-%m-%d %H:%M:%s", &tm_a) && strptime("2014-01-01 11:59:59", "%Y-%m-%d %H:%M:%s", &tm_b)) {
        if(mktime(&tm_a) > mktime(&tm_b)) std::cout << "time_t ordering OK." << std::endl;
        else std::cout << "time_t ordering tainted" << std::endl;
    } else std::cout << "failed to parse time" << std::endl;
    return 0;
}

Will time_t be untainted on all platforms?

Herbert
  • 5,279
  • 5
  • 44
  • 69

3 Answers3

4

(time_t)(-1) already means "this is not a valid time", regardless of what time_t actually is. The standard function mktime returns this value on error, so can you.

The C and C++ standards say nothing about encoding of time in time_t. The standard function difftime computes time difference in seconds, as a double, between two times represented as time_t, and that's the only blessed way to order time_t values chronologically. However, the POSIX standard specifies that time_t is the time in seconds, so on a POSIX system it is OK to compare time_t directly with <.

Note that both C and POSIX permit time_t to be any arithmetic type (not just integral).

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • You are entirely right, thank you for this answer. Although, on my error of not being clear from the beginning, the real question would (also) be "is the ordering of a time_t type chronological according to the < operator". – Herbert Jun 14 '14 at 12:19
  • Basically, I'm wondering how **cross platform** different (mathematical) properties of a time_t are, like ordering and using negative values. – Herbert Jun 14 '14 at 12:21
  • 1
    Thank you for taking the time to re-interpreter my question and add the difftime(). That is a very valid solution for my ordering problem. – Herbert Jun 14 '14 at 12:34
1

If you need a time representation which is guaranteed to be portable between different platforms, you need to use or create a library which takes care of the differences between the platforms you use.

For example Boost.Date_Time, there you can select any representation it supports. You can even use seconds elapsed since epoch in a way which is platform independent (on all platforms supported by boost).

wimh
  • 15,072
  • 6
  • 47
  • 98
  • I moved the accept to difftime, since it is a c++/c solution, instead of an external library solution. Thank you for your valid suggestion though! – Herbert Jun 14 '14 at 12:35
0

I have become addicted to optional (via boost, or roll your own based off C++1y tr working paper).

optional<foo> is either a foo or a nullopt. You access the foo via dereerence, but the data is stored within the optional via a union. My lazy implememtation uses a pointer for the 'is it a foo or not" as that makes debugging trivial.

It both communicates failure better than flag values, and replaces a bunch of pointer-based flagging in code I write.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524