20 Stimmen

Timegm plattformübergreifend

Ich verwende den Visual Studio c++ Compiler (2010), aber die Bibliothek hat eine unterschiedliche Implementierung von ANSI C- und POSIX-Bibliotheksfunktionen.

Was ist der Unterschied zwischen ANSI C-Funktion und der Windows CRT-Implementierung? Zum Beispiel, was ist der Unterschied zwischen tzset() und _tzset() oder setenv() und _setenv()? Es scheint, dass sie das gleiche in der gleichen Weise tun...

Ich verwende MSVC (2010), sollte ich die Windows CRT-Implementierung bevorzugen?

EDIT 1

Ich möchte eine Struktur tm, die in UTC ausgedrückt ist, auf tragbare Weise in ein time_t konvertieren, aber es gibt keine tragbare Möglichkeit, dies zu tun. Ich muss die Funktion für verschiedene Plattformen schreiben (Android, Linux, Windows, Windows CE).

Ich habe diesen Stackoverflow-Beitrag gesehen, der setenv, getenv und tzset() verwendet.

Edit2

Leider habe ich nach einigen Tests festgestellt, dass getenv("TZ") auf Windows einen Nullzeiger zurückgibt. Aber warum ist es so schwierig, eine UTC-Zeitstruktur in ein time_t zu transformieren?

Edit 3

Durch Boost habe ich dieses Codefragment in boost/chrono/io/time_point_io.hpp entdeckt. Hoffentlich hilft es mir.

inline int32_t is_leap(int32_t year)
{
  if(year % 400 == 0)
  return 1;
  if(year % 100 == 0)
  return 0;
  if(year % 4 == 0)
  return 1;
  return 0;
}
inline int32_t days_from_0(int32_t year)
{
  year--;
  return 365 * year + (year / 400) - (year/100) + (year / 4);
}
inline int32_t days_from_1970(int32_t year)
{
  static const int days_from_0_to_1970 = days_from_0(1970);
  return days_from_0(year) - days_from_0_to_1970;
}
inline int32_t days_from_1jan(int32_t year,int32_t month,int32_t day)
{
  static const int32_t days[2][12] =
  {
    { 0,31,59,90,120,151,181,212,243,273,304,334},
    { 0,31,60,91,121,152,182,213,244,274,305,335}
  };
  return days[is_leap(year)][month-1] + day - 1;
}

inline time_t internal_timegm(std::tm const *t)
{
  int year = t->tm_year + 1900;
  int month = t->tm_mon;
  if(month > 11)
  {
    year += month/12;
    month %= 12;
  }
  else if(month < 0)
  {
    int years_diff = (-month + 11)/12;
    year -= years_diff;
    month+=12 * years_diff;
  }
  month++;
  int day = t->tm_mday;
  int day_of_year = days_from_1jan(year,month,day);
  int days_since_epoch = days_from_1970(year) + day_of_year;

  time_t seconds_in_day = 3600 * 24;
  time_t result = seconds_in_day * days_since_epoch + 3600 * t->tm_hour + 60 * t->tm_min + t->tm_sec;

  return result;
}

32voto

Naszta Punkte 7252

Ich verwende das folgende Makro unter Windows:

#define timegm _mkgmtime

da _mkgmtime dasselbe macht.

9voto

Hans Passant Punkte 894572

Als David Cutlers Team 1989 mit der Gestaltung von Windows NT begann, wussten sie noch nicht, welches API dominant sein würde. Also haben sie drei davon erstellt. Win32 war eine Anpassung der 16-Bit-Version des Windows-APIs. OS/2 wurde unterstützt, das Betriebssystem, das DOS ersetzen sollte, es aber nicht tat. Und Posix war das Dritte, das hinzugefügt wurde, weil die US-Regierung damals festlegte, dass sie nur Betriebssysteme in Betracht ziehen würden, die dem aufkommenden Posix-Standard folgten.

Die von Ihnen erwähnte Funktion tzset() ist ein Überbleibsel aus dem Posix-API. Sie haben wahrscheinlich putenv() falsch geschrieben, dieselbe Geschichte. Das Subsystem schnitt nicht gut ab, Win32 gewann den API-Kampf auf beeindruckende Weise und die Posix-Unterstützung wurde 2001 aus Windows entfernt. Microsoft behielt die Unterstützung für die Posix-Funktionen bei, benannte sie jedoch mit einem Unterstrich um, da sie nicht Teil der Standard-C-Bibliothek sind. Sie sollten Deprecation-Warnungen erhalten, wenn Sie die nicht vorangestellte Version der Funktionen verwenden. Es scheint, als hätten Sie _CRT_NONSTDC_NO_DEPRECATE definiert, um sie zu unterdrücken. Es ist am besten, das nicht zu tun. Bevorzugen Sie die Standard-C-Bibliotheksfunktionen.

8voto

Sergey D Punkte 605
// Algorithm: http://howardhinnant.github.io/date_algorithms.html
int days_from_epoch(int y, int m, int d)
{
    y -= m <= 2;
    int era = y / 400;
    int yoe = y - era * 400;                                   // [0, 399]
    int doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1;  // [0, 365]
    int doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;           // [0, 146096]
    return era * 146097 + doe - 719468;
}

// It  does not modify broken-down time
time_t timegm(struct tm const* t)     
{
    int year = t->tm_year + 1900;
    int month = t->tm_mon;          // 0-11
    if (month > 11)
    {
        year += month / 12;
        month %= 12;
    }
    else if (month < 0)
    {
        int years_diff = (11 - month) / 12;
        year -= years_diff;
        month += 12 * years_diff;
    }
    int days_since_epoch = days_from_epoch(year, month + 1, t->tm_mday);

    return 60 * (60 * (24L * days_since_epoch + t->tm_hour) + t->tm_min) + t->tm_sec;
}

Dies ist eine tragbare Möglichkeit, tm in UTC in time_t umzuwandeln.

Beachten Sie, dass es die tm-Struktur nicht ändert/normalisiert und keine tz-Einstellungen ändert.

3voto

rodrigo Punkte 87935

Für die meisten Funktionen, die ich kenne, gibt es keinen Unterschied.

Der Unterstrich in den Namen soll betonen, dass dies keine Standard-C-Funktionen sind: Meines Wissens gibt es in ANSI C keine tzset bzw. setenv Funktionen. Es handelt sich größtenteils um POSIX-Funktionen, die vom MS CRT als Hilfestellung zur Portabilität von anderen Betriebssystemen implementiert werden.

Aber sie beanspruchen keine POSIX-Kompatibilität, daher der Unterstrich. Und daher sollten Sie vorsichtig sein und die MS-Dokumentation zu diesen Funktionen lesen ... da lauern Dämonen!

1voto

Siewca Punkte 27

Meine Implementierung von timegm funktioniert auf Windows.

time_t timegm(struct tm * a_tm)
{
    time_t ltime = mktime(a_tm);
    struct tm tm_val;
    gmtime_s(&tm_val, <ime);
    int offset = (tm_val.tm_hour - a_tm->tm_hour);
    if (offset > 12)
    {
        offset = 24 - offset;
    }
    time_t utc = mktime(a_tm) - offset * 3600;
    return utc;
}

Sollte funktionieren.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X