I\'ve set up a C++ server/client environment, and am trying to send a time_t value from the server to the client (an useful thing in any server). But I\'m coming accross a heada
You could send it in textual form, with a fixed number of digits. Then you don't have to worry about signs, size incompatibilities, or even byte order.
You could send a textual representation produced by strftime in combination with gmtime
. The representation would be a bit larger than a binary representation, but not huge. E.g., the format string "%Y%j%H%M%S"
produces a 13-byte representation of a moment in time (excluding a NUL character).
EDIT: forget about my previous advice to use ctime
; that uses localtime and would therefore only work if client and server are in the same timezone. And apparently, asctime
is unsafe, so use strftime
.
First, I think you need to decide if you want to deal with the issue that the C standard leaves the meaning of time_t
overly vague (it's not necessarily represented in seconds and doesn't even have any meaningful numerical properties like order/comparison). This is contrary to the behavior of every existing and historical implementation, where time_t
is in seconds. Both C and POSIX also allow time_t
to be a floating point type; as far as I know, no implementations make use of this, and on POSIX it would be rather harmful since the value of time_t
has to be an integer the way it's used in struct timespec
, etc.
If you decide you're happy assuming time_t
is always an integral number of seconds since the epoch, i.e. the values are meaningful for interchange between systems, then it's just a matter of formatting them. The safest thing to do would be to simply cast to a integer type that's large enough to store any meaningful value and that's the same size on all systems: that would be int64_t
. Then use whatever normal means you use for serializing int64_t
in a way that's immune to endian differences.
If on the other hand you want to be "absolutely" portable, you should compute your own time_t
value for "the epoch" (either the standard one or your own choice of epoch), then use difftime
to convert to a double representing "seconds since the epoch", and format the double
with snprintf(buf, sizeof buf, "%.0f", diff)
. Note that computing a time_t
value for the epoch in portable C is actually quite difficult because most of the standard functions work in local time, whereas you need universal time. There are tricks you can do with the gmtime
, mktime
, and localtime
functions to figure it out, but it's nontrivial...
Update: There seems to be a library that provides exactly what you are looking for, check out Apache Portable Runtime, specifically this page on time routines. Other than that, I would say my answer still provides a way to implement this manually, provided all systems are POSIX.1-2001 compliant.
I'm having a similar problem right now and I think it might be nice to have some instructions on how to go through with this. Note that this solution here should be POSIX.1-2001 compatible (on Ubuntu 14.04, man tzset
and man localtime
gives such information, and I haven't used other sources, really).
Use localtime
to convert the data obtained from your call to time
into a struct tm
(see time.h
):
struct tm {
int tm_sec; /* seconds */
int tm_min; /* minutes */
int tm_hour; /* hours */
int tm_mday; /* day of the month */
int tm_mon; /* month */
int tm_year; /* year */
int tm_wday; /* day of the week */
int tm_yday; /* day in the year */
int tm_isdst; /* daylight saving time */
};
Note that localtime
will set the variable declared as (again, see time.h
)
extern long timezone; //seconds West of UTC
Since all types are now known, you can write your own conversion tool to make this data network-portable. Things to consider:
int
and long
have (use sizeof
, of course)struct tm
(use htonl
or htons
- for 64bit types, you will have to write your own) and send that information to the client (in whatever way you like).timezone
(see above).The client will then have to
struct tm
(if time zones are involved, write the received time zone data into a long
)long
and compute the time zone difference (compute the difference of the received timezone
datum and what you get by calling tzset
locally...), then adjust the struct tm
variable created in step 2.struct tm
adjusted to the client's local time zone, use mktime
to convert data back into a time_t