Hier ist ein einfaches, getestetes, hoffentlich tragbares Stück Code, das von struct tm
in Sekunden seit Beginn eines einstellbaren UTC Jahres konvertiert, ohne temporäre Änderung der Zeitzone.
// Conversion from UTC date to second, signed 64-bit adjustable epoch version.
// Written by François Grieu, 2015-07-21; public domain.
#include <time.h> // needed for struct tm
#include <stdint.h> // needed for int_least64_t
#define MY_EPOCH 1970 // epoch year, changeable
typedef int_least64_t my_time_t; // type for seconds since MY_EPOCH
// my_mktime converts from struct tm UTC to non-leap seconds since
// 00:00:00 on the first UTC day of year MY_EPOCH (adjustable).
// It works since 1582 (start of Gregorian calendar), assuming an
// apocryphal extension of Coordinated Universal Time, until some
// event (like celestial impact) deeply messes with Earth.
// It strive to be strictly C99-conformant.
//
// input: Pointer to a struct tm with field tm_year, tm_mon, tm_mday,
// tm_hour, tm_min, tm_sec set per mktime convention; thus
// - tm_year is year minus 1900;
// - tm_mon is [0..11] for January to December, but [-2..14]
// works for November of previous year to February of next year;
// - tm_mday, tm_hour, tm_min, tm_sec similarly can be offset to
// the full range [-32767 to 32767].
// output: Number of non-leap seconds since beginning of the first UTC
// day of year MY_EPOCH, as a signed at-least-64-bit integer.
// The input is not changed (in particular, fields tm_wday,
// tm_yday, and tm_isdst are unchanged and ignored).
my_time_t my_mktime(const struct tm * ptm) {
int m, y = ptm->tm_year+2000;
if ((m = ptm->tm_mon)<2) { m += 12; --y; }
// compute number of days within constant, assuming appropriate origin
#define MY_MKTIME(Y,M,D) ((my_time_t)Y*365+Y/4-Y/100*3/4+(M+2)*153/5+D)
return (((MY_MKTIME(y , m, ptm->tm_mday)
-MY_MKTIME((MY_EPOCH+99), 12, 1 )
)*24+ptm->tm_hour)*60+ptm->tm_min)*60+ptm->tm_sec;
#undef MY_MKTIME // this macro is private
}
Key Beobachtungen große Vereinfachung, um den Code in this und that Antworten im Vergleich erlaubt:
- Nummerierungs Monate ab März alle Monate mit Ausnahme der vor diesem Ursprung Wiederholung mit einem Zyklus von 5 Monaten 153 in Höhe von insgesamt Tage abwechselnd 31 und 30 Tage, so dass für beliebige Monat, und ohne Berücksichtigung von Schaltjahren, die Anzahl der Tage seit dem letzten Februar (innerhalb einer Konstante) unter Verwendung einer entsprechenden Konstante, Multiplikation mit 153 und berechnet werden kann ganzzahlige Division durch 5;
- Die Korrektur in Tagen, die die Regel für das Schaltjahr auf Jahre multiple-of-100 berücksichtigt (die von Ausnahme zu multiple-of-4-Regeln nicht springt, außer wenn multiple von 400) kann berechnet werden (innerhalb einer Konstante) durch Addition einer entsprechenden Konstanten, ganzzahlige Division durch 100, Multiplikation mit 3 und ganzzahlige Division durch 4;
- können wir die Korrektur für jede Epoche mit der gleichen Formel berechnen, die wir in der Hauptberechnung verwenden, und können dies mit einem Makro tun, so dass diese Korrektur zur Kompilierungszeit berechnet wird.
ist hier eine andere Version nicht 64-Bit-Unterstützung erforderlich ist, bis 1970 Herkunft gesperrt.
// Conversion from UTC date to second, unsigned 32-bit Unix epoch version.
// Written by François Grieu, 2015-07-21; public domain.
#include <time.h> // needed for struct tm
#include <limits.h> // needed for UINT_MAX
#if UINT_MAX>=0xFFFFFFFF // unsigned is at least 32-bit
typedef unsigned my_time_t; // type for seconds since 1970
#else
typedef unsigned long my_time_t; // type for seconds since 1970
#endif
// my_mktime converts from struct tm UTC to non-leap seconds since
// 00:00:00 on the first UTC day of year 1970 (fixed).
// It works from 1970 to 2105 inclusive. It strives to be compatible
// with C compilers supporting // comments and claiming C89 conformance.
//
// input: Pointer to a struct tm with field tm_year, tm_mon, tm_mday,
// tm_hour, tm_min, tm_sec set per mktime convention; thus
// - tm_year is year minus 1900
// - tm_mon is [0..11] for January to December, but [-2..14]
// works for November of previous year to February of next year
// - tm_mday, tm_hour, tm_min, tm_sec similarly can be offset to
// the full range [-32767 to 32768], as long as the combination
// with tm_year gives a result within years [1970..2105], and
// tm_year>0.
// output: Number of non-leap seconds since beginning of the first UTC
// day of year 1970, as an unsigned at-least-32-bit integer.
// The input is not changed (in particular, fields tm_wday,
// tm_yday, and tm_isdst are unchanged and ignored).
my_time_t my_mktime(const struct tm * ptm) {
int m, y = ptm->tm_year;
if ((m = ptm->tm_mon)<2) { m += 12; --y; }
return ((((my_time_t)(y-69)*365u+y/4-y/100*3/4+(m+2)*153/5-446+
ptm->tm_mday)*24u+ptm->tm_hour)*60u+ptm->tm_min)*60u+ptm->tm_sec;
}
„Mktime nur den Zeitstempel als Ortszeit zurück“ - klar zu sein, ist der Zeitstempel ein UNIX-Zeitstempel (für wen Zeitzonen sind völlig irrelevant). Was passiert, ist, dass 'mktime' seinen _input_ als lokale Zeit interpretiert. –