1

I am looking for the UTC (from RFC3339 format) to IST conversion in C program. But I could not find any generic way to convert the time.

Here, I found the shell script to convert the UTC time (in RFC3339 format) to IST and I am trying to implement in C code.

From the script, I can't find the equivalent way for the statement newdate=$(TZ=IST date -d "$formatT UTC-5:30") in C code.

So, I did time diff of -5:30 with the GMT time as shown in below snippet. But, it is not working as expected.

int main(int argc, char *argv[])
{  
    const char *utctime = "2019-07-24T11:47:33";
    struct tm tm = {0};
    char s[128] = {0};

    if (NULL == (strptime(utctime, "%Y-%m-%dT%H:%M:%S", &tm))) {
        printf("strptime failed\n");
    }

    printf("IST Time : %2d:%02d\n", ((tm.tm_hour-5)%24), tm.tm_min-30);

}

Kindly, guide me to do the task in C code that the script does.

Kirubakaran
  • 378
  • 4
  • 20
  • Doing time/date arithmetic on `struct tm` is hairy. Are you really going to handle all the boundaries where hours, minutes, seconds, day, month and year changes, including leap years and leap seconds? No, you're not! Convert the value to a `time_t` with `mktime` and do the arithmetic there. Note that this is still tricky because you need to figure out whether DST is in effect in the target timezone. It still gets a bit hairy, but I recall figuring out a neat hack years ago. Can't quite remember what I did in the end. – paddy Jul 25 '19 at 06:24
  • If IST is your local time, you just can convert to time_t first (as in @paddy's comment), then directly convert back using [`localtime` function](https://linux.die.net/man/3/gmtime). If it is not, you might adjust timezone first with [`tzset` function](https://linux.die.net/man/3/tzset). – Aconcagua Jul 25 '19 at 08:12
  • Just wait a second, `mktime` assumes [local time](https://stackoverflow.com/questions/530519/stdmktime-and-timezone-info)! So you'd need to set UTC as local time first! As on linux, better: [timegm](https://linux.die.net/man/3/timegm). – Aconcagua Jul 25 '19 at 08:15

1 Answers1

2

Non-portable, linux:

struct tm time;
// fill appropriately

time_t utc = timegm(&time)

localtime_r(&utc, &time);

If your local time zone isn't IST, you need to change to before calling local time:

setenv("TZ", "IST-05:30:00", 1);
//             ^ not entirely sure if this is correct, please verify yourself (*)

tzset();

Edit (following the comments): (*) Especially if daylight saving time (DST) has to be applied, the time zone string looks different; you find information about at tzset documentation. Possibly the server provides time zone information in a local file, then you might try :Asia/Kolkata as well.

You might retrieve current timezone with getenv first if you intend to restore it afterwards, complete example is shown at timegm documentation.

The portable way would now be to first set timezone to UTC, call mktime instead of timegm, then set timezone to IST and call localtime just as in non-portable version and finally restore local timezone (if intended/needed and you haven't already done so by setting it to IST).

Aconcagua
  • 24,880
  • 4
  • 34
  • 59
  • Hi, thanks for your answer. I tried both the portable and non-portable methods to convert the UTC time to IST. In local machine (IST) both are works fine. But, If I the code in the machine with local time as UTC, it does not return the valid IST time. Instead, it returns the same UTC time even I changed the time-zone as IST. In the shared link, I have added the code snippet of both versions and pasted the output aswell. Please correct me if I missed anything. [1] https://drive.google.com/open?id=1BIwXQP3ZfklhlnZYLjCYsyzNCkdQVaSm – Kirubakaran Jul 25 '19 at 20:32
  • At first, be aware that you are not returning a value at all in one of the functions and that `int` is not suitable to hold values of type `time_t`, the latter usually being larger in size than the former. Apart from, as it seems to work on one system, I'd check time zone settings of the other one. Maybe it is not configured as UTC, but still IST, and was set back by 5.5 hours manually instead? – Aconcagua Jul 26 '19 at 09:16
  • Hi Aconcagua, Its a typo of returning ```time_t``` data as ```int```. And I was printing the time within the function thru ```puts(s)```, so no need to consider the return value. Also, I was using a different machine (local & UTC) and not adjusted the time value. Please find the test-case in the bottom of the shared code in the commented section. I have corrected the ```return``` value :) – Kirubakaran Jul 26 '19 at 10:38
  • Timezone string apparently is not correct; [tzset](https://linux.die.net/man/3/tzset) provides appropriate information for, should be: `IST-05:30:00` (I mentioned that you'd need to verify...), if there's daylight saving time in IST (I don't know if so or not), it must be specified explicitly (sample from link above for New Zealand time: `TZ="NZST-12:00:00NZDT-13:00:00,M10.1.0,M3.3.0"`). Explanations see the link. – Aconcagua Jul 26 '19 at 11:04
  • You might ask Google support if there are appropriate timezone files, or maybe just try [`:Asia/Kolkata`](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). – Aconcagua Jul 26 '19 at 11:07