私は次の整数を持っています:
int y, mon, d, h, min, s;
それらの値は、2012
それぞれ、、、、、、です。アプリケーションの別の場所で「UTC」を選択した場合は「2012/06/2712:47:53 UTC」の日時を表し、「2012/06/2712:47:53AEST」を選択した場合は「アプリケーションのどこかで「AEST」を選択しました。06
27
12
47
53
これをに変換したいのですが、これtime_t
を行うために現在使用しているコードは次のとおりです。
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(&timeinfo);
#else
return mktime(&timeinfo); //FIXME Still incorrect
#endif
だから私はとを使用してtm struct
いmktime
ますが、これは常に私のローカルタイムゾーンを想定しているため、うまく機能していません。
これを行う正しい方法は何ですか?
以下は私がこれまでに思いついた解決策です。基本的に、次の3つのいずれかを実行します。
- UNIXの場合は、単に使用します
timegm
- UNIXでない場合
- どちらか、UTCエポックとローカルエポックの違いをオフセットとして使用して計算を行います
- 予約:数学が正しくない可能性があります
- または、「TZ」環境変数を一時的にUTCに設定します
- 予約:このコードをマルチスレッド化する必要がある場合は、トリップします
- どちらか、UTCエポックとローカルエポックの違いをオフセットとして使用して計算を行います
namespace tmUtil
{
int const tm_yearCorrection = -1900;
int const tm_monthCorrection = -1;
int const tm_isdst_dontKnow = -1;
#if !defined(DEBUG_DATETIME_TIMEGM_ENVVARTZ) && !(defined(UNIX) && !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) && !defined(DEBUG_DATETIME_TIMEGM) //TODO remove && 00
time_t result;
result = timegm(&time);
return result;
#else
#if !defined(DEBUG_DATETIME_TIMEGM_ENVVARTZ)
//TODO check that math is correct
time_t fromEpochUtc = mktime(&time);
struct tm localData;
struct tm utcData;
struct tm* loc = localtime_r (&fromEpochUtc, &localData);
struct tm* utc = gmtime_r (&fromEpochUtc, &utcData);
int utcYear = utc->tm_year - tmUtil::tm_yearCorrection;
int gmtOff =
(loc-> tm_sec - utc-> tm_sec)
+ (loc-> tm_min - utc-> tm_min) * 60
+ (loc->tm_hour - utc->tm_hour) * 60 * 60
+ (loc->tm_yday - utc->tm_yday) * 60 * 60 * 24
+ (loc->tm_year - utc->tm_year) * 60 * 60 * 24 * tmUtil::daysIn(utcYear);
#ifdef UNIX
if (loc->tm_gmtoff != gmtOff)
{
StringBuilder err("loc->tm_gmtoff=", StringBuilder((int)(loc->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(&time);
if (tz)
setenv("TZ", tz, 1);
else
unsetenv("TZ");
tzset();
return result;
#endif
#endif
}
NBStringBuilder
は内部クラスであり、この質問の目的には関係ありません。
より詳しい情報:
これは、ブーストなどを使用して簡単に実行できることを私は知っています。しかし、これはオプションではありません。数学的に、またはacまたはc ++標準関数、あるいはそれらの組み合わせを使用して実行する必要があります。
timegm
この問題は解決しているように見えますが、C/POSIX標準の一部ではないようです。#ifdef $PLATFORM
このコードは現在、複数のプラットフォーム(Linux、OSX、Windows、iOS、Android(NDK))でコンパイルされているため、ソリューションにタイプのものが含まれている場合でも、これらすべてのプラットフォームで機能させる方法を見つける必要があります。