I am trying to get a timestamp in the YYYY-MM-DDTHH:MM:SS.SSS+HH:MM format, for e.g. 2021-10-28T07:31:56.345+05:30. The nearest I could achieve was 2021-11-03T13:06:43+0530. Notice the missing SSS after the seconds field and the missing : in 0530. This is what I have done:
#include <stdio.h>
#include <time.h>
void current_time(char* str)
{
time_t timer;
struct tm* tm_info;
time(&timer);
tm_info = localtime(&timer);
strftime(str, 50, "%FT%T%z", tm_info);
}
int main(void)
{
char str[50];
current_time(str);
printf("%s\n", str);
}
Any help would be appreciated. Thank you.
Perhaps you could use timespec_get which gets the time including nanoseconds.
#include <stdio.h>
#include <time.h>
void current_time(char* str, size_t len) {
if(len < 30) { // the final string is 29 chars + '\0'
str[0] = '\0';
return;
}
struct timespec ts;
// get timestamp inc. nanoseconds
timespec_get(&ts, TIME_UTC);
// get the second part of the timespec:
struct tm lt = *localtime(&ts.tv_sec);
// format the beginning of the string
size_t w = strftime(str, len, "%FT%T.", <);
// add milliseconds
w += sprintf(str + w, "%03d", (int)(ts.tv_nsec / 1000000));
// get zone offset from UTC
char zone[6];
strftime(zone, sizeof zone, "%z", <);
if(zone[0]) { // check that we got the offset from UTC
// add the zone to the resulting string
w += sprintf(str + w, "%.3s:", zone);
w += sprintf(str + w, "%.2s", zone + 3);
}
}
int main(void) {
char buff[100];
current_time(buff, sizeof buff);
printf("Timestamp: %s\n", buff);
}
Possible output:
Timestamp: 2021-11-03T10:05:06.696+01:00
Which matches your wanted format:
YYYY-MM-DDTHH:MM:SS.SSS+HH:MM
Related
I am using difftime() to try to subtract two dates. But consider, as in this example, I'm getting incorrect result. Here's the code:
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
const struct tm* stringToDate(const char *iDateStr)
{
struct tm *tm = (struct tm*)malloc(sizeof(struct tm));
memset(tm, 0, sizeof(struct tm));
sscanf_s(iDateStr, "%d-%d-%d", &tm->tm_mday, &tm->tm_mon, &tm->tm_year);
tm->tm_year -= 1900;
return tm;
}
const int stringDateDiffDays(const char *isDateTime1, const char *isDateTime2)
{
const struct tm *d1 = stringToDate(isDateTime1);
const struct tm *d2 = stringToDate(isDateTime2);
int diff = 0;
double diffSecs = 0;
// Seconds since start of epoch
diffSecs = difftime(mktime((struct tm*)d1), mktime((struct tm*)d2));
free((void *)d1);
free((void *)d2);
diff = (int)(diffSecs/(3600*24));
return diff;
}
int main(void)
{
char date1[] = "16-11-2017";
char date2[] = "16-12-2017";
printf("Date 1: %10s\n", date1);
printf("Date 2: %10s\n", date2);
printf("\nDifference : %d", stringDateDiffDays(date2, date1));
return 0;
}
What has happened? Is stringToDate() responsible for this, because of maybe the memset()? I am using Visual Studio 2012 to compile this code. How could I correctly implement these functions?
I have a string that contains microseconds since the epoch. How could I convert it to a time structure?
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
int main ()
{
struct tm tm;
char buffer [80];
char *str ="1435687921000000";
if(strptime (str, "%s", &tm) == NULL)
exit(EXIT_FAILURE);
if(strftime (buffer,80,"%Y-%m-%d",&tm) == 0)
exit(EXIT_FAILURE);
printf("%s\n", buffer);
return 0;
}
Portable solution (assuming 32+ bit int). The following does not assume anything about time_t.
Use mktime() which does not need to have fields limited to their primary range.
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char buffer[80];
char *str = "1435687921000000";
// Set the epoch: assume Jan 1, 0:00:00 UTC.
struct tm tm = { 0 };
tm.tm_year = 1970 - 1900;
tm.tm_mday = 1;
// Adjust the second's field.
tm.tm_sec = atoll(str) / 1000000;
tm.tm_isdst = -1;
if (mktime(&tm) == -1)
exit(EXIT_FAILURE);
if (strftime(buffer, 80, "%Y-%m-%d", &tm) == 0)
exit(EXIT_FAILURE);
printf("%s\n", buffer);
return 0;
}
Edit: You could simply truncate the string, since struct tm does not store less than 1 second accuracy.
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main ()
{
struct tm now;
time_t secs;
char buffer [80];
char str[] ="1435687921000000";
int len = strlen(str);
if (len < 7)
return 1;
str[len-6] = 0; // divide by 1000000
secs = (time_t)atol(str);
now = *localtime(&secs);
strftime(buffer, 80, "%Y-%m-%d", &now);
printf("%s\n", buffer);
printf("%s\n", asctime(&now));
return 0;
}
Program output:
2015-06-30
Tue Jun 30 19:12:01 2015
You can convert the microseconds to seconds, and use localtime() like this
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
int main (void)
{
struct tm *tm;
char buffer[80];
char *str = "1435687921000000";
time_t ms = strtol(str, NULL, 10);
/* convert to seconds */
ms = (time_t) ms / 1E6;
tm = localtime(&ms);
if (strftime(buffer, 80, "%Y-%m-%d", tm) == 0)
return EXIT_FAILURE;
printf("%s\n", buffer);
return EXIT_SUCCESS;
}
Note that in the printed date, the microseconds are not present, so you can ignore that part.
Convert the string to a time_t, then use gmtime(3) or localtime(3).
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
int main () {
struct tm *tm;
char buffer [80];
char *str ="1435687921000000";
time_t t;
/* or strtoull */
t = (time_t)(atoll(str)/1000000);
tm = gmtime(&t);
strftime(buffer,80,"%Y-%m-%d",tm);
printf("%s\n", buffer);
return 0;
}
In my C program, how can I get the date and time in the format 2013-01-11 23:34:21?
I tried
time_t now;
time(&now);
printf("%s", ctime(&now));
But it's giving it like Fri Jan 11 23:50:33 2013...
Thanks
You could use the strftime() function from <time.h>
#include <time.h>
#include <stdio.h>
int main() {
time_t now;
time(&now);
struct tm* now_tm;
now_tm = localtime(&now);
char out[80];
strftime (out, 80, "Now it's %Y-%m-%d %H:%M:%S.", now_tm);
puts(out);
}
Output
Now it's 2013-01-12 10:33:13.
Try strftime from time.h:
char timeString[20];
time_t t;
struct tm tmp;
t = time(NULL);
// TODO: Error checking if (t < 0)
tmp = localtime_r(&t, &tmp);
// TODO: Error checking if tmp == NULL
strftime(timeString, sizeof(timeString), "%Y-%m-%d %H:%M:%S", tmp));
// TODO: Error checking if returned number == sizeof(timeString)-1
How to format struct timespec to string? This structure is returned e.g. by clock_gettime() on Linux gcc:
struct timespec {
time_t tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};
One way to format it is:
printf("%lld.%.9ld", (long long)ts.tv_sec, ts.tv_nsec);
I wanted to ask the same question. Here is my current solution to obtain a string like this: 2013-02-07 09:24:40.749355372
I am not sure if there is a more straight forward solution than this, but at least the string format is freely configurable with this approach.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define NANO 1000000000L
// buf needs to store 30 characters
int timespec2str(char *buf, uint len, struct timespec *ts) {
int ret;
struct tm t;
tzset();
if (localtime_r(&(ts->tv_sec), &t) == NULL)
return 1;
ret = strftime(buf, len, "%F %T", &t);
if (ret == 0)
return 2;
len -= ret - 1;
ret = snprintf(&buf[strlen(buf)], len, ".%09ld", ts->tv_nsec);
if (ret >= len)
return 3;
return 0;
}
int main(int argc, char **argv) {
clockid_t clk_id = CLOCK_REALTIME;
const uint TIME_FMT = strlen("2012-12-31 12:59:59.123456789") + 1;
char timestr[TIME_FMT];
struct timespec ts, res;
clock_getres(clk_id, &res);
clock_gettime(clk_id, &ts);
if (timespec2str(timestr, sizeof(timestr), &ts) != 0) {
printf("timespec2str failed!\n");
return EXIT_FAILURE;
} else {
unsigned long resol = res.tv_sec * NANO + res.tv_nsec;
printf("CLOCK_REALTIME: res=%ld ns, time=%s\n", resol, timestr);
return EXIT_SUCCESS;
}
}
output:
gcc mwe.c -lrt
$ ./a.out
CLOCK_REALTIME: res=1 ns, time=2013-02-07 13:41:17.994326501
The following will return an ISO8601 and RFC3339-compliant UTC timestamp, including nanoseconds.
It uses strftime(), which works with struct timespec just as well as with struct timeval because all it cares about is the number of seconds, which both provide. Nanoseconds are then appended (careful to pad with zeros!) as well as the UTC suffix 'Z'.
Example output: 2021-01-19T04:50:01.435561072Z
#include <stdio.h>
#include <time.h>
#include <sys/time.h>
int utc_system_timestamp(char[]);
int main(void) {
char buf[31];
utc_system_timestamp(buf);
printf("%s\n", buf);
}
// Allocate exactly 31 bytes for buf
int utc_system_timestamp(char buf[]) {
const int bufsize = 31;
const int tmpsize = 21;
struct timespec now;
struct tm tm;
int retval = clock_gettime(CLOCK_REALTIME, &now);
gmtime_r(&now.tv_sec, &tm);
strftime(buf, tmpsize, "%Y-%m-%dT%H:%M:%S.", &tm);
sprintf(buf + tmpsize -1, "%09luZ", now.tv_nsec);
return retval;
}
GCC command line example (note the -lrt):
gcc foo.c -o foo -lrt
You can pass the tv_sec parameter to some of the formatting function. Have a look at gmtime, localtime(). Then look at snprintf.
You could use a std::stringstream. You can stream anything into it:
std::stringstream stream;
stream << 5.7;
stream << foo.bar;
std::string s = stream.str();
That should be a quite general approach. (Works only for C++, but you asked the question for this language too.)
Could you please help me how to format a struct timeval instance to human readable format like "2010-01-01 15:35:10.0001"?
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").
Convert the tv_sec using localtime, and strftime, then append tv_usec part.
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;
}
ctime((const time_t *) &timeval.ts.tv_sec)
I think you are looking for this code, just for your reference.
You can use the strftime function to convert a date and time to a string.
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
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.