title: Convert date and time numbers to time_t AND specify the timezone
body: <p>I have the following integers:</p>
  
  <pre><code>int y, mon, d, h, min, s;
  </code></pre>
  
  <p>Their values are: <code>2012</code>, <code>06</code>, <code>27</code>, <code>12</code>, <code>47</code>, <code>53</code> respectively. I want to represent the date time of "2012/06/27 12:47:53 UTC" if I have selected 'UTC' somewhere else in my application, or "2012/06/27 12:47:53 AEST" if I have selected 'AEST' somewhere else in my application.</p>
  
  <p>I want to convert this into a <code>time_t</code>, and here's the code that I am current using to do so:</p>
  
  <pre><code>struct tm timeinfo;
  timeinfo.tm_year = year - 1900;
  timeinfo.tm_mon = mon - 1;
  timeinfo.tm_mday = day;
  timeinfo.tm_hour = hour;
  timeinfo.tm_min = min;
  timeinfo.tm_sec = sec;
  //timeinfo.tm_isdst = 0; //TODO should this be set?
  
  //TODO find POSIX or C standard way to do covert tm to time_t without in UTC instead of local time
  #ifdef UNIX
  return timegm(&amp;timeinfo);
  #else
  return mktime(&amp;timeinfo); //FIXME Still incorrect
  #endif
  </code></pre>
  
  <p>So I am using a <code>tm struct</code> and <code>mktime</code>, however this is not working well, because it is always assuming my local time-zone.</p>
  
  <p>What is the correct way of doing this?</p>
  
  <p>So below is the solution that I have come up with so far.
  It basically does one of three things:</p>
  
  <ol>
  <li>If UNIX, simply use <code>timegm</code></li>
  <li>If not UNIX
  <ol>
  <li>Either, do math using the difference between UTC epoch and local epoch as an offset
  <ul>
  <li>Reservation: Math may be incorrect</li>
  </ul></li>
  <li>Or, set the "TZ" environment variable to UTC temporarily
  <ul>
  <li>Reservation: will trip up if/ when this code needs to be multithreaded</li>
  </ul></li>
  </ol></li>
  </ol>
  
  <pre class="lang-cpp prettyprint-override"><code>namespace tmUtil
  {
      int const tm_yearCorrection = -1900;
      int const tm_monthCorrection = -1;
      int const tm_isdst_dontKnow = -1;
  
  #if !defined(DEBUG_DATETIME_TIMEGM_ENVVARTZ) &amp;&amp; !(defined(UNIX) &amp;&amp; !defined(DEBUG_DATETIME_TIMEGM))
      static bool isLeap(int year)
      {
          return
              (year % 4) ? false
              : (year % 100) ? true
              : (year % 400) ? false
              : true;
      }
  
      static int daysIn(int year)
      {
          return isLeap(year) ? 366 : 365;
      }
  #endif
  }
  
  time_t utc(int year, int mon, int day, int hour, int min, int sec)
  {
      struct tm time = {0};
      time.tm_year = year + tmUtil::tm_yearCorrection;
      time.tm_mon = mon + tmUtil::tm_monthCorrection;
      time.tm_mday = day;
      time.tm_hour = hour;
      time.tm_min = min;
      time.tm_sec = sec;
      time.tm_isdst = tmUtil::tm_isdst_dontKnow;
  
      #if defined(UNIX) &amp;&amp; !defined(DEBUG_DATETIME_TIMEGM) //TODO remove &amp;&amp; 00
          time_t result;
          result = timegm(&amp;time);
          return result;
      #else
          #if !defined(DEBUG_DATETIME_TIMEGM_ENVVARTZ)
              //TODO check that math is correct
              time_t fromEpochUtc = mktime(&amp;time);
  
              struct tm localData;
              struct tm utcData;
              struct tm* loc = localtime_r (&amp;fromEpochUtc, &amp;localData);
              struct tm* utc = gmtime_r (&amp;fromEpochUtc, &amp;utcData);
              int utcYear = utc-&gt;tm_year - tmUtil::tm_yearCorrection;
              int gmtOff =
                  (loc-&gt; tm_sec - utc-&gt; tm_sec)
                  + (loc-&gt; tm_min - utc-&gt; tm_min) * 60
                  + (loc-&gt;tm_hour - utc-&gt;tm_hour) * 60 * 60
                  + (loc-&gt;tm_yday - utc-&gt;tm_yday) * 60 * 60 * 24
                  + (loc-&gt;tm_year - utc-&gt;tm_year) * 60 * 60 * 24 * tmUtil::daysIn(utcYear);
  
              #ifdef UNIX
                  if (loc-&gt;tm_gmtoff != gmtOff)
                  {
                      StringBuilder err("loc-&gt;tm_gmtoff=", StringBuilder((int)(loc-&gt;tm_gmtoff)), " but gmtOff=", StringBuilder(gmtOff));
                      THROWEXCEPTION(err);
                  }
              #endif
  
              int resultInt = fromEpochUtc + gmtOff;
              time_t result;
              result = (time_t)resultInt;
              return result;
          #else
              //TODO Find a way to do this without manipulating environment variables
              time_t result;
              char *tz;
              tz = getenv("TZ");
              setenv("TZ", "", 1);
              tzset();
              result = mktime(&amp;time);
              if (tz)
                  setenv("TZ", tz, 1);
              else
                  unsetenv("TZ");
              tzset();
              return result;
          #endif
      #endif
  }
  </code></pre>
  
  <p>N.B. <code>StringBuilder</code> is an internal class, it doesn't matter for the purposes of this question.</p>
  
  <p>More info:</p>
  
  <p>I know that this can be done easily using boost, et al. But this is NOT and option. I need it to be done mathematically, or using a c or c++ standard function, or combinations thereof.</p>
  
  <p><code>timegm</code> appears to solve this problem, however, it doesn't appear to part of the C / POSIX standard. This code currently is compiled on multiple platforms (Linux, OSX, WIndows, iOS, Android (NDK)), so I need to find a way to make it work across all of these platforms, even if the solution involves <code>#ifdef $PLATFORM</code> type things.</p>