[Last Call] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1599
  • Last Modified:

strptime not recognizing timezone

#include <stdio.h>
#include <time.h>
#include <cstring>
#include <time.h>
int main() {
   char * p = "31-Dec-2002 22:36:36 -0800";
   time_t epoch;

   struct tm tm;

   memset( &tm, 0, sizeof(tm) );

   // Epoch time 0
 /*
  date.tm_hour = -8;
   date.tm_mday = 1;
   date.tm_year = 1970 - 1900;
 */
epoch = mktime( &tm);
   printf(" Epoch = %d\n", epoch);

   if (strptime("31-Dec-2002 22:36:36 -0800", "%d-%b-%Y %H:%M:%S %Z", &tm)==NULL){printf( "error\n");}



printf("year: %d; month: %d; day: %d;\n",
        tm.tm_year, tm.tm_mon, tm.tm_mday);
printf("hour: %d; minute: %d; second: %d\n",
        tm.tm_hour, tm.tm_min, tm.tm_sec);
printf("week day: %d; year day: %d\n", tm.tm_wday, tm.tm_yday);


tm.tm_isdst = -1;
 /* Not set by strptime(); tells mktime()
                          to determine whether daylight saving time
                          is in effect */

  epoch = mktime( &tm);


   printf(p); printf("\n");
   printf(" Epoch = %d\n", epoch);
}

#include <stdio.h>
#include <time.h>
#include <cstring>
#include <time.h>
int main() {
   char * p = "31-Dec-2002 22:36:36 -0800";
   time_t epoch;

   struct tm tm;

   memset( &tm, 0, sizeof(tm) );

   // Epoch time 0
 /*
  date.tm_hour = -8;
   date.tm_mday = 1;
   date.tm_year = 1970 - 1900;
 */
epoch = mktime( &tm);
   printf(" Epoch = %d\n", epoch);

   if (strptime("31-Dec-2002 22:36:36 -0800", "%d-%b-%Y %H:%M:%S %Z", &tm)==NULL){printf( "error\n");}



printf("year: %d; month: %d; day: %d;\n",
        tm.tm_year, tm.tm_mon, tm.tm_mday);
printf("hour: %d; minute: %d; second: %d\n",
        tm.tm_hour, tm.tm_min, tm.tm_sec);
printf("week day: %d; year day: %d\n", tm.tm_wday, tm.tm_yday);


tm.tm_isdst = -1;
 /* Not set by strptime(); tells mktime()
                          to determine whether daylight saving time
                          is in effect */

  epoch = mktime( &tm);


   printf(p); printf("\n");
   printf(" Epoch = %d\n", epoch);
}

Open in new window

0
Vlearns
Asked:
Vlearns
  • 9
  • 7
  • 7
  • +1
2 Solutions
 
VlearnsAuthor Commented:
hi in the code above


the time zone -0800 seems to be ignored by strptime, can some one help whats wrong or suggest any way by which i can correctly convert
"31-Dec-2002 22:36:36 -0800" to utc epoch time

thanks

0
 
jb1devCommented:
%Z expects a timezone name (like "PDT") not an offset. See this link:

http://www.experts-exchange.com/expertsZone.jsp
0
 
jb1devCommented:
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
phoffricCommented:
Are you required to use strptime? It is not fully portable yet to other platforms. In fact, the %Z is under a category called GNU extension, which sounds like using %Z is even less portable even if strptime is supported.

See %z and %Z definition in strftime (strptime is supposed to use similar definitions):
http://linux.die.net/man/3/strftime

Here is another link that may assist:
http://www.experts-exchange.com/Programming/Languages/C/Q_24684311.html?sfQueryTermInfo=1+strptime

0
 
VlearnsAuthor Commented:
my bad understanding then


could you help change my code to use strftime instead of strptime..

i am finding the conversion a bit confusing

strftime seems to correctly handle offsets from the man page link
0
 
phoffricCommented:
Someone else may have a solution in using strptime if you want to go that course.

Otherwise, I am thinking that you can use scanf or strtok to parse. I'll be back in a few hours to assist. In the meantime, why not take a stab at using scanf or strtok to start the process. Post your code, and we'll be happy to help.
0
 
phoffricCommented:
Vlearns:
re: "change my code to use strftime instead of strptime"
strftime is an inverse function of strptime (at least that's what I recently learned, since my two platforms do not support strptime, and I never heard of it before). So, strftime yields an ascii string based on a formatting string that is described in http://linux.die.net/man/3/strftime. You are trying to go the other way around. You are starting with with a date/time string and are trying to get to an unix epoch time.

jb1dev,
The link you provided appears to be python related. Do you know if the python definition applies to the c-environment?
0
 
VlearnsAuthor Commented:
yes... any ideas????
0
 
phoffricCommented:
I recommend whichever approach you either feel comfortable, or wish to learn about:
1. use scanf to parse
2. use strtok to parse and convert strings to atoi where applicable
3. parse using your own code, one char at a time
Please review the two functions. If you are taking a course, both of them are important to know about. (Granted, scanf does have some controversial issues - but not to worry at this time.)

Do you need help with designing the parsing? If so, we can talk it through. Give an approach, and I'll be happy to critique it. Or, if you have specific questions, I'll try to answer them.

Is this related to homework?
0
 
Infinity08Commented:
>> strptime not recognizing timezone

strptime could parse your timezone (with %Z or %z in gcc eg.), but it doesn't put it in the tm struct, because there's no timezone information in the tm struct.

Furthermore, proper handling of DST complicates things even more.

Parsing it manually, and adjusting for timezone and DST as needed seems the way to go.
0
 
VlearnsAuthor Commented:
hi

thank you all for the responses

" parsing it manually, and adjusting for timezone and DST as needed seems the way to go."

are you suggesting that we should not use tm struct?

or rather use the tm  struct and then add/subract time zone? can you point me to an example that does this?
0
 
Infinity08Commented:
>> are you suggesting that we should not use tm struct?

The tm struct can't account for timezone information. So if you wanted, you could use it, up to the moment you want to add the timezone offset.

You could fill up the tm struct with all information you have, then use mktime to get the seconds since the epoch (remember that this is in local time). Finally adjust that value with the timezone (relative to the local timezone) and DST information.

Or you could fill up the tm struct with all information you have, then adjust the tm struct members to take into account the timezone and DST information, and finally use mktime to calculate the seconds since the epoch (again remember that this is done in local time, so you need to adjust for that too).

The first approach looks easier.
0
 
VlearnsAuthor Commented:
You could fill up the tm struct with all information you have, then use mktime to get the seconds since the epoch (remember that this is in local time). Finally adjust that value with the timezone (relative to the local timezone) and DST information.


if i run the program i pasted above

 Epoch = 0
31-Dec-2002 22:36:36 -0800
 Epoch = 1041374196

the result above doesnot account for -8000

should i do a Epoch = 1041374196 - 0800 = 1041373396

if i put this resulting 1041373396 at http://www.epochconverter.com/ i get the result as


GMT: Tue, 31 Dec 2002 22:23:16 GMT
Your timezone: Tuesday, December 31, 2002 2:23:16 PM


which is not  the same as 1041374196

also i have entered the date  31-Dec-2002 22:36:36 on the website and found the resulting Epoch = 1041374196  which is same as the output of the program which tells us that the epoch time is correct (minus the timezone info -0800) how do i use -0800?

thanks






0
 
Infinity08Commented:
>>  Epoch = 1041374196

Remember that this is adjusted for your local timezone. mktime interpreted the time 31-Dec-2002 22:36:36 in your local timezone, then calculated the time in the GMT timezone at that moment, and got the number of seconds since the epoch for that time.

For example, since my local timezone is GMT+1, if it is 31-Dec-2002 22:36:36 over here, it is 31-Dec-2002 21:36:36 in the GMT timezone (1 hour earlier). And the seconds since the epoch are thus : 1041370596.

Since you get 1041374196, that would mean that your local timezone is set to GMT. Right ?


>> should i do a Epoch = 1041374196 - 0800 = 1041373396

It seems you just subtracted 800. There are 3600 seconds in an hour, and 8*3600 seconds in 8 hours.


What should happen is that you first have to adjust for your local timezone and local DST. In your specific case (since your local timezone is already GMT, and there's no DST in december), no adjustment is needed. But in the general case, you will have to adjust for the local timezone and DST. That way, the seconds since the epoch will be for the time interpreted in the GMT timezone.

Then you have to adjust again, but this time for the target timezone.

Let's take my case (local timezone is GMT+1) as the example :

1) first adjust 1041370596 by adding 3600 (1 hour) to get it from the local timezone to the GMT timezone :

        1041370596 + 3600 = 1041374196

2) then adjust 1041374196 by adding 8*3600 (8 hours) to get it from the GMT timezone to the target timezone  (-0800) :

        1041374196 + 8*3600 = 1041402996

This corresponds to : Wed, 01 Jan 2003 06:36:36 GMT
0
 
phoffricCommented:
In previous post, http://www.experts-exchange.com/OS/Unix/Q_24998178.html, I show how to take the parsed values and insert them into struct tm, and then use mktime to obtain the epoch time. Also shown is a general example of how to use strtok for parsing. And I said that we could fine-tune the timezone issues once we had a parser working.

But, from your previous post, I see that you wish to deal with your original question about "strptime not recognizing timezone".

As I mentioned, strptime has not been added to my two compilers (on Cygwin and Windows), so I cannot assist you there. But I have some comments on your output.

Your first output is:   Epoch = 0
This corresponds to Jan 1, 1970 00:00:00 zulu time.
But your program says:
   struct tm tm;
   memset( &tm, 0, sizeof(tm) );
   epoch = mktime( &tm);
   printf(" Epoch = %d\n", epoch);

With the entire struct tm zero'd out, we have an invalid case:
 (See http://www.cplusplus.com/reference/clibrary/ctime/tm/)
since tm_mday ~ day of the month ~ must be in range 1-31.

In fact, I ran this on both cygwin and Visual Studio and got -1, which is the error return code of mktime. So, I'm not sure how you got "Epoch = 0".

I think it is important to know what epoch time you get when you plug in a struct tm date that corresponds to the start of the epoch (Jan 1, 1970 00:00:00). This will verify what your local time setting on your computer is. On two computers next to each other in the workplace, one might be set to GMT (aka zulu) time, and the other might be set to local time. Then if you run the same code on both systems, you will get different results, since the struct tm values are defined as the local time.
0
 
Infinity08Commented:
>> I think it is important to know what epoch time you get when you plug in a struct tm date that corresponds to the start of the epoch (Jan 1, 1970 00:00:00). This will verify what your local time setting on your computer is. On two computers next to each other in the workplace, one might be set to GMT (aka zulu) time, and the other might be set to local time. Then if you run the same code on both systems, you will get different results, since the struct tm values are defined as the local time.

I've already deduced his local timezone in my previous post ;)
0
 
phoffricCommented:
Let's see what happens if you alter your code as follows:
   memset( &tm, 0, sizeof(tm) );
   tm.tm_mday = 1;  // set to Jan
   tm.tm_year = 1970 - 1900; // set to first year of epoch
   epoch = mktime( &tm);
   printf(" Epoch 0 = %d\n", epoch);
0
 
phoffricCommented:
oh, race conditions... :)
0
 
VlearnsAuthor Commented:
thanks for both the responses ,this clarifies my understanding

if i do not want to assume the time zone of my machine what should i do?

1) first adjust 1041370596 by adding 3600 (1 hour) to get it from the local timezone to the GMT timezone :

        1041370596 + 3600 = 1041374196

how do i adjust to gmtime programatically?
0
 
phoffricCommented:
The code below shows the epoch time when my local time is Jan 1, 1970 00:00:00.

Here is my output:
 Epoch 0 = 18000

Notice that 18000/3600 = 5 (hours) which means that at 0000 hours here, it is 0500 GMT. This means that my local time is -0500 from GMT.

   struct tm tm;

   memset( &tm, 0, sizeof(tm) );
   tm.tm_mday = 1;  // set to Jan
   tm.tm_year = 1970 - 1900; // set to first year of epoch
   epoch = mktime( &tm);
   printf(" Epoch 0 = %d\n", epoch);

Open in new window

0
 
Infinity08Commented:
>> if i do not want to assume the time zone of my machine what should i do?

What I told you in http:#26115164 ;)

>> how do i adjust to gmtime programatically?

By adjusting for the local timezone. That's all you can do, because mktime works based on the local timezone. The alternative is not to use mktime, but then you have to implement the whole time calculation yourself.
0
 
Infinity08Commented:
Or maybe you meant : "How do I retrieve the local timezone ?" In that case, phoffric's previous post should help ;)
0
 
VlearnsAuthor Commented:

i have a formatted input  date  as

"31-Dec-2002 22:36:36 -0800 so like

"date"<space>"zone

where zone is defined as



zone            = ("+" / "-") 4DIGIT
                    ; Signed four-digit value of hhmm representing
                    ; hours and minutes east of Greenwich (that is,
                    ; the amount that the given time differs from
                    ; Universal Time).  Subtracting the timezone
                    ; from the given time will give the UT form.
                    ; The Universal Time zone is "+0000".

is there a easy way for me to convert the zone to 0000

31-Dec-2002 22:36:36  +0000

so that this date is universal time zone

now i can safely use strptime and mktime to get the epoch time ?
0
 
phoffricCommented:
I'm a little confused about what you want; maybe a little tired, so please bear with me (I'm EST).

To recap, from http:#26114838 and http:#26115164, it appears that your platform's timezone is set to GMT time. I think -0800 is Pacific Standard Time. If that is where you are, then your computer clock gives a time that is 8 hours ahead of your local time (i.e., the time on your wrist watch). If this is incorrect info, let me know.

I also thought from the discussion that you were not going to use the %Z option, but rather adjust the GMT time after you used mktime.

Could you define a function signature with all the inputs necessary to fully characterize the problem you wish to solve; and all the outputs; and any assumptions about the platform's local time zone setting.

I assume that you have no problem parsing out the "-0800" from the input string,
    "31-Dec-2002 22:36:36 -0800".
And that you have no problem then computing the integer -8 (hours) from this substring. Is this correct?

I see that http:#26115164 provides a 2-step method to compute the epoch time, which you should verify to see if that meets your needs. But it appears that this approach does not use the %Z conversion that you would like to use. But if that approach does work for you, then is it necessary to use %Z?
0
 
Infinity08Commented:
>> is there a easy way for me to convert the zone to 0000

It's a lot more complicated to modify the string than to modify the seconds count. So, no ... the easiest way to do this would require you to use the same procedure discussed earlier (using mktime with timezone and DST adjustments) to get a time in GMT, then convert it back to a string, and then use strptime to get the time out of that string again (which you already had).

This, as you can see, is not easier than the procedure we've already explained to you. There's a reason we chose to explain that procedure - and that's because it's probably the best approach for you. Where is it that you have a problem with it ?
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 9
  • 7
  • 7
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now