Could you please help me how to format a struct timeval
instance to human readable format like "2010-01-01 15:35:10.0001"?
-
2Duplicate of http://stackoverflow.com/questions/1469495/unix-programming-struct-timeval-how-to-print-it-c-programming ? – David Gelhar Mar 09 '10 at 12:38
-
9Not a dup, since this one specifies human-readable formatting, pointing to stftime, while the other just extracts the seconds and useconds. – Joe Hildebrand Nov 07 '10 at 22:35
7 Answers
You need to manually append the microseconds part, since it's not in the struct tm
that strftime
() deals with. Here's a snippet:
struct timeval tv;
time_t nowtime;
struct tm *nowtm;
char tmbuf[64], buf[64];
gettimeofday(&tv, NULL);
nowtime = tv.tv_sec;
nowtm = localtime(&nowtime);
strftime(tmbuf, sizeof tmbuf, "%Y-%m-%d %H:%M:%S", nowtm);
snprintf(buf, sizeof buf, "%s.%06ld", tmbuf, tv.tv_usec);
Note how we use explicit precision of 06
to get a zero-filled microseconds field. Since the microseconds go from 0 to 999,999, it must always be padded to 6 digits. We don't want to misrepresent e.g. 57 microseconds as 570,000 (compare "1.57" vs "1.000057").

- 391,730
- 64
- 469
- 606
-
2This could be done more efficiently by saving the return value of strftime (which returns number of bytes return) and using it to index into the same buffer which can then be passed to snprintf. This would utilize one buffer and avoid the additional copy of the string from strftime(). – Nathan Doromal Sep 18 '13 at 15:02
-
2Very useful your answer and in general all this thread. Just as complement, in the last line perhaps it would be better to specify `",%s.%06ld"`. Regards – lrleon Oct 11 '15 at 16:45
-
1I'm getting a warning: format ‘%d’ expects argument of type ‘int’, but argument 5 has type ‘__suseconds_t {aka long int}’ [-Wformat=] on the last line anyway to get rid of it? – Lightsout Feb 13 '17 at 23:57
-
-
`snprintf(buf, sizeof buf, "%s.%06ld", tmbuf, tv.tv_usec)`will give compilation warning/error like below: > '%06ld' directive output may be truncated writing between 6 and 20 bytes into a region of size between 0 and 63 [-Werror=format-truncation=] – leiyc Jun 22 '22 at 01:14
Convert the tv_sec
using localtime
, and strftime
, then append tv_usec
part.

- 36,376
- 13
- 83
- 122
Combining previous answers and comments, changing the format to be RFC3339-compliant, and checking all of the error conditions, you get this:
#include <stdio.h>
#include <sys/time.h>
ssize_t format_timeval(struct timeval *tv, char *buf, size_t sz)
{
ssize_t written = -1;
struct tm *gm = gmtime(&tv->tv_sec);
if (gm)
{
written = (ssize_t)strftime(buf, sz, "%Y-%m-%dT%H:%M:%S", gm);
if ((written > 0) && ((size_t)written < sz))
{
int w = snprintf(buf+written, sz-(size_t)written, ".%06dZ", tv->tv_usec);
written = (w > 0) ? written + w : -1;
}
}
return written;
}
int main() {
struct timeval tv;
char buf[28];
if (gettimeofday(&tv, NULL) != 0) {
perror("gettimeofday");
return 1;
}
if (format_timeval(&tv, buf, sizeof(buf)) > 0) {
printf("%s\n", buf);
// sample output:
// 2015-05-09T04:18:42.514551Z
}
return 0;
}

- 1
- 1

- 10,354
- 2
- 38
- 48
ctime((const time_t *) &timeval.ts.tv_sec)
I think you are looking for this code, just for your reference.

- 9,971
- 4
- 28
- 40

- 81
- 4
-
Note that the format of the values (eg "Wed Jun 30 21:49:08 1993\n") returned by `ctime()` and `asctime()` do not match up with the OP's requirements as they do not include fractional seconds and they don't even have the seconds last so there is no easy way to append the fractional seconds afterwards. – John Hascall Sep 28 '18 at 14:58
-
Note, I agree with @JohnHascall's comment above, this does not solve the problem as stated. I'm going to leave the answer here so that nobody else is tempted to solve it this way. – Joe Hildebrand Aug 30 '20 at 18:16
You can use the strftime function to convert a date and time to a string.

- 90,689
- 19
- 115
- 207
-
1strftime takes `struct tm` as the time parameter, not `struct timeval` – Zoey Hewll Dec 09 '19 at 06:45
Convert the tv_sec using localtime_s instead of localtime, because if you are writing a global function it may cause some problems. if your function may work in a multi-threaded solution then please consider using localtime_r

- 67
- 11
This is what I use:
#include <time.h>
#include <string.h>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#define gmtime_r(ptime,ptm) (gmtime_s((ptm),(ptime)), (ptm))
#else
#include <sys/time.h>
#endif
#define ISO8601_LEN (sizeof "1970-01-01T23:59:59.123456Z")
char *timeval_to_str(char iso8601[restrict static ISO8601_LEN], unsigned precision, const struct timeval * restrict tv) {
struct tm tm;
if (!gmtime_r(&tv->tv_sec, &tm))
return memcpy(iso8601, "Error: Year overflow", sizeof "Error: Year overflow");
tm.tm_year %= 10*1000;
char *frac = iso8601 + strftime(iso8601, sizeof "1970-01-01T23:59:59.", "%Y-%m-%dT%H:%M:%SZ", &tm);
if (precision) {
unsigned long usecs = tv->tv_usec;
for (int i = precision; i < 6; i++) usecs /= 10;
char *spaces = frac + sprintf(frac - 1, ".%-*luZ", precision, usecs) - 3;
if (spaces > frac) while (*spaces == ' ') *spaces-- = '0';
}
return iso8601;
}
precision
specifies the width of the seconds fraction. Code is y10k- and yINT_MAX
-proof.

- 8,517
- 1
- 41
- 46