169QString QTimeZonePrivate::displayName(qint64 atMSecsSinceEpoch,
170 QTimeZone::NameType nameType,
171 const QLocale &locale)
const
173 const Data tran = data(atMSecsSinceEpoch);
174 if (tran.atMSecsSinceEpoch != invalidMSecs()) {
175 if (nameType == QTimeZone::OffsetName && locale.language() == QLocale::C)
176 return isoOffsetFormat(tran.offsetFromUtc);
177 if (nameType == QTimeZone::ShortName && isDataLocale(locale))
178 return tran.abbreviation;
180 QTimeZone::TimeType timeType
181 = tran.daylightTimeOffset != 0 ? QTimeZone::DaylightTime : QTimeZone::StandardTime;
182#if QT_CONFIG(timezone_locale)
183 return localeName(atMSecsSinceEpoch, tran.offsetFromUtc, timeType, nameType, locale);
185 return displayName(timeType, nameType, locale);
305QDateTimePrivate::ZoneState QTimeZonePrivate::stateAtZoneTime(
306 qint64 forLocalMSecs, QDateTimePrivate::TransitionOptions resolve)
const
308 auto dataToState = [](
const Data &d) {
309 return QDateTimePrivate::ZoneState(d.atMSecsSinceEpoch + d.offsetFromUtc * 1000,
311 d.daylightTimeOffset ? QDateTimePrivate::DaylightTime
312 : QDateTimePrivate::StandardTime);
316
317
318
319
320
321
322
323 std::integral_constant<qint64, 17 * 3600 * 1000> seventeenHoursInMSecs;
324 static_assert(-seventeenHoursInMSecs / 1000 < QTimeZone::MinUtcOffsetSecs
325 && seventeenHoursInMSecs / 1000 > QTimeZone::MaxUtcOffsetSecs);
328 const qint64 recent =
329 qSubOverflow(forLocalMSecs, seventeenHoursInMSecs, &millis) || millis < minMSecs()
330 ? minMSecs() : millis;
332 const qint64 imminent =
333 qAddOverflow(forLocalMSecs, seventeenHoursInMSecs, &millis)
334 ? maxMSecs() : millis;
336 Q_ASSERT(recent < imminent && seventeenHoursInMSecs < imminent - recent + 1);
338 const Data past = data(recent), future = data(imminent);
339 if (future.atMSecsSinceEpoch == invalidMSecs()
340 && past.atMSecsSinceEpoch == invalidMSecs()) {
343 return { forLocalMSecs };
346 if (Q_LIKELY(past.offsetFromUtc == future.offsetFromUtc
347 && past.standardTimeOffset == future.standardTimeOffset
349 && past.abbreviation == future.abbreviation)) {
351 data.atMSecsSinceEpoch = forLocalMSecs - future.offsetFromUtc * 1000;
352 return dataToState(data);
356
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 if (hasTransitions()) {
383
384
385
386
387
388
389
390
391
392
397 Q_ASSERT(forLocalMSecs < 0 ||
398 forLocalMSecs - tran.offsetFromUtc * 1000 >= tran.atMSecsSinceEpoch);
400 Data nextTran = nextTransition(tran.atMSecsSinceEpoch);
402
403
404
405
406
407
408
409 while (nextTran.atMSecsSinceEpoch != invalidMSecs()
410 && forLocalMSecs > nextTran.atMSecsSinceEpoch + nextTran.offsetFromUtc * 1000) {
411 Data newTran = nextTransition(nextTran.atMSecsSinceEpoch);
412 if (newTran.atMSecsSinceEpoch == invalidMSecs()
413 || newTran.atMSecsSinceEpoch + newTran.offsetFromUtc * 1000 > imminent) {
420 const qint64 nextStart = nextTran.atMSecsSinceEpoch;
423 if (tran.atMSecsSinceEpoch != invalidMSecs()) {
425 Q_ASSERT(forLocalMSecs < 0
426 || forLocalMSecs - tran.offsetFromUtc * 1000 > tran.atMSecsSinceEpoch);
428 tran.atMSecsSinceEpoch = forLocalMSecs - tran.offsetFromUtc * 1000;
436 if (nextStart == invalidMSecs() && tran.offsetFromUtc == future.offsetFromUtc)
437 return dataToState(tran);
440 if (tran.atMSecsSinceEpoch != invalidMSecs() && nextStart != invalidMSecs()) {
442
443
444
445
446
447
448
449
450
452 nextTran.atMSecsSinceEpoch = forLocalMSecs - nextTran.offsetFromUtc * 1000;
454 bool fallBack =
false;
455 if (nextStart > nextTran.atMSecsSinceEpoch) {
457 if (nextStart > tran.atMSecsSinceEpoch)
458 return dataToState(tran);
460 Q_ASSERT(tran.offsetFromUtc < nextTran.offsetFromUtc);
462 }
else if (nextStart <= tran.atMSecsSinceEpoch) {
464 return dataToState(nextTran);
466 Q_ASSERT(nextTran.offsetFromUtc < tran.offsetFromUtc);
474 = resolve.testFlag(QDateTimePrivate::FlipForReverseDst)
475 && (fallBack ? !tran.daylightTimeOffset && nextTran.daylightTimeOffset
476 : tran.daylightTimeOffset && !nextTran.daylightTimeOffset);
479 if (resolve.testFlag(flipped
480 ? QDateTimePrivate::FoldUseBefore
481 : QDateTimePrivate::FoldUseAfter)) {
482 return dataToState(nextTran);
484 if (resolve.testFlag(flipped
485 ? QDateTimePrivate::FoldUseAfter
486 : QDateTimePrivate::FoldUseBefore)) {
487 return dataToState(tran);
491
492
493
494
495
496 std::swap(tran.atMSecsSinceEpoch, nextTran.atMSecsSinceEpoch);
497 if (resolve.testFlag(flipped
498 ? QDateTimePrivate::GapUseBefore
499 : QDateTimePrivate::GapUseAfter))
500 return dataToState(nextTran);
501 if (resolve.testFlag(flipped
502 ? QDateTimePrivate::GapUseAfter
503 : QDateTimePrivate::GapUseBefore))
504 return dataToState(tran);
507 return {forLocalMSecs};
514 qint64 utcEpochMSecs;
517 int early = past.offsetFromUtc;
518 int late = future.offsetFromUtc;
519 if (early == late || late == invalidSeconds()) {
520 if (early == invalidSeconds()
521 || qSubOverflow(forLocalMSecs, early * qint64(1000), &utcEpochMSecs)) {
522 return {forLocalMSecs};
526 const qint64 forEarly = forLocalMSecs - early * 1000;
527 const qint64 forLate = forLocalMSecs - late * 1000;
530 const bool earlyOk = offsetFromUtc(forEarly) == early;
531 const bool lateOk = offsetFromUtc(forLate) == late;
535 Q_ASSERT(early > late);
537 if (resolve.testFlag(QDateTimePrivate::FoldUseBefore))
538 utcEpochMSecs = forEarly;
539 else if (resolve.testFlag(QDateTimePrivate::FoldUseAfter))
540 utcEpochMSecs = forLate;
542 return {forLocalMSecs};
545 utcEpochMSecs = forEarly;
549 utcEpochMSecs = forLate;
552 Q_ASSERT(late > early);
553 const int dstStep = (late - early) * 1000;
554 if (resolve.testFlag(QDateTimePrivate::GapUseBefore))
555 utcEpochMSecs = forEarly - dstStep;
556 else if (resolve.testFlag(QDateTimePrivate::GapUseAfter))
557 utcEpochMSecs = forLate + dstStep;
559 return {forLocalMSecs};
563 return dataToState(data(utcEpochMSecs));
972QUtcTimeZonePrivate::QUtcTimeZonePrivate(qint32 offsetSeconds)
977 const auto data = std::lower_bound(std::begin(utcDataTable), std::end(utcDataTable),
978 offsetSeconds, atLowerUtcOffset);
979 if (data != std::end(utcDataTable) && data->offsetFromUtc == offsetSeconds) {
980 QByteArrayView ianaId = data->id();
981 qsizetype cut = ianaId.indexOf(
' ');
982 QByteArrayView cutId = (cut < 0 ? ianaId : ianaId.first(cut));
983 if (cutId == utcQByteArray()) {
985 id = utcQByteArray();
989 id = cutId.toByteArray();
990 name = QString::fromUtf8(id);
992 Q_ASSERT(!name.isEmpty());
994 name = isoOffsetFormat(offsetSeconds, QTimeZone::ShortName);
997 init(id, offsetSeconds, name, name, QLocale::AnyTerritory, name);
1156QList<QByteArray> QUtcTimeZonePrivate::availableTimeZoneIds(qint32 offsetSeconds)
const
1160 QList<QByteArray> result;
1161 const auto data = std::lower_bound(std::begin(utcDataTable), std::end(utcDataTable),
1162 offsetSeconds, atLowerUtcOffset);
1163 if (data != std::end(utcDataTable) && data->offsetFromUtc == offsetSeconds) {
1164 QByteArrayView id = data->id();
1166 while ((cut = id.indexOf(
' ')) >= 0) {
1167 result << id.first(cut).toByteArray();
1168 id = id.sliced(cut + 1);
1170 result << id.toByteArray();
1175 QByteArray isoName = isoOffsetFormat(offsetSeconds, QTimeZone::ShortName).toUtf8();
1176 if (offsetFromUtcString(isoName) == qint64(offsetSeconds) && !result.contains(isoName))
1179 std::sort(result.begin(), result.end());