Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to programatically convert a time from one timezone to another in C?

The info pages for the GNU date command contains this example:

For example, with the GNU date command you can answer the question "What time is it in New York when a Paris clock shows 6:30am on October 31, 2004?" by using a date beginning with `TZ="Europe/Paris"' as shown in the following shell transcript:

 $ export TZ="America/New_York"
 $ date --date='TZ="Europe/Paris" 2004-10-31 06:30'
 Sun Oct 31 01:30:00 EDT 2004

In this example, the '--date' operand begins with its own 'TZ' setting, so the rest of that operand is processed according to 'Europe/Paris' rules, treating the string 2004-10-31 06:30 as if it were in Paris. However, since the output of the date command is processed according to the overall time zone rules, it uses New York time. (Paris was normally six hours ahead of New York in 2004, but this example refers to a brief Halloween period when the gap was five hours.)

I am trying to accomplish essentially the same thing programatically in C without calling the date program millions of times. Basically I am looking for a way to take an arbitrary date and time in one timezone and convert it to the equivalent date and time in another timezone either directly or via conversion to and from UTC. I don't care about the formats of the input and output time as long as I can manipulate them using standard functions (strftime/strptime/mktime/etc).

The date program appears to accomplish this using complex routines internal to the coreutils package, I am looking for a way to do this in C using either standard POSIX/Linux routines or an external library. I looked at zoneinfo quite a bit which seemed promising but I cannot find any libraries to do anything useful with it.

like image 373
Robert Gamble Avatar asked Mar 09 '10 23:03

Robert Gamble


People also ask

How do I convert datetime to another time zone?

To convert Time to another TimeZone we can use the ConvertTimeZoneService class method by passing the DateTime value to that method which we want to convert.

How do I convert one time zone to another in C #?

TimeZoneInfo timeZone = TimeZoneInfo. FindSystemTimeZoneById("Eastern Standard Time"); var time = timeZoneInfo. ConvertTime(gmTime, timeZone);

How do I convert DateTimeOffset to local time?

In performing the conversion to local time, the method first converts the current DateTimeOffset object's date and time to Coordinated Universal Time (UTC) by subtracting the offset from the time. It then converts the UTC date and time to local time by adding the local time zone offset.

How do I convert a date from one time zone to another in SQL Server?

One way is to get the UTC time directly and store it in a date-time datatype column. Next way is to convert the given local time to UTC time and then store it in a date time column. Another way is to use the datetimeoffset to add the offset to UTC and store it in a datetimeoffset column.


1 Answers

I came up with a solution that seems to work on Linux with glibc, I don't know how portable this behavior is, any comments about portability or a better way to go about this would be welcome.

convert_time.c (No error checking for clarity):

#define _XOPEN_SOURCE
#include <time.h>
#include <stdio.h>
#include <stdlib.h>

int main (int argc, char *argv[])
{
  struct tm mytm = {0};
  time_t mytime;
  char buf[100];

  mytm.tm_isdst = -1;
  putenv(argv[1]);
  tzset();
  strptime(argv[2], "%Y-%m-%d %H:%M", &mytm);
  mytime = mktime(&mytm);

  putenv(argv[3]);
  tzset();
  localtime_r(&mytime, &mytm);
  strftime(buf, 100, "%a, %d %b %Y %H:%M:%S %z(%Z)", &mytm);
  puts(buf);

  return 0;
}

The first argument is the source timezone (actually "TZ=Timezone" to pass to putenv), the second argument is the time in the specified format, the last argument is the destination timezone. I am using zoneinfo timezone names which glibc supports using the zoneinfo database.

The results of several DST test corner cases correspond to the results from the equivalent date command as well as this site which uses the zoneinfo database:

$ ./convert_time "TZ=America/New_York" "2005-05-31 06:30" "TZ=America/Indiana/Indianapolis"
Tue, 31 May 2005 05:30:00 -0500(EST)

$ ./convert_time "TZ=America/New_York" "2006-05-31 06:30" "TZ=America/Indiana/Indianapolis"
Wed, 31 May 2006 06:30:00 -0400(EDT)

$ ./convert_time "TZ=Europe/Paris" "2004-10-30 06:30" "TZ=America/New_York"
Sat, 30 Oct 2004 00:30:00 -0400(EDT)

$ ./convert_time "TZ=Europe/Paris" "2004-10-31 06:30" "TZ=America/New_York"
Sun, 31 Oct 2004 01:30:00 -0400(EDT)

$ ./convert_time "TZ=Europe/Paris" "2004-11-01 06:30" "TZ=America/New_York"
Mon, 01 Nov 2004 00:30:00 -0500(EST)
like image 109
Robert Gamble Avatar answered Sep 30 '22 15:09

Robert Gamble