jmasterx
jmasterx

Reputation: 54113

Get a time_t from universal time string?

If I have this string:

2011-10-08T07:07:09Z

is it possible to get a time_t from it? If so, how can this be done?

Upvotes: 0

Views: 873

Answers (3)

chux
chux

Reputation: 153358

Another approach works should code know that time_t is the number of seconds since Jan 1, 1970 0:00:00. Uses sscanf() to parse the string, calculate the number of days, and then return the number of seconds.

#include <time.h>
#include <stdio.h>

#define MARCH 3
#define DaysPer400Years   (400*365LL + 97)
#define DaysPer100Years   (100*365LL + 24)
#define DaysPer4Years     (4*365LL + 1)
#define DaysPer1Year      365LL
#define DayNumber1970Jan1 719469LL

long long DayNumber(int year, int Month, int Day, long epoch) {
  long long dn = Day;
  long long y = year;
  y += Month / 12;
  Month %= 12;
  while (Month < MARCH) {
    Month += 12;
    y--;
  }
  // And then a miracle occurs.
  dn += ((Month - MARCH) * (7832 / 4) + (140 / 4)) >> (8 - 2);
  dn += (y / 400) * DaysPer400Years;
  y %= 400;
  dn += (y / 100) * DaysPer100Years;
  y %= 100;
  dn += (y / 4) * DaysPer4Years;
  y %= 4;
  dn += y * DaysPer1Year;
  return dn - epoch;
}

time_t UniversalTimeStamp_to_time_t(const char *ts) {
  int y,m,d,H,M,S;

  // Use a sentinel to catch extra garbage
  char sentinel;
  if (sscanf(ts, "%d-%2d-%2dT%2d:%2d:%2dZ%c", &y, &m,
      &d, &H, &M, &S, &sentinel) != 6) {
    return -1;
  }

  long long t = DayNumber(y, m, d, DayNumber1970Jan1);
  t = t*24L*60*60 + 3600L*H + 60*M + S;

  // test code
  {
  printf("UTC  `%s`\n", ts);
  time_t tt = t;
  struct tm tm = *gmtime(&tt);
  char buf[100];
  strftime(buf, sizeof buf, "%Y-%m-%dT%H:%M:%S %Z", &tm);
  printf("Local %s\n", buf);
  printf("Unix  %lld\n\n", t);
  }

  return t;
}

int main(void) {
  UniversalTimeStamp_to_time_t("2015-06-18T22:07:52Z");
  UniversalTimeStamp_to_time_t("2011-10-08T07:07:09Z");
  UniversalTimeStamp_to_time_t("1970-01-01T00:00:00Z");
  return 0;
}

Output

UTC  `2015-06-18T22:07:52Z`
Local 2015-06-18T22:07:52    
Unix  1434665272

UTC  `2011-10-08T07:07:09Z`
Local 2011-10-08T07:07:09    
Unix  1318057629

UTC  `1970-01-01T00:00:00Z`
Local 1970-01-01T00:00:00    
Unix  0

Upvotes: 1

chux
chux

Reputation: 153358

Use sscanf() to tear apart the time. The trick is somehow determine the difference between local and universal time so code may call mktime() - which uses assumes struct tm is local time..

#include <time.h>
#include <stdio.h>

int Get_TZ_delta(const struct tm *tmptr) {
  // Make local copy
  struct tm tm = *tmptr;
  time_t t = mktime(&tm);
  struct tm utc_tm = *gmtime(&t);
  time_t t2 = mktime(&utc_tm);
  return (int) difftime(t, t2);
}

time_t UniversalTimeStamp_to_time_t(const char *ts) {
  struct tm tm = { 0 };
  // Use a sentinel to catch extra garbage
  char sentinel;
  if (sscanf(ts, "%d-%2d-%2dT%2d:%2d:%2dZ%c", &tm.tm_year, &tm.tm_mon,
      &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &sentinel) != 6) {
    return -1;
  }
  // struct tm uses offset from 1900 and January is month 0
  tm.tm_year -= 1900;
  tm.tm_mon--;
  // Convert tm from UCT to local standard time
  tm.tm_isdst = 0;
  tm.tm_sec += Get_TZ_delta(&tm);

  time_t t = mktime(&tm); // mktime() assumes tm is local

  // test code
  {
  printf("UTC  `%s`\n", ts);
  char buf[100];
  strftime(buf, sizeof buf, "%Y-%m-%dT%H:%M:%S %Z", &tm);
  printf("Local %s\n", buf);
  printf("Unix  %lld\n\n", (long long) mktime(&tm));
  }

  return t;
}

int main(void) {
  UniversalTimeStamp_to_time_t("2015-06-18T22:07:52Z");
  UniversalTimeStamp_to_time_t("2011-10-08T07:07:09Z");
  UniversalTimeStamp_to_time_t("1970-01-01T00:00:00Z");
  return 0;
}

Output

UTC  `2015-06-18T22:07:52Z`
Local 2015-06-18T17:07:52 CDT
Unix  1434665272

UTC  `2011-10-08T07:07:09Z`
Local 2011-10-08T02:07:09 CDT
Unix  1318057629

UTC  `1970-01-01T00:00:00Z`
Local 1969-12-31T18:00:00 CST
Unix  0

Upvotes: 1

Filipe Gon&#231;alves
Filipe Gon&#231;alves

Reputation: 21213

Yes, it is. First, convert it to a broken down time with strptime(3). This gives you a struct tm, which is the structure type for a broken down time.

From there, you can convert to a time_t with mktime(3).

Here's an example:

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

int main(void) {
        const char *date_example = "2011-10-08T07:07:09Z";
    struct tm broken_down;

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

    strptime(date_example, "%Y-%m-%dT%H:%M:%SZ", &broken_down);
    broken_down.tm_isdst = 0; // Indicates that DST is not in effect
    time_t epoch_time = mktime(&broken_down);

    // Note: this is platform dependent
    printf("Epoch time: %lld\n", (long long) epoch_time);

    return 0;
}

Upvotes: 3

Related Questions