Order of elements in strptime - c

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.

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.

Printing out current date

Implement a function that determines and prints out the current year, month and day. For example:
Today is 03/04/2014.
Code so far that I have:
#include <stdio.h>
#include <time.h>
int main ()
{
int days, weeks, months, years, option, rmd, currentyear, currentmonth;
int daysinjan, daysinfeb, daysinmarch;
time_t seconds;
seconds = time(NULL);
days = seconds/(60*60*24);
weeks = seconds/((60*60*24)*7);
rmd=seconds%31557600;
months = ((seconds/31557600) * 12)+(((float)rmd/31557600)*12);
years = days/(365.25);
currentyear = 1970 + years;
currentmonth = (((float)rmd/31557600)*12)+1;
printf("%ld/%ld", currentmonth,currentyear);
return 0;
}
Please do not mind all the useless stuff in the code, this question is part of a project and i simply used the code from my previous question to try and work with that code in order to solve this question. The problem i have is that i cannot print the current day of the month that it is, because of this i feel that i have gone about this question wrongly.
This uses standard library calls to do all the math for you.
From Here:
#include <time.h>
#include <stdio.h>
#define SIZE 256
int main (void)
{
char buffer[SIZE];
time_t curtime;
struct tm *loctime;
/* Get the current time. */
curtime = time (NULL);
/* Convert it to local time representation. */
loctime = localtime (&curtime);
/* Print out the date and time in the standard format. */
fputs (asctime (loctime), stdout);
/* Print it out in a nice format. */
strftime (buffer, SIZE, "Today is %A, %B %d.\n", loctime);
fputs (buffer, stdout);
strftime (buffer, SIZE, "The time is %I:%M %p.\n", loctime);
fputs (buffer, stdout);
return 0;
}
If you wanted to create this as a function to return a string, you could do it like this:
char * getTimeString (char *str)
{
//replace this comment with relevant code from above with (at least) two additional lines:
strcpy(str, buffer);
return str;
}
Call it like this:
int main(void)
{
char *timeStr;
timeStr = malloc(30);//sufficient length to accept values assigned in getTimeString()
printf("%s\n", getTimeString(timeStr);
free(timeStr);
return 0;
}
#include <time.h> // for time_t
#include <stdio.h> // for printf
int main () {
int days, weeks, months, years, option, rmd, currentyear, currentmonth;
int daysinjan, daysinfeb, daysinmarch;
time_t seconds;
seconds = time(NULL);
days = seconds/(60*60*24);
weeks = seconds/((60*60*24)*7);
rmd=seconds%31557600;
months = ((seconds/31557600) * 12)+(((float)rmd/31557600)*12);
years = days/(365.25);
currentyear = 1970 + years;
currentmonth = (((float)rmd/31557600)*12)+1;
printf("%ld/%ld", currentmonth,currentyear);
return 0;
}

C code for date time format validation. specified format is "YYYYMMDDHHMMSSmmmmmm"

I need to validate a date-time value for "YYYYMMDDHHMMSSmmmmmm" format. Actually what I am hoping is I need to find out a already tested working C code to validate a date time value for above format.
Further, I have a date-time value like 201304011031000000. I need a function to verify whether this is a valid date or not.[isdatetime()]
Below are the each parts of formats.
YYYY : Year
MM : Month
DD : Day
HH : hour
MM : Minutes
SS : seconds
mmmmmm: micro-seconds
If you're on a POSIX system, this looks like something that should be handled with strptime(), but the 'milliseconds' (or microseconds) part is not handled by strptime() or any other standard conversion function I know of.
Assuming the question is asking for microseconds, you could use a variation on the theme provided by:
#include <stdio.h>
#include <string.h>
#include <time.h>
int main(void)
{
const char datetime[] = "20130417221633012345"; // YYYYMMDDHHMMSSFFFFFF
struct tm time_val;
unsigned microsecs;
const char *end = strptime(datetime, "%Y%m%d%H%M%S", &time_val);
if (end != 0)
{
int nbytes;
if (strlen(end) == 6 && sscanf(end, "%6u%n", &microsecs, &nbytes) == 1 &&
nbytes == 6)
{
char buffer[32];
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &time_val);
printf("%s = %s.%.6u\n", datetime, buffer, microsecs);
}
}
return 0;
}
Revised requirement
#include <stdio.h>
#include <string.h>
#include <time.h>
int isdatetime(const char *datetime)
{
// datetime format is YYYYMMDDHHMMSSFFFFFF
struct tm time_val;
unsigned microsecs;
int nbytes;
const char *end = strptime(datetime, "%Y%m%d%H%M%S", &time_val);
if (end != 0 && strlen(end) == 6 &&
sscanf(end, "%6u%n", &microsecs, &nbytes) == 1 && nbytes == 6)
return 1; // Valid
return 0; // Invalid
}
You can use regex.h for windows or for linux.
"YYYYMMDDHHMMSSMSSSSS" is something like: (\d{4}[0,1][0,9]\d{})... you can find your specific format here, it depends wether you enable 24 or 12 clock etc.

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

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