Two digit date in strftime and struct tm - c

I'm doing the following to get time in "Day Month Day Year" format.
struct tm *example= localtime(&t);
strftime(buf,sizeof(buf),"%a %b %d %Y",example);
strncpy(time_buffer,buffer,sizeof(time_buffer)) ;
But if date is single digit,such as 9 it is displayed as 9. I'd like to print it as 09. Any idea how that can be done?

The manpage for strftime says:
%d The day of the month as a decimal number (range 01 to 31).
Which seems like what you want.
// compile with: gcc -o ex1 -Wall ex1.c
#include "stdio.h"
#include "sys/time.h"
#include "time.h"
int main (const int argc, const char ** argv ) {
time_t curr_time;
char buff[1024];
// time(&curr_time);
curr_time = 1359684105; // Thu Jan 31 2013
struct tm *now = localtime(&curr_time);
strftime(buff, sizeof(buff), "%a %b %d %Y", now);
printf("time: %ld\n", curr_time);
printf("time: %s\n", buff);
curr_time += 24 * 60 * 60; // Fri Feb 01 2013
now = localtime(&curr_time);
strftime(buff, sizeof(buff), "%a %b %d %Y", now);
printf("time: %ld\n", curr_time);
printf("time: %s\n", buff);
return 0;
}
That produces:
time: 1359684105
time: Thu Jan 31 2013
time: 1359770505
time: Fri Feb 01 2013
Which looks like what you're after. If you want to drop the leading zero, you can use %e:
%e Like %d, the day of the month as a decimal number, but a leading zero is replaced by a space. (SU)
Author reported that %d doesn't adhere to the manpage on solaris, here's an alternate solution that uses sprintf directly:
// compile with: gcc -o ex1 -Wall ex1.c
#include "stdio.h"
#include "sys/time.h"
#include "time.h"
int main (const int argc, const char ** argv ) {
time_t curr_time;
char buff[1024], daynamebuff[8], monbuff[8], daynumbuff[3], yearbuff[8];
// time(&curr_time);
curr_time = 1359684105; // Thu Jan 31 2013
curr_time += 24 * 60 * 60; // Fri Feb 01 2013
struct tm *now = localtime(&curr_time);
strftime(daynamebuff, sizeof(daynamebuff), "%a", now);
strftime(monbuff, sizeof(monbuff), "%b", now);
strftime(daynumbuff, sizeof(daynumbuff), "%e", now);
strftime(yearbuff, sizeof(yearbuff), "%Y", now);
sprintf(buff, "%s %s %02d %s", daynamebuff, monbuff, now->tm_mday, yearbuff);
printf("%s\n", buff);
return 0;
}

Related

strptime() produces wrong result on armv7l environment

I have the following code:
#include <stdio.h>
#include <string.h>
#include <time.h>
time_t make_time(char *input, char *hs) {
struct tm t;
char d[17];
strcpy(d, input);
strcat(d, hs);
d[16] = '\0';
strptime(d, "%m%d%Y%H:%M:%S", &t);
printf("data: %s", asctime(&t));
return mktime(&t);
}
void main(int argc, char *argv[]) {
char *s = argv[1];
char *e = argv[2];
time_t now = time(NULL);
time_t start = make_time(s, "00:00:00");
time_t end = make_time(e, "23:59:59");
int s1 = difftime(now, start);
int s2 = difftime(end, now);
int ret = 0;
if (s1 > 0 && s2 > 0) {
ret = 1;
}
printf("Result:\nInput: %s %s\nDiff: start: %d; end: %d\nret: %d\n", s, e, s1, s2, ret);
printf("\n");
}
2 versions were built. One is for use on debian linux & the other for an arm device.
On debian linux, the result looks right:
devbox#debian:~$ ./a.out 11182015 11302015
data: Wed Nov 18 00:00:00 2015
data: Mon Nov 30 23:59:59 2015
Result:
Input: 11182015 11302015
diff: start: 665291; end: 457908
ret: 1
But on armv7l env, strptime() produces wrong result:
# /tmp/a.out 11182015 11302015
data: ??? Jan 8 ??:??:?? 1900
data: ??? Jan 8 ??:??:?? 1900
Result:
Input: 11182015 11302015
diff: start: 1448437831; end: -1448437831
ret: 0
Is there something wrong with strptime on armv7l or is it not a standard GNU C method?
UPDATE
Here is the result of uname command:
# uname -a
Linux buildroot 3.1.0-xg3517-1.1 #1 Tue Mar 12 12:54:57 JST 2013 armv7l GNU/Linux
I finally know why & make it works. The problem is: strptime() seems to have no idea how to parse the following formats:
"%m%d%Y%H:%M:%S"
// or
"%m%d%Y %H:%M:%S"
// or
"%m/%d/%Y %H:%M:%S"
But, if I use this: "%m-%d-%Y %T"
strptime(d, "%m-%d-%Y %T", &t);
Then it works, what a shame !
I don't know why those formats are not accepted, since doc didn't say anything about those which are not being fully implemented. Anyway, if anyone knows why, please shed me some light.

Getting a time difference in seconds from now to future using difftime

I am trying to find the difference in seconds from time now and a future time.
#include <time.h>
#include <stdio.h>
#include <float.h>
void main() {
time_t future = 0xFFFFFFFFFFF;
time_t now_time = time(NULL);
printf("The future time is %s\n", ctime(&future));
long double diff_in_sec = difftime(time(&future), time(&now_time));
printf("The diff in sec from now to future is %ld\n", diff_in_sec);
}
Now as i see , difftime returns double even though i try to use long double it is not possible for me to return the proper time diff in seconds. How can i achieve this?
offcourse long double doesn't make any sense there. But i only want to know is there another way i can achieve such a big diff.
Note: I am using 64bit system
time_t is not big enough to hold 0xFFFFFFFFFFF.
Try this:
printf("%0lli\n%0lli\n", future, 0xFFFFFFFFFFF);
It will return this:
-1
4294971391
The issue is with time(&future) call that modifies future. difftime() accepts the original future value on my machine:
/** $ make CC="gcc -std=c99" kingsdeb && ./kingsdeb */
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
int
main(void) {
struct tm t = {
.tm_year=559444 - 1900, .tm_mon=2, .tm_mday=8,
.tm_hour=13, .tm_min=40, .tm_sec=15, .tm_isdst=-1
};
time_t future = mktime(&t);
if (future == (time_t) -1) {
fprintf(stderr, "error: mktime returns -1 for %s", asctime(&t));
exit(EXIT_FAILURE);
}
time_t now_time = time(NULL);
if (now_time == (time_t) -1) {
perror("time");
exit(EXIT_FAILURE);
}
time_t now_from_future = future;
if (time(&now_from_future) == (time_t) -1) {
perror("time(&now_from_future)");
exit(EXIT_FAILURE);
}
double diff_in_sec = difftime(future, now_time);
if (diff_in_sec < 1 && future != now_time) {
fprintf(stderr, "difftime() returned value %f is too small\nfor "
"the time difference between (\n%s",
diff_in_sec, ctime(&future));
fprintf(stderr, "and\n%s)\n", ctime(&now_time));
exit(EXIT_FAILURE);
}
printf("The current time is %s", ctime(&now_time));
printf("time(&future) %s", ctime(&now_from_future));
printf("The future time is %s", ctime(&future));
printf("The diff in sec from now to future is %f\n", diff_in_sec);
return 0;
}
Output
The current time is Mon Sep 8 13:52:00 2014
time(&future) Mon Sep 8 13:52:00 2014
The future time is Fri Mar 8 13:40:15 559444
The diff in sec from now to future is 17590775874495.000000
The output shows that time(&ts) stores the current time into ts. Don't pass future into it.

calculating time in C - AIX machine

I am editing time value using a variable of type struct tm (adding some seconds to tm->tm_sec), but I am getting wrong results after doing mktime(&t).
Doing so in Linux gets me proper results, but in AIX not. What could be the problem?
#include <stdio.h>
#include <time.h>
#include <langinfo.h>
#include <locale.h>
int main ()
{
struct tm tm;
struct tm *end;
time_t t;
char str[20] = {'\0'};
//if (strptime("7 Feb 2013 01:47:30", "%d %b %Y %H:%M:%S", &tm) == NULL)
if (strptime("2012-10-17-01-07-30", "%Y-%m-%d-%H-%M-%S", &tm) == NULL)
{printf("Error\n");
}
tm.tm_sec = (tm.tm_sec + 1200);
//tm.tm_sec = 12;
//t = mktime(&tm);
//t = t + 12;
//end =localtime(&t);
strftime(str,20,"%Y %m %d %H %M %S",&tm);
printf("str is %s\n",str);
return 0;
}
I believe the correct answer is to use time_t, which is a large number representing the time in seconds since midnight of 1 Jan 1970. Adding arbitrary number of seconds here becomes very trivial.
I expect that if you are just adding seconds to tm->tm_sec, it overflows, and that causes the result to be incorrect. If you are unlucky, you will need to ripple your change in seconds all the way through to year (adding 5 seconds to 31 Dec 2013 23:59:56 will take you to 01 Jan 2014 00:00:01). Which of course can be done, but instead of:
t =+ 5;
you get about a dozen steps along the line of
tm.tm_sec += 5;
if (tm.tm_sec >= 60)
{
tm.tm_sec -= 60;
tm.tm_min += 1;
if (tm.tm_min >= 60)
{
... And so on ...
}
}
It gets even more interesting if you overflow the days in a month, since you then have to take into account of the number of days in each month, 28, 29, 30 or 31 depending on which month [and if it's a leap-year or not].
This is effectively what Mats said:
#include <stdio.h>
#include <time.h>
#include <langinfo.h>
#include <locale.h>
int main ()
{
struct tm tm;
time_t t;
char str[20] = {'\0'};
if (strptime("2012-10-17-01-07-30", "%Y-%m-%d-%H-%M-%S", &tm) == NULL) {
printf("error\n");
}
t = mktime(&tm);
t += 1200;
tm = *localtime(&t);
strftime(str,20,"%Y %m %d %H %M %S",&tm);
printf("str is %s\n",str);
return 0;
}
Produces:
cc -o t t.c && ./t
str is 2012 10 17 02 27 30

Order of elements in strptime

I am trying to use strptime(buf, &pattern,&result) to convert char[] containing date into tm structure.
I am using function like this:
if(strptime(buf, &pattern,&result) == NULL)
{
printf("\nstrptime failed\n");
...
and everything works if my variables are defined like this:
char buf[] = "26/10/2011";
char pattern[] = "%d/%m/%y";
struct tm result;
but if I change them into:
char buf[] = "2011/26/10";
char pattern[] = "%y/%d/%m";
struct tm result;
I get "strptime failed". Notice, that I have only put year in the beginning (both in buf and pattern).
Help appreciated. My final target is to convert string in this format: 2011-10-26T08:39:21
It's because the lower case %y is for the two-digit year within the century. Try changing it to uppercase %Y and it will work okay. You can see this from the following program:
#include <stdio.h>
#include <time.h>
int main (void) {
char buf[] = "26/10/2011";
char pattern[] = "%d/%m/%y";
struct tm result;
if (strptime (buf, pattern, &result) == NULL) {
printf("strptime failed\n");
return -1;
}
printf ("%d\n", 1900 + result.tm_year);
return 0;
}
This outputs 2020, meaning that the year is being read as just the 20 portion of 2011, with the remainder being ignored. If you use upper-case %Y, it outputs the correct 2011 instead.
Code that generates the conversion error using the reversed format:
#include <stdio.h>
#include <time.h>
int main (void) {
char buf[] = "2011/10/26";
char pattern[] = "%y/%m/%d";
struct tm result;
if (strptime (buf, pattern, &result) == NULL) {
printf("strptime failed\n");
return -1;
}
printf ("%d\n", 1900 + result.tm_year);
return 0;
}
will work fine (ie, output 2011) when you change the pattern value to "%Y/%m/%d".
Using my own 'strptime' and 'timestamp' commands, I get:
$ strptime -T '%y/%d/%m' 2011/26/11
strptime: failed to convert <2011/26/11> using format <%y/%d/%m>
$ strptime -T '%Y/%d/%m' 2011/26/11
1322294400 = 2011/26/11
$ strptime -T '%d/%m/%y' 26/11/2011
1606377600 = 26/11/2011
$ timestamp 1322294400 1606377600
1322294400 = Sat Nov 26 00:00:00 2011
1606377600 = Thu Nov 26 00:00:00 2020
$
(Time zone here is US/Pacific, currently UTC-7.)
Note that the '%d/%m/%y' format generates a date in 2020, not in 2011.

is c mktime different on Windows and GNU/Linux?

the following code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
static const char * wday_abb_names[] =
{
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat",
"Sun",
};
static void mb_setenv(const char *name, const char *value)
{
#if !(defined _WIN32) || defined HAVE_SETENV
setenv(name, value, 1);
#else
int len = strlen(name)+1+strlen(value)+1;
char *str = malloc(len);
sprintf(str, "%s=%s", name, value);
putenv(str);
#endif
}
static void mb_unsetenv(const char *name)
{
#if !(defined _WIN32) || defined HAVE_SETENV
unsetenv(name);
#else
int len = strlen(name)+2;
char *str = malloc(len);
sprintf(str, "%s=", name);
putenv(str);
free(str);
#endif
}
time_t mb_timegm(struct tm *tm)
{
time_t ret;
char *tz;
tz = getenv("TZ");
mb_setenv("TZ", "");
tzset();
ret = mktime(tm);
if (tz)
{
mb_setenv("TZ", tz);
}
else
{
mb_unsetenv("TZ");
}
tzset();
return ret;
}
time_t get_test_time()
{
struct tm msg_time;
msg_time.tm_isdst = 0;
msg_time.tm_wday = 4;
msg_time.tm_mon = 5;
msg_time.tm_mday = 16;
msg_time.tm_hour = 4;
msg_time.tm_min = 53;
msg_time.tm_sec = 0;
msg_time.tm_year = 111; //2011 - 1900
time_t retval = mb_timegm(&msg_time);
printf("final msg_time = %ld\n", retval);
return retval;
}
void print_time(const char *msg, struct tm *t)
{
printf("%s %s, %02d.%02d.%2d %2d:%02d\n", msg,
wday_abb_names[t->tm_wday], t->tm_mday, t->tm_mon, t->tm_year,
t->tm_hour, t->tm_min);
}
int main()
{
printf( "=== ENVIRON ===\n");
printf("TZ = %s\n", getenv("TZ"));
time_t now;
struct tm l, g;
time(&now);
l = *localtime(&now);
g = *gmtime(&now);
print_time("Local time :", &l);
print_time("utc :", &g);
printf("=== END ENVIRON ===\n\n");
time_t tt = get_test_time();
printf("fix test (16.6.2011 04:53) --> %s\n", ctime(&tt));
printf("done.\n");
return 0;
}
running on GNU/Linux it produces:
=== ENVIRON ===
TZ = (null)
Local time : Sat, 24.05.111 14:20
utc : Sat, 24.05.111 12:20
=== END ENVIRON ===
final msg_time = 1308199980
fix test (16.6.2011 04:53) --> Thu Jun 16 06:53:00 2011
done.
running on Win7 it produces:
=== ENVIRON ===
TZ = (null)
Local time : Sat, 24.05.111 14:25
utc : Sat, 24.05.111 12:25
=== END ENVIRON ===
final msg_time = 1308196380
fix test (16.6.2011 04:53) --> Thu Jun 16 05:53:00 2011
done.
Both Systems have a Timezone of UTC+1 including DST (that makes UTC+2 in effect) and both systems are not having any time-problems at all - except for the difference displayed.
As you can see, the "final msg_time" is missing exactly 3600 seconds, so it is not a problem in ctime.
Can anybody explain to me why mktime seems to behave different on GNU/Linux and Windows - or how to correct that?
Edit:
Both systems (after calling tzset()) are reporting tzname[0] = CET, tzname[1] = CEST, daylight=1, timezone = -3600
My mb_timegm was based on the code stated in man 3 timegm and it stated
"set the TZ environment variable to UTC" to do this setenv("TZ", ""); is called.
However - this does not work on windows.
Using setenv("TZ", "UTC"); (or, in the above case mb_setenv) instead fixes the problem.
I'm assuming based on the info your provided where daylight savings time is in effect, that you would need to set msg_time.tm_isdst in get_test_time() to a value of 1 rather than 0. This may be the issue accounting for the missing hour. Either that, or you could set it to -1 and allow the system to attempt to figure out if you are in daylight savings time or not for the given input value.

Resources