5#include "qplatformdefs.h"
7#include "private/qcalendarmath_p.h"
8#if QT_CONFIG(datetimeparser)
9#include "private/qdatetimeparser_p.h"
11#include "private/qgregoriancalendar_p.h"
12#include "private/qnumeric_p.h"
13#include "private/qtenvironmentvariables_p.h"
14#if QT_CONFIG(timezone)
15#include "private/qtimezoneprivate_p.h"
33constexpr int tmYearFromQYear(
int year) {
return year - (year < 0 ? 1899 : 1900); }
34constexpr int qYearFromTmYear(
int year) {
return year + (year < -1899 ? 1899 : 1900); }
36constexpr inline qint64 tmSecsWithinDay(
const struct tm &when)
59inline bool meansEnd1969(tm *local)
65 if (local->tm_sec < 59 || local->tm_year < 69 || local->tm_year > 70
66 || local->tm_min % 5 != 4
67 || (local->tm_year == 69
68 ? local->tm_mon < 11 || local->tm_mday < 31
69 : local->tm_mon > 0 || local->tm_mday > 1)) {
116inline bool callMkTime(tm *local, time_t *secs)
118 constexpr time_t maybeError = -1;
119 const tm
copy = *local;
121 bool good = *secs != maybeError || meansEnd1969(local);
122 if (
copy.tm_isdst >= 0 && (!good || local->tm_isdst !=
copy.tm_isdst)) {
125 local->tm_isdst = -1;
127 good = *secs != maybeError || meansEnd1969(local);
133 if (local->tm_isdst == 0 && local->tm_hour !=
copy.tm_hour) {
135 if (local->tm_hour > 23) {
136 local->tm_hour -= 24;
138 local->tm_mon + 1, qYearFromTmYear(local->tm_year))) {
140 if (++local->tm_mon > 11) {
155 Q_ASSERT(0 <= secs && secs < 3600 * 24);
157 struct tm local = {};
158 local.tm_year = tmYearFromQYear(ymd.year);
159 local.tm_mon = ymd.month - 1;
160 local.tm_mday = ymd.day;
161 local.tm_hour = secs / 3600;
162 local.tm_min = (secs % 3600) / 60;
163 local.tm_sec = (secs % 60);
164 local.tm_isdst = int(
dst);
168inline std::optional<qint64> tmToJd(
const struct tm &
date)
174#define IC(N) std::integral_constant<qint64, N>()
177inline bool daysAndSecondsOverflow(
qint64 julianDay,
qint64 daySeconds,
qint64 *epochSeconds)
180 ||
qAddOverflow(*epochSeconds, daySeconds, epochSeconds);
184inline bool secondsAndMillisOverflow(
qint64 epochSeconds,
qint64 millis,
qint64 *epochMillis)
196#ifndef QT_BOOTSTRAPPED
202 TIME_ZONE_INFORMATION tzInfo;
203 if (GetTimeZoneInformation(&tzInfo) != TIME_ZONE_ID_INVALID) {
204 int bias = tzInfo.Bias;
206 if (tzInfo.StandardDate.wMonth)
207 bias += tzInfo.StandardBias;
213 const time_t curr =
time(
nullptr);
227# if defined(_POSIX_THREAD_SAFE_FUNCTIONS)
229 if (gmtime_r(&curr, &
t)) {
231 int offset = int(curr - mkt);
236 if (
struct tm *tp = gmtime(&curr)) {
239 int offset = int(curr - mkt);
246 qDebug(
"Unable to determine current standard time offset from UTC");
263 const auto epoch = QRoundingDown::qDivMod<MSECS_PER_SEC>(utcMillis);
264 const time_t epochSeconds = epoch.quotient;
265 const int msec = epoch.remainder;
274 auto jd = tmToJd(local);
278 const qint64 daySeconds = tmSecsWithinDay(local);
280 qint64 localSeconds, localMillis;
281 if (
Q_UNLIKELY(daysAndSecondsOverflow(*jd, daySeconds, &localSeconds)
282 || secondsAndMillisOverflow(localSeconds,
qint64(msec), &localMillis))) {
287 return { localMillis, int(localSeconds - epochSeconds),
dst };
292 const auto localDayMilli = QRoundingDown::qDivMod<MSECS_PER_DAY>(local);
293 qint64 millis = localDayMilli.remainder;
295 struct tm tmLocal = timeToTm(localDayMilli.quotient,
int(millis /
MSECS_PER_SEC),
dst);
297 if (!callMkTime(&tmLocal, &utcSecs))
299 return qTzName(tmLocal.tm_isdst > 0 ? 1 : 0);
306 const auto localDaySec = QRoundingDown::qDivMod<SECS_PER_DAY>(localSecs);
307 qint64 daySecs = localDaySec.remainder;
310 struct tm tmLocal = timeToTm(localDaySec.quotient, daySecs,
dst);
312 if (!callMkTime(&tmLocal, &utcSecs))
318 int offset = localSecs - utcSecs;
320 auto jd = tmToJd(tmLocal);
324 daySecs = tmSecsWithinDay(tmLocal);
330 if (
Q_UNLIKELY(daysAndSecondsOverflow(*jd, daySecs, &localSecs)))
333 offset = localSecs - utcSecs;
340 const bool overflow = secondsAndMillisOverflow(localSecs, millis, &revised);
341 return {overflow ? local : revised,
offset,
dst, !overflow};
377 constexpr qint64 TIME_T_MAX = std::numeric_limits<time_t>::max();
378 using Bounds = std::numeric_limits<qint64>;
379 constexpr bool isNarrow = Bounds::max() /
MSECS_PER_SEC > TIME_T_MAX;
380 if constexpr (isNarrow) {
382 const qint64 msecsMin = -1 - msecsMax;
384 struct tm local = {};
385 local.tm_year = tmYearFromQYear(1901);
389 return {
qMkTime(&local) == -1 ? 0 : msecsMin, msecsMax,
false,
false};
391 const struct {
int year;
qint64 millis; } starts[] = {
412 for (
const auto c : ends) {
413 struct tm local = {};
414 local.tm_year = tmYearFromQYear(
c.year);
418 local.tm_min = local.tm_sec = 59;
426 bool startMin =
true;
427 for (
const auto c : starts) {
429 local.tm_year = tmYearFromQYear(
c.year);
434 return {
c.millis, stop, startMin, stopMax};
437 return {0, stop,
false, stopMax};
static ZoneState expressUtcAsLocal(qint64 utcMSecs)
static std::optional< qint64 > julianFromParts(int year, int month, int day)
static int monthLength(int month, int year)
static QCalendar::YearMonthDay partsFromJulian(qint64 jd)
\macro QT_RESTRICTED_CAST_FROM_ASCII
QString localTimeAbbbreviationAt(qint64 local, QDateTimePrivate::DaylightStatus dst)
SystemMillisRange computeSystemMillisRange()
QDateTimePrivate::ZoneState utcToLocal(qint64 utcMillis)
int getCurrentStandardUtcOffset()
QDateTimePrivate::ZoneState mapLocalTime(qint64 local, QDateTimePrivate::DaylightStatus dst)
int getUtcOffset(qint64 atMSecsSinceEpoch)
Combined button and popup list for selecting options.
constexpr qint64 SECS_PER_MIN
constexpr qint64 SECS_PER_DAY
constexpr qint64 MSECS_PER_DAY
constexpr qint64 JULIAN_DAY_FOR_EPOCH
constexpr qint64 MINS_PER_HOUR
constexpr qint64 MSECS_PER_SEC
static jboolean copy(JNIEnv *, jobject)
std::enable_if_t< std::is_unsigned_v< T >, bool > qAddOverflow(T v1, T v2, T *r)
std::enable_if_t< std::is_unsigned_v< T >||std::is_signed_v< T >, bool > qMulOverflow(T v1, T v2, T *r)
GLenum GLuint GLintptr offset
bool qLocalTime(time_t utc, struct tm *local)
time_t qMkTime(struct tm *when)
QString qTzName(int dstIndex)
unsigned long long quint64