11#include <private/qnumeric_p.h>
12#include <private/wcharhelpers_win_p.h>
17#include <private/qwinregistry_p.h>
23using namespace Qt::StringLiterals;
26
27
28
29
31#define MAX_KEY_LENGTH 255
41static const wchar_t tzRegPath[] = LR"(SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones)";
42static const wchar_t currTzRegPath[] = LR"(SYSTEM\CurrentControlSet\Control\TimeZoneInformation)";
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
88QDate msecsToDate(qint64 msecs)
90 qint64 jd = JULIAN_DAY_FOR_EPOCH;
92 if (msecs >= MSECS_PER_DAY || msecs <= -MSECS_PER_DAY) {
93 jd += msecs / MSECS_PER_DAY;
94 msecs %= MSECS_PER_DAY;
98 Q_ASSERT(msecs > -MSECS_PER_DAY);
102 return QDate::fromJulianDay(jd);
105bool equalSystemtime(
const SYSTEMTIME &t1,
const SYSTEMTIME &t2)
107 return (t1.wYear == t2.wYear
108 && t1.wMonth == t2.wMonth
109 && t1.wDay == t2.wDay
110 && t1.wDayOfWeek == t2.wDayOfWeek
111 && t1.wHour == t2.wHour
112 && t1.wMinute == t2.wMinute
113 && t1.wSecond == t2.wSecond
114 && t1.wMilliseconds == t2.wMilliseconds);
117bool equalTzi(
const TIME_ZONE_INFORMATION &tzi1,
const TIME_ZONE_INFORMATION &tzi2)
119 return(tzi1.Bias == tzi2.Bias
120 && tzi1.StandardBias == tzi2.StandardBias
121 && equalSystemtime(tzi1.StandardDate, tzi2.StandardDate)
122 && wcscmp(tzi1.StandardName, tzi2.StandardName) == 0
123 && tzi1.DaylightBias == tzi2.DaylightBias
124 && equalSystemtime(tzi1.DaylightDate, tzi2.DaylightDate)
125 && wcscmp(tzi1.DaylightName, tzi2.DaylightName) == 0);
128QWinTimeZonePrivate::QWinTransitionRule readRegistryRule(
const HKEY &key,
129 const wchar_t *value,
bool *ok)
132 QWinTimeZonePrivate::QWinTransitionRule rule;
134 DWORD tziSize =
sizeof(tzi);
135 if (RegQueryValueEx(key, value,
nullptr,
nullptr,
reinterpret_cast<BYTE *>(&tzi), &tziSize)
137 Q_ASSERT(tziSize ==
sizeof(tzi));
139 rule.standardTimeBias = tzi.Bias + tzi.StandardBias;
140 rule.daylightTimeBias = tzi.Bias + tzi.DaylightBias - rule.standardTimeBias;
141 rule.standardTimeRule = tzi.StandardDate;
142 rule.daylightTimeRule = tzi.DaylightDate;
148TIME_ZONE_INFORMATION getRegistryTzi(
const QByteArray &windowsId,
bool *ok)
151 TIME_ZONE_INFORMATION tzi;
152 REG_TZI_FORMAT regTzi;
153 const QString tziKeyPath = QString::fromWCharArray(tzRegPath) + u'\\'
154 + QString::fromUtf8(windowsId);
156 QWinRegistryKey key(HKEY_LOCAL_MACHINE, tziKeyPath);
158 auto regQuery = [&key](
const wchar_t *entry,
auto buffer, size_t space) {
159 std::optional<size_t> res;
160 DWORD size = DWORD(space);
161 if (RegQueryValueEx(key, entry,
nullptr,
nullptr,
162 reinterpret_cast<LPBYTE>(buffer), &size) == ERROR_SUCCESS) {
167 auto regStrQuery = [®Query](
const wchar_t *entry,
auto buffer, size_t space) {
169 if (
auto res = regQuery(entry, buffer, space); !res)
171 else if (*res >= space)
172 buffer[space /
sizeof(buffer[0]) - 1] = L'\0';
174 regStrQuery(L"Dlt", tzi.DaylightName,
sizeof(tzi.DaylightName));
175 regStrQuery(L"Std", tzi.StandardName,
sizeof(tzi.StandardName));
176 if (
auto res = regQuery(L"TZI", ®Tzi,
sizeof(regTzi))) {
177 Q_ASSERT(*res ==
sizeof(regTzi));
178 tzi.Bias = regTzi.Bias;
179 tzi.StandardBias = regTzi.StandardBias;
180 tzi.DaylightBias = regTzi.DaylightBias;
181 tzi.StandardDate = regTzi.StandardDate;
182 tzi.DaylightDate = regTzi.DaylightDate;
190bool isSameRule(
const QWinTimeZonePrivate::QWinTransitionRule &last,
191 const QWinTimeZonePrivate::QWinTransitionRule &rule)
198 return equalSystemtime(last.standardTimeRule, rule.standardTimeRule)
199 && equalSystemtime(last.daylightTimeRule, rule.daylightTimeRule)
200 && last.standardTimeBias == rule.standardTimeBias
201 && last.daylightTimeBias == rule.daylightTimeBias;
204QList<QByteArray> availableWindowsIds()
206 static const QList<QByteArray> cache = [] {
207 QList<QByteArray> list;
208 QWinRegistryKey key(HKEY_LOCAL_MACHINE, tzRegPath);
211 if (RegQueryInfoKey(key, 0, 0, 0, &idCount, 0, 0, 0, 0, 0, 0, 0) == ERROR_SUCCESS
213 for (DWORD i = 0; i < idCount; ++i) {
216 if (RegEnumKeyEx(key, i, buffer, &maxLen, 0, 0, 0, 0) == ERROR_SUCCESS)
217 list.append(QString::fromWCharArray(buffer).toUtf8());
226QByteArray windowsSystemZoneId()
229 const QString id = QWinRegistryKey(HKEY_LOCAL_MACHINE,
currTzRegPath)
230 .stringValue(L"TimeZoneKeyName");
236 TIME_ZONE_INFORMATION sysTzi;
237 if (GetTimeZoneInformation(&sysTzi) != TIME_ZONE_ID_INVALID) {
239 const auto winIds = availableWindowsIds();
240 for (
const QByteArray &winId : winIds) {
241 if (equalTzi(getRegistryTzi(winId, &ok), sysTzi) && ok)
247 return QTimeZonePrivate::utcQByteArray();
250QDate calculateTransitionLocalDate(
const SYSTEMTIME &rule,
int year)
253 if (rule.wMonth == 0)
258 Q_ASSERT(rule.wMonth > 0 && rule.wMonth <= 12);
262 return QDate(rule.wYear, rule.wMonth, rule.wDay);
265 Q_ASSERT(rule.wDayOfWeek >= 0 && rule.wDayOfWeek < 7);
266 const int dayOfWeek = rule.wDayOfWeek == 0 ? 7 : rule.wDayOfWeek;
267 QDate date(year, rule.wMonth, 1);
268 Q_ASSERT(date.isValid());
270 int adjust = dayOfWeek - date.dayOfWeek();
275 adjust += (rule.wDay < 1 ? 1 : rule.wDay > 4 ? 5 : rule.wDay) * 7;
276 date = date.addDays(adjust);
278 if (date.month() != rule.wMonth) {
279 Q_ASSERT(rule.wDay > 4);
282 date = date.addDays(-7);
283 Q_ASSERT(date.month() == rule.wMonth);
289inline bool timeToMSecs(QDate date, QTime time, qint64 *msecs)
292 qint64 daySinceEpoch = date.toJulianDay() - JULIAN_DAY_FOR_EPOCH;
293 qint64 msInDay = time.msecsSinceStartOfDay();
294 if (daySinceEpoch < 0 && msInDay > 0) {
298 msInDay -= MSECS_PER_DAY;
300 return qMulOverflow(daySinceEpoch, std::integral_constant<qint64, MSECS_PER_DAY>(), &dayms)
301 || qAddOverflow(dayms, msInDay, msecs);
304qint64 calculateTransitionForYear(
const SYSTEMTIME &rule,
int year,
int bias)
309 const QDate date = calculateTransitionLocalDate(rule, year);
310 const QTime time = QTime(rule.wHour, rule.wMinute, rule.wSecond);
312 if (date.isValid() && time.isValid() && !timeToMSecs(date, time, &msecs)) {
316 return bias && qAddOverflow(msecs, qint64(bias) * 60000, &msecs)
317 ? (bias < 0 ? QTimeZonePrivate::minMSecs() : QTimeZonePrivate::maxMSecs())
318 : qMax(QTimeZonePrivate::minMSecs(), msecs);
320 return QTimeZonePrivate::invalidMSecs();
324bool isAtStartOfYear(
const SYSTEMTIME &transition,
int year)
327
328
329
330
331
332
333
334
335 return transition.wMonth == 1 && transition.wDay == 1
336 && (
QDate(year, 1, 1).dayOfWeek() - transition.wDayOfWeek) % 7 == 0
337 && transition.wHour == 0 && transition.wMinute == 0 && transition.wSecond == 0;
340struct TransitionTimePair
346 bool fakesDst =
false;
348 TransitionTimePair(
const QWinTimeZonePrivate::QWinTransitionRule &rule,
349 int year,
int oldYearOffset)
351 : std(calculateTransitionForYear(rule.standardTimeRule, year,
352 rule.standardTimeBias + rule.daylightTimeBias)),
354 dst(calculateTransitionForYear(rule.daylightTimeRule, year, rule.standardTimeBias))
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401 if (rule.standardTimeBias + rule.daylightTimeBias == oldYearOffset
402 && isAtStartOfYear(rule.daylightTimeRule, year)) {
403 dst = QTimeZonePrivate::invalidMSecs();
406 if (rule.standardTimeBias == oldYearOffset
407 && isAtStartOfYear(rule.standardTimeRule, year)) {
408 Q_ASSERT_X(!fakesDst,
"TransitionTimePair",
409 "Year with (DST bias zero and) both transitions fake !");
410 std = QTimeZonePrivate::invalidMSecs();
415 bool startsInDst()
const
419 return std != QTimeZonePrivate::invalidMSecs()
420 && (std < dst || dst == QTimeZonePrivate::invalidMSecs());
427 bool beforeInitialDst(
int year, qint64 millis)
const
429 return !fakesDst && (year == FIRST_DST_YEAR ? millis < dst : year < FIRST_DST_YEAR);
432 QTimeZonePrivate::Data ruleToData(
const QWinTimeZonePrivate::QWinTransitionRule &rule,
433 const QWinTimeZonePrivate *tzp,
bool isDst)
const
435 const auto type = isDst ? QTimeZone::DaylightTime : QTimeZone::StandardTime;
436 auto time = isDst ? dst : std;
439 if (fakesDst && time == QTimeZonePrivate::invalidMSecs())
440 time = isDst ? std : dst;
441 return tzp->ruleToData(rule, time, type, fakesDst);
445int yearEndOffset(
const QWinTimeZonePrivate::QWinTransitionRule &rule,
int year)
448 int offset = rule.standardTimeBias;
452 TransitionTimePair pair(rule, year, offset);
453 if (pair.dst > pair.std)
454 offset += rule.daylightTimeBias;
458QLocale::Territory userTerritory()
460 const GEOID id = GetUserGeoID(GEOCLASS_NATION);
462 const int size = GetGeoInfo(id, GEO_ISO2, code, 3, 0);
463 return (size == 3) ? QLocalePrivate::codeToTerritory(QStringView(code, size))
464 : QLocale::AnyTerritory;
468int ruleIndexForYear(
const QList<QWinTimeZonePrivate::QWinTransitionRule> &rules,
int year)
470 Q_ASSERT(!rules.isEmpty());
471 if (rules.last().startYear <= year)
472 return rules.count() - 1;
474 if (rules.first().startYear > year)
478 int lo = 0, hi = rules.count();
481 while (lo + 1 < hi) {
482 const int mid = (lo + hi) / 2;
485 const int midYear = rules.at(mid).startYear;
488 else if (midYear < year)
499QWinTimeZonePrivate::QWinTimeZonePrivate()
506QWinTimeZonePrivate::QWinTimeZonePrivate(
const QByteArray &ianaId)
512QWinTimeZonePrivate::~QWinTimeZonePrivate()
516QWinTimeZonePrivate *QWinTimeZonePrivate::clone()
const
518 return new QWinTimeZonePrivate(*
this);
521void QWinTimeZonePrivate::init(
const QByteArray &ianaId)
523 if (ianaId.isEmpty()) {
524 m_windowsId = windowsSystemZoneId();
525 m_id = systemTimeZoneId();
527 m_windowsId = ianaIdToWindowsId(ianaId).toByteArray();
530 const auto initialYear = [](
const QWinTransitionRule &rule) {
535 return (rule.standardTimeRule.wMonth > 0 || rule.daylightTimeRule.wMonth > 0
536 ? FIRST_DST_YEAR :
int(QDateTime::YearRange::First));
539 bool badMonth =
false;
540 if (!m_windowsId.isEmpty()) {
542 const QString baseKeyPath = QString::fromWCharArray(tzRegPath) + u'\\'
543 + QString::fromUtf8(m_windowsId);
544 QWinRegistryKey baseKey(HKEY_LOCAL_MACHINE, baseKeyPath);
545 if (baseKey.isValid()) {
547 m_displayName = baseKey.stringValue(L"Display");
548 m_standardName = baseKey.stringValue(L"Std");
549 m_daylightName = baseKey.stringValue(L"Dlt");
551 const QString dynamicKeyPath = baseKeyPath +
"\\Dynamic DST"_L1;
552 QWinRegistryKey dynamicKey(HKEY_LOCAL_MACHINE, dynamicKeyPath);
553 if (dynamicKey.isValid()) {
555 constexpr int YearBoundMin = 1970, YearBoundMax = 3000;
557 const int startYear = dynamicKey.value<
int>(L"FirstEntry").value_or(YearBoundMin);
558 Q_ASSERT(startYear >= YearBoundMin);
559 const int endYear = dynamicKey.value<
int>(L"LastEntry").value_or(YearBoundMax);
560 Q_ASSERT(endYear <= YearBoundMax);
561 for (
int year = startYear; year <= endYear; ++year) {
563 QWinTransitionRule rule = readRegistryRule(dynamicKey,
564 qt_castToWchar(QString::number(year)),
568 && (m_tranRules.isEmpty()
569 || !isSameRule(m_tranRules.last(), rule))) {
571 && (rule.standardTimeRule.wMonth == 0)
572 != (rule.daylightTimeRule.wMonth == 0)) {
574 qWarning(
"MS registry TZ API violated its wMonth constraint;"
575 "this may cause mistakes for %s from %d",
576 ianaId.constData(), year);
578 const TransitionTimePair pair(rule, year, rule.standardTimeBias);
581 = m_tranRules.size() || pair.fakesDst ? year : initialYear(rule);
582 m_tranRules.append(rule);
588 QWinTransitionRule rule = readRegistryRule(baseKey, L"TZI", &ruleOk);
590 rule.startYear = initialYear(rule);
591 m_tranRules.append(rule);
598 if (m_tranRules.isEmpty()) {
601 m_displayName.clear();
602 }
else if (m_id.isEmpty()) {
603 m_id = m_standardName.toUtf8();
607QString QWinTimeZonePrivate::comment()
const
609 return m_displayName;
612QString QWinTimeZonePrivate::displayName(QTimeZone::TimeType timeType,
613 QTimeZone::NameType nameType,
614 const QLocale &locale)
const
617 if (nameType == QTimeZone::LongName && locale == QLocale::system()) {
619 case QTimeZone::DaylightTime :
620 return m_daylightName;
621 case QTimeZone::GenericTime :
622 return m_displayName;
623 case QTimeZone::StandardTime :
624 return m_standardName;
628 return QTimeZonePrivate::displayName(timeType, nameType, locale);;
631QString QWinTimeZonePrivate::abbreviation(qint64 atMSecsSinceEpoch)
const
633 return data(atMSecsSinceEpoch).abbreviation;
636int QWinTimeZonePrivate::offsetFromUtc(qint64 atMSecsSinceEpoch)
const
638 return data(atMSecsSinceEpoch).offsetFromUtc;
641int QWinTimeZonePrivate::standardTimeOffset(qint64 atMSecsSinceEpoch)
const
643 return data(atMSecsSinceEpoch).standardTimeOffset;
646int QWinTimeZonePrivate::daylightTimeOffset(qint64 atMSecsSinceEpoch)
const
648 return data(atMSecsSinceEpoch).daylightTimeOffset;
651bool QWinTimeZonePrivate::hasDaylightTime()
const
658 for (
const QWinTransitionRule &rule : m_tranRules) {
659 if (rule.standardTimeRule.wMonth > 0 && rule.daylightTimeRule.wMonth > 0)
665bool QWinTimeZonePrivate::isDaylightTime(qint64 atMSecsSinceEpoch)
const
667 return (data(atMSecsSinceEpoch).daylightTimeOffset != 0);
670QTimeZonePrivate::Data QWinTimeZonePrivate::data(qint64 forMSecsSinceEpoch)
const
673 int year = msecsToDate(forMSecsSinceEpoch).year();
674 for (
int ruleIndex = ruleIndexForYear(m_tranRules, year);
675 ruleIndex >= 0; --ruleIndex) {
676 const QWinTransitionRule &rule = m_tranRules.at(ruleIndex);
677 Q_ASSERT(ruleIndex == 0 || year >= rule.startYear);
678 if (year < rule.startYear
679 || !(rule.standardTimeRule.wMonth > 0 || rule.daylightTimeRule.wMonth > 0)) {
681 return ruleToData(rule, forMSecsSinceEpoch, QTimeZone::StandardTime);
684 int prior = year == 1 ? -1 : year - 1;
685 const int endYear = qMax(rule.startYear, prior);
686 while (year >= endYear) {
687 const int newYearOffset = (prior < rule.startYear && ruleIndex > 0)
688 ? yearEndOffset(m_tranRules.at(ruleIndex - 1), prior)
689 : yearEndOffset(rule, prior);
690 const TransitionTimePair pair(rule, year, newYearOffset);
692 if (ruleIndex == 0 && pair.beforeInitialDst(year, forMSecsSinceEpoch)) {
696 }
else if (pair.std != invalidMSecs() && pair.std <= forMSecsSinceEpoch) {
697 isDst = pair.std < pair.dst && pair.dst <= forMSecsSinceEpoch;
698 }
else if (pair.dst != invalidMSecs() && pair.dst <= forMSecsSinceEpoch) {
702 prior = year == 1 ? -1 : year - 1;
705 return ruleToData(rule, forMSecsSinceEpoch,
706 isDst ? QTimeZone::DaylightTime : QTimeZone::StandardTime,
710 Q_ASSERT(year < rule.startYear);
717bool QWinTimeZonePrivate::hasTransitions()
const
723QTimeZonePrivate::Data QWinTimeZonePrivate::nextTransition(qint64 afterMSecsSinceEpoch)
const
726 int year = msecsToDate(afterMSecsSinceEpoch).year();
727 int newYearOffset = invalidSeconds();
728 for (
int ruleIndex = ruleIndexForYear(m_tranRules, year);
729 ruleIndex < m_tranRules.count(); ++ruleIndex) {
730 const QWinTransitionRule &rule = m_tranRules.at(ruleIndex);
732 if (rule.standardTimeRule.wMonth > 0 || rule.daylightTimeRule.wMonth > 0) {
733 int prior = year == 1 ? -1 : year - 1;
734 if (newYearOffset == invalidSeconds()) {
737 newYearOffset = (prior < rule.startYear && ruleIndex > 0)
738 ? yearEndOffset(m_tranRules.at(ruleIndex - 1), prior)
739 : yearEndOffset(rule, prior);
741 if (year < rule.startYear) {
745 TransitionTimePair pair(rule, rule.startYear, newYearOffset);
749 return pair.ruleToData(rule,
this, !(year > FIRST_DST_YEAR && pair.startsInDst()));
751 const int endYear = ruleIndex + 1 < m_tranRules.count()
752 ? qMin(m_tranRules.at(ruleIndex + 1).startYear, year + 2) : (year + 2);
753 while (year < endYear) {
754 const TransitionTimePair pair(rule, year, newYearOffset);
756 Q_ASSERT(invalidMSecs() <= afterMSecsSinceEpoch);
757 if (ruleIndex == 0 && pair.beforeInitialDst(year, afterMSecsSinceEpoch)) {
760 Q_ASSERT(year == FIRST_DST_YEAR);
766 }
else if (pair.std > afterMSecsSinceEpoch) {
767 isDst = pair.std > pair.dst && pair.dst > afterMSecsSinceEpoch;
768 }
else if (pair.dst > afterMSecsSinceEpoch) {
771 newYearOffset = rule.standardTimeBias;
772 if (pair.dst > pair.std)
773 newYearOffset += rule.daylightTimeBias;
776 year = year == -1 ? 1 : year + 1;
780 return pair.ruleToData(rule,
this, isDst);
787 if (newYearOffset == invalidSeconds())
788 newYearOffset = rule.standardTimeBias;
790 Q_ASSERT(newYearOffset == rule.standardTimeBias);
797QTimeZonePrivate::Data QWinTimeZonePrivate::previousTransition(qint64 beforeMSecsSinceEpoch)
const
800 if (beforeMSecsSinceEpoch <= minMSecs())
803 int year = msecsToDate(beforeMSecsSinceEpoch).year();
804 for (
int ruleIndex = ruleIndexForYear(m_tranRules, year);
805 ruleIndex >= 0; --ruleIndex) {
806 const QWinTransitionRule &rule = m_tranRules.at(ruleIndex);
807 Q_ASSERT(ruleIndex == 0 || year >= rule.startYear);
809 if (year >= rule.startYear
810 && (rule.standardTimeRule.wMonth > 0 || rule.daylightTimeRule.wMonth > 0)) {
811 int prior = year == 1 ? -1 : year - 1;
812 const int endYear = qMax(rule.startYear, prior);
813 while (year >= endYear) {
814 const int newYearOffset = (prior < rule.startYear && ruleIndex > 0)
815 ? yearEndOffset(m_tranRules.at(ruleIndex - 1), prior)
816 : yearEndOffset(rule, prior);
817 const TransitionTimePair pair(rule, year, newYearOffset);
822 if (ruleIndex == 0 && pair.beforeInitialDst(year, beforeMSecsSinceEpoch - 1))
823 return ruleToData(rule, minMSecs(), QTimeZone::StandardTime,
false);
826 if (pair.std != invalidMSecs() && pair.std < beforeMSecsSinceEpoch) {
827 isDst = pair.std < pair.dst && pair.dst < beforeMSecsSinceEpoch;
828 }
else if (pair.dst != invalidMSecs() && pair.dst < beforeMSecsSinceEpoch) {
832 prior = year == 1 ? -1 : year - 1;
835 return pair.ruleToData(rule,
this, isDst);
838 }
else if (ruleIndex == 0) {
842 return ruleToData(rule, minMSecs(), QTimeZone::StandardTime,
false);
844 if (year >= rule.startYear) {
845 year = rule.startYear - 1;
854QByteArray QWinTimeZonePrivate::systemTimeZoneId()
const
856 const QLocale::Territory territory = userTerritory();
857 const QByteArray windowsId = windowsSystemZoneId();
858 QByteArrayView ianaId;
860 if (territory != QLocale::AnyTerritory)
861 ianaId = windowsIdToDefaultIanaId(windowsId, territory);
863 if (ianaId.isEmpty())
864 ianaId = windowsIdToDefaultIanaId(windowsId);
865 return ianaId.toByteArray();
868QList<QByteArray> QWinTimeZonePrivate::availableTimeZoneIds()
const
870 static const QList<QByteArray> cache = [] {
871 QList<QByteArray> result;
872 const auto winIds = availableWindowsIds();
873 for (
const QByteArray &winId : winIds)
874 result += windowsIdToIanaIds(winId);
875 return QTimeZonePrivate::uniqueSortedAliasPadded(std::move(result));
880QTimeZonePrivate::Data QWinTimeZonePrivate::ruleToData(
const QWinTransitionRule &rule,
881 qint64 atMSecsSinceEpoch,
882 QTimeZone::TimeType type,
886 tran.atMSecsSinceEpoch = atMSecsSinceEpoch;
887 tran.standardTimeOffset = rule.standardTimeBias * -60;
889 tran.daylightTimeOffset = 0;
891 if (type == QTimeZone::DaylightTime)
892 tran.standardTimeOffset += rule.daylightTimeBias * -60;
893 }
else if (type == QTimeZone::DaylightTime) {
894 tran.daylightTimeOffset = rule.daylightTimeBias * -60;
896 tran.daylightTimeOffset = 0;
898 tran.offsetFromUtc = tran.standardTimeOffset + tran.daylightTimeOffset;
899 tran.abbreviation = localeName(atMSecsSinceEpoch, tran.offsetFromUtc,
900 type, QTimeZone::ShortName, QLocale::system());
\inmodule QtCore \reentrant
QT_REQUIRE_CONFIG(timezone_locale)
constexpr qint64 JULIAN_DAY_FOR_EPOCH
constexpr int FIRST_DST_YEAR
static const wchar_t tzRegPath[]
static const wchar_t currTzRegPath[]
constexpr qint64 MSECS_PER_DAY