Konvertiert Datum und Zeit, zahlen zu time_t UND geben Sie die Zeitzone

Habe ich die folgenden ganzen zahlen:

int y, mon, d, h, min, s;

Ihre Werte sind: 2012, 06, 27, 12, 47, 53 bzw. Ich möchte zum darstellen des Datum-Zeit "2012/06/27 12:47:53 UTC -" wenn ich gewählt haben, 'UTC' irgendwo anders in meiner Anwendung, oder "2012/06/27 12:47:53 AEST" wenn ich gewählt haben, 'US /Eastern' irgendwo anders in meiner Anwendung.

Will ich wandeln diese in eine time_t, und hier ist der code, ich bin aktuell mit zu tun:

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

So, ich bin mit einem tm struct und mktime werden, das ist aber nicht gut, denn es wird immer vorausgesetzt, meine lokale Zeitzone.

Was ist der richtige Weg, dies zu tun?

Also unten ist die Lösung, die ich kommen mit so weit.
Es im Grunde genommen drei Dinge:

  1. Wenn UNIX, verwenden Sie einfach timegm
  2. Wenn nicht UNIX
    1. Entweder, rechnen die Differenz zwischen UTC-Zeit und lokaler Zeit als ein offset
      • Reservierung: Mathe kann falsch sein,
    2. Oder die "TZ" - Umgebungsvariable auf UTC zeitweise
      • Reservierung: wird die Reise, wenn/wenn dieser code muss Multithread
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
}

N. B. StringBuilder ist eine interne Klasse, es spielt keine Rolle, für die Zwecke dieser Frage.

Mehr info:

Ich weiß, dass dies kann leicht getan werden mit boost, et al. Aber das ist KEINE option. Ich muss es getan werden rechnerisch oder mit Hilfe eines c-oder c++ - standard-Funktion, oder Kombinationen davon.

timegm angezeigt wird, um dieses problem zu lösen, aber es scheint nicht Teil der C /POSIX-standard. Dieser code ist derzeit zusammengestellt, die auf mehreren Plattformen (Linux, OSX, WIndows, iOS, Android (NDK)), so muss ich einen Weg finden, damit es funktioniert auf allen diesen Plattformen, auch wenn die Lösung umfasst #ifdef $PLATFORM Art Dinge.

  • Haben Sie andere Bibliotheken? Sie haben eine Liste von Zeitzonen & Ihre offsets?
  • Nein, ich will nicht zu verwenden Bibliotheken, wie Sie entstehen viel Entwicklungsaufwand bei der cross-Compilierung. Auch, Nein, ich habe nicht eine Liste von Zeitzonen und deren offsets. Werfen Sie einen Blick auf mein update oben, ich habe es in einer Weise zu berechnen, Zeitzone offsets - sieht es richtige für Sie?
  • <HÄSSLICHER HACK> könnte Man es in einen string konvertieren mit strftime() ersetzen Sie die Zeitzone in den string und konvertieren Sie es dann zurück mit mktime(strptime()) </HÄSSLICHER HACK>, aber ich würde einfach davon überzeugen, die Kräfte, die sein, dass der boost ist in der Tat eine option.
  • Könntest du posten, dass da eine Antwort?
  • Sicher, aber ich bin tatsächlich ein bisschen beschämt, dass ich sogar gepostet als Kommentar 🙂
  • auch wenn, wie Sie sagen, es ist hässlich (nicht zu erwähnen, nicht sehr effizient), es bedeutet, dass ich [1] nicht zu tun, keine Mathematik (und haben zu sorgen über deren Richtigkeit), oder [2] Bearbeiten alle Umgebungsvariablen (und sorgen multi-threading-Probleme), also die Vermeidung der Fallstricke der beiden Methoden, die ich kommen mit so weit. So können Sie beantworten würde intakt!

InformationsquelleAutor bguiz | 2012-06-27
Schreibe einen Kommentar