time_t timegm(struct tm * const t) { // time_t is signed on Android. static const time_t kTimeMax = ~(1 << (sizeof (time_t) * CHAR_BIT - 1)); static const time_t kTimeMin = (1 << (sizeof (time_t) * CHAR_BIT - 1)); time64_t result = timegm64(t); if (result < kTimeMin || result > kTimeMax) return -1; return result; }
static long long millis_from_datetime(PyObject* datetime) { struct TM timeinfo; long long millis; timeinfo.tm_year = PyDateTime_GET_YEAR(datetime) - 1900; timeinfo.tm_mon = PyDateTime_GET_MONTH(datetime) - 1; timeinfo.tm_mday = PyDateTime_GET_DAY(datetime); timeinfo.tm_hour = PyDateTime_DATE_GET_HOUR(datetime); timeinfo.tm_min = PyDateTime_DATE_GET_MINUTE(datetime); timeinfo.tm_sec = PyDateTime_DATE_GET_SECOND(datetime); millis = timegm64(&timeinfo) * 1000; millis += PyDateTime_DATE_GET_MICROSECOND(datetime) / 1000; return millis; }
BOOL SystemTimeToFileTime(const SYSTEMTIME* lpSystemTime, LPFILETIME lpFileTime) { static const int dayoffset[12] = {0, 31, 59, 90, 120, 151, 182, 212, 243, 273, 304, 334}; #if defined(TARGET_DARWIN) static long timegm_lock = 0; #endif struct tm sysTime = {}; sysTime.tm_year = lpSystemTime->wYear - 1900; sysTime.tm_mon = lpSystemTime->wMonth - 1; sysTime.tm_wday = lpSystemTime->wDayOfWeek; sysTime.tm_mday = lpSystemTime->wDay; sysTime.tm_hour = lpSystemTime->wHour; sysTime.tm_min = lpSystemTime->wMinute; sysTime.tm_sec = lpSystemTime->wSecond; sysTime.tm_yday = dayoffset[sysTime.tm_mon] + (sysTime.tm_mday - 1); sysTime.tm_isdst = g_timezone.m_IsDST; // If this is a leap year, and we're past the 28th of Feb, increment tm_yday. if (IsLeapYear(lpSystemTime->wYear) && (sysTime.tm_yday > 58)) sysTime.tm_yday++; #if defined(TARGET_DARWIN) CAtomicSpinLock lock(timegm_lock); #endif #if defined(TARGET_ANDROID) time64_t t = timegm64(&sysTime); #else time_t t = timegm(&sysTime); #endif LARGE_INTEGER result; result.QuadPart = (long long) t * 10000000 + (long long) lpSystemTime->wMilliseconds * 10000; result.QuadPart += WIN32_TIME_OFFSET; lpFileTime->dwLowDateTime = result.u.LowPart; lpFileTime->dwHighDateTime = result.u.HighPart; return 1; }
struct tm64* localtime64_r(const time64_t* time64, struct tm64* tm64) { if(*time64 >= LONG_MIN && *time64 <= LONG_MAX) { struct tm tm; memset(&tm, 0, sizeof(tm)); time_t time = (time_t) *time64; if(localtime_r(&time, &tm)) { tm_to_tm64(&tm, tm64); #ifndef HAVE_TM_ZONE #if HAVE_TZNAME && HAVE_DAYLIGHT tm64->tm_zone = tzname[daylight && tm64->tm_isdst]; #else tm64->tm_zone = NULL; #endif #endif return tm64; } } /* * First determine the (approximate) year that this timestamp * is in using the gmtime64_r function. We then use this so * we are able to map this to a year that should be compatible * with the system localtime_r */ struct tm64 gm; gmtime64_r(time64, &gm); int64_t gm_year = gm.tm_year; if(gm_year < 1902) { /* For years below the 32 bit size time_t value we need to use * the lower comparable years */ int day = day_of_week(gm_year, gm.tm_mon + 1, gm.tm_mday); if(gm.tm_mon == 2 && leap_year(gm_year)) { gm.tm_year = lower_leap_month_table[day]; } else { gm.tm_year = lower_common_month_table[gm.tm_mon][day]; } } else if(gm_year > 2037) { /* For years above the 32 bit size time_t value we need to use * the lower comparable years */ int day = day_of_week(gm_year, gm.tm_mon + 1, gm.tm_mday); if(gm.tm_mon == 2 && leap_year(gm_year)) { gm.tm_year = higher_leap_month_table[day]; } else { gm.tm_year = higher_common_month_table[gm.tm_mon][day]; } } /* * Get the timestamp for the safe date that we mapped the * large date to. */ time_t time = (time_t)timegm64(&gm); struct tm tm; memset(&tm, 0, sizeof(tm)); localtime_r(&time, &tm); tm_to_tm64(&tm, tm64); tm64->tm_year = gm_year; /* * We need to correct here for the case where the timezone difference * results in the dates occuring in two different years. */ int month_diff = tm64->tm_mon - gm.tm_mon; if(month_diff == 11) { tm64->tm_year--; } else if(month_diff == -11) { tm64->tm_year++; } /* If the gm year is a leap year, but the local isn't and we're on * December 31st in the local year, this is marked as day 365 because * the gm year is a leap year. Therefore we need to substract 1. */ if(!leap_year(tm64->tm_year) && tm64->tm_yday == 365 ) { tm64->tm_yday--; } #ifndef HAVE_TM_ZONE #if HAVE_TZNAME && HAVE_DAYLIGHT tm64->tm_zone = tzname[daylight && tm64->tm_isdst]; #else tm64->tm_zone = NULL; #endif #endif return tm64; }
struct TM *localtime64_r (const Time64_T *time, struct TM *local_tm) { time_t safe_time; struct tm safe_date; struct TM gm_tm; Year orig_year; int month_diff; assert(local_tm != NULL); /* Use the system localtime() if time_t is small enough */ if( SHOULD_USE_SYSTEM_LOCALTIME(*time) ) { safe_time = *time; TRACE1("Using system localtime for %lld\n", *time); LOCALTIME_R(&safe_time, &safe_date); copy_tm_to_TM(&safe_date, local_tm); assert(check_tm(local_tm)); return local_tm; } if( gmtime64_r(time, &gm_tm) == NULL ) { TRACE1("gmtime64_r returned null for %lld\n", *time); return NULL; } orig_year = gm_tm.tm_year; if (gm_tm.tm_year > (2037 - 1900) || gm_tm.tm_year < (1970 - 1900) ) { TRACE1("Mapping tm_year %lld to safe_year\n", (Year)gm_tm.tm_year); gm_tm.tm_year = safe_year((Year)(gm_tm.tm_year + 1900)) - 1900; } safe_time = timegm64(&gm_tm); if( LOCALTIME_R(&safe_time, &safe_date) == NULL ) { TRACE1("localtime_r(%d) returned NULL\n", (int)safe_time); return NULL; } copy_tm_to_TM(&safe_date, local_tm); local_tm->tm_year = orig_year; if( local_tm->tm_year != orig_year ) { TRACE2("tm_year overflow: tm_year %lld, orig_year %lld\n", (Year)local_tm->tm_year, (Year)orig_year); #ifdef EOVERFLOW errno = EOVERFLOW; #endif return NULL; } month_diff = local_tm->tm_mon - gm_tm.tm_mon; /* When localtime is Dec 31st previous year and gmtime is Jan 1st next year. */ if( month_diff == 11 ) { local_tm->tm_year--; } /* When localtime is Jan 1st, next year and gmtime is Dec 31st, previous year. */ if( month_diff == -11 ) { local_tm->tm_year++; } /* GMT is Jan 1st, xx01 year, but localtime is still Dec 31st in a non-leap xx00. There is one point in the cycle we can't account for which the safe xx00 year is a leap year. So we need to correct for Dec 31st comming out as the 366th day of the year. */ if( !IS_LEAP(local_tm->tm_year) && local_tm->tm_yday == 365 ) local_tm->tm_yday--; assert(check_tm(local_tm)); return local_tm; }
time_t timegm(struct tm* t) { return (time_t) timegm64(t); }
static bool compose_location(const struct nmea_parser_t *ctx, struct location_t *dst) { const struct nmea_fix_t *fix; bool min_gga, min_rmc, min_gll; bool is_valid; struct tm time_full; fix = &ctx->fix; min_gga = fix->gpgga_active && fix->gpgga.has_latitude && fix->gpgga.has_longitude; min_rmc = fix->gprmc_active && fix->gprmc.has_latitude && fix->gprmc.has_longitude; min_gll = fix->gpgll_active && fix->gpgll.has_latitude && fix->gpgll.has_longitude; is_valid = min_gga || min_rmc || min_gll; if (fix->gpgga_active) is_valid &= fix->gpgga.fix_quality != 0; if (fix->gprmc_active) is_valid &= fix->gprmc.status_active; if (!is_valid) { dst->is_valid = false; return dst->is_valid; } dst->is_valid = true; time_full = ctx->time_full; dst->time = 1000ll * (long long)timegm64(&time_full) + ctx->fix.fix_time.mss; // Latitude, longitude if (min_gga) { dst->latitude = fix->gpgga.latitude; dst->longitude = fix->gpgga.longitude; }else if(min_rmc) { dst->latitude = fix->gprmc.latitude; dst->longitude = fix->gprmc.longitude; }else { assert(min_gll); dst->latitude = fix->gpgll.latitude; dst->longitude = fix->gpgll.longitude; } // Altitude if (min_gga && fix->gpgga.has_altitude) { dst->has_altitude = true; dst->altitude = fix->gpgga.altitude; }else { dst->has_altitude = false; dst->altitude = 0; } // Satellites if (min_gga && fix->gpgga.has_sattelites_nb) { dst->satellites = fix->gpgga.sattelites_nb; }else if (ctx->gpgsa.is_valid) { unsigned i; dst->satellites = 0; for (i=0; i<sizeof(ctx->gpgsa.prn)/sizeof(ctx->gpgsa.prn[0]); ++i) { if (ctx->gpgsa.prn[i] > 0) dst->satellites += 1; } }else { dst->satellites = -1; } // Bearing if (fix->gprmc_active && fix->gprmc.has_course) { dst->has_bearing = true; dst->bearing = fix->gprmc.course; }else if (ctx->gpvtg.is_valid && (ctx->gpvtg.fix_mode != 'N') && ctx->gpvtg.has_course_true) { dst->has_bearing = true; dst->bearing = ctx->gpvtg.course_true; }else { dst->has_bearing = false; dst->bearing = 0; } // Speed if (fix->gprmc_active && fix->gprmc.has_speed) { dst->has_speed = true; dst->speed = fix->gprmc.speed; }else if (ctx->gpvtg.is_valid && (ctx->gpvtg.fix_mode != 'N') && ctx->gpvtg.has_speed_kmph) { dst->has_speed = true; dst->speed = ctx->gpvtg.speed_kmph * KMPH_TO_MPS; }else { dst->has_speed = false; dst->speed = 0; } // Accuracy dst->has_accuracy = false; dst->accuracy = 0; if (fix->gpgst_active) { if (fix->gpgst.has_std_lat && fix->gpgst.has_std_lon) { dst->has_accuracy = true; dst->accuracy = hypotf(fix->gpgst.std_lat, fix->gpgst.std_lon); }else if (fix->gpgst.has_range_rms) { dst->has_accuracy = true; dst->accuracy = fix->gpgst.range_rms; }else { assert(!dst->has_accuracy); } } return dst->is_valid; }