diff options
Diffstat (limited to 'src/corelib/time/qtimezoneprivate.cpp')
-rw-r--r-- | src/corelib/time/qtimezoneprivate.cpp | 184 |
1 files changed, 138 insertions, 46 deletions
diff --git a/src/corelib/time/qtimezoneprivate.cpp b/src/corelib/time/qtimezoneprivate.cpp index 861ebefbdf..b18b7e8758 100644 --- a/src/corelib/time/qtimezoneprivate.cpp +++ b/src/corelib/time/qtimezoneprivate.cpp @@ -5,6 +5,9 @@ #include "qtimezone.h" #include "qtimezoneprivate_p.h" +#if QT_CONFIG(timezone_locale) +# include "qtimezonelocale_p.h" +#endif #include "qtimezoneprivate_data_p.h" #include <qdatastream.h> @@ -51,6 +54,11 @@ constexpr bool atLowerWindowsKey(const WindowsData &entry, qint16 winIdKey) noex return entry.windowsIdKey < winIdKey; } +static bool earlierAliasId(const AliasData &entry, QByteArrayView aliasId) noexcept +{ + return entry.aliasId().compare(aliasId, Qt::CaseInsensitive) < 0; +} + static bool earlierWindowsId(const WindowsData &entry, QByteArrayView winId) noexcept { return entry.windowsId().compare(winId, Qt::CaseInsensitive) < 0; @@ -172,22 +180,37 @@ QString QTimeZonePrivate::displayName(qint64 atMSecsSinceEpoch, QTimeZone::NameType nameType, const QLocale &locale) const { - if (nameType == QTimeZone::OffsetName) - return isoOffsetFormat(offsetFromUtc(atMSecsSinceEpoch)); - - if (isDaylightTime(atMSecsSinceEpoch)) - return displayName(QTimeZone::DaylightTime, nameType, locale); - else - return displayName(QTimeZone::StandardTime, nameType, locale); + const Data tran = data(atMSecsSinceEpoch); + if (tran.atMSecsSinceEpoch != invalidMSecs()) { + if (nameType == QTimeZone::OffsetName && locale.language() == QLocale::C) + return isoOffsetFormat(tran.offsetFromUtc); + if (nameType == QTimeZone::ShortName && isDataLocale(locale)) + return tran.abbreviation; + + QTimeZone::TimeType timeType + = tran.daylightTimeOffset != 0 ? QTimeZone::DaylightTime : QTimeZone::StandardTime; +#if QT_CONFIG(timezone_locale) + return localeName(atMSecsSinceEpoch, tran.offsetFromUtc, timeType, nameType, locale); +#else + return displayName(timeType, nameType, locale); +#endif + } + return QString(); } QString QTimeZonePrivate::displayName(QTimeZone::TimeType timeType, QTimeZone::NameType nameType, const QLocale &locale) const { - Q_UNUSED(timeType); - Q_UNUSED(nameType); - Q_UNUSED(locale); + const Data tran = data(timeType); + if (tran.atMSecsSinceEpoch != invalidMSecs()) { + if (nameType == QTimeZone::OffsetName && isDataLocale(locale)) + return isoOffsetFormat(tran.offsetFromUtc); + +#if QT_CONFIG(timezone_locale) + return localeName(tran.atMSecsSinceEpoch, tran.offsetFromUtc, timeType, nameType, locale); +#endif + } return QString(); } @@ -227,17 +250,67 @@ bool QTimeZonePrivate::isDaylightTime(qint64 atMSecsSinceEpoch) const return false; } +QTimeZonePrivate::Data QTimeZonePrivate::data(QTimeZone::TimeType timeType) const +{ + // True if tran is valid and has the DST-ness to match timeType: + const auto validMatch = [timeType](const QTimeZonePrivate::Data &tran) { + return tran.atMSecsSinceEpoch != invalidMSecs() + && ((timeType == QTimeZone::DaylightTime) != (tran.daylightTimeOffset == 0)); + }; + + // Get current tran, use if suitable: + const qint64 currentMSecs = QDateTime::currentMSecsSinceEpoch(); + QTimeZonePrivate::Data tran = data(currentMSecs); + if (validMatch(tran)) + return tran; + + if (hasTransitions()) { + // Otherwise, next tran probably flips DST-ness: + tran = nextTransition(currentMSecs); + if (validMatch(tran)) + return tran; + + // Failing that, prev (or present, if current MSecs is exactly a + // transition moment) tran defines what data() got us and the one before + // that probably flips DST-ness; failing that, keep marching backwards + // in search of a DST interval: + tran = previousTransition(currentMSecs + 1); + while (tran.atMSecsSinceEpoch != invalidMSecs()) { + tran = previousTransition(tran.atMSecsSinceEpoch); + if (validMatch(tran)) + return tran; + } + } + return {}; +} + +/*! + \internal + + Returns true if the abbreviation given in data()'s returns is appropriate + for use in the given \a locale. + + Base implementation assumes data() corresponds to the system locale; derived + classes should override if their data() is something else (such as + C/English). +*/ +bool QTimeZonePrivate::isDataLocale(const QLocale &locale) const +{ + // Guess data is for the system locale unless backend overrides that. + return locale == QLocale::system(); +} + QTimeZonePrivate::Data QTimeZonePrivate::data(qint64 forMSecsSinceEpoch) const { Q_UNUSED(forMSecsSinceEpoch); - return invalidData(); + return {}; } // Private only method for use by QDateTime to convert local msecs to epoch msecs QDateTimePrivate::ZoneState QTimeZonePrivate::stateAtZoneTime( qint64 forLocalMSecs, QDateTimePrivate::TransitionOptions resolve) const { - auto dataToState = [](QTimeZonePrivate::Data d) { + auto dataToState = [](const QTimeZonePrivate::Data &d) { return QDateTimePrivate::ZoneState(d.atMSecsSinceEpoch + d.offsetFromUtc * 1000, d.offsetFromUtc, d.daylightTimeOffset ? QDateTimePrivate::DaylightTime @@ -489,13 +562,13 @@ bool QTimeZonePrivate::hasTransitions() const QTimeZonePrivate::Data QTimeZonePrivate::nextTransition(qint64 afterMSecsSinceEpoch) const { Q_UNUSED(afterMSecsSinceEpoch); - return invalidData(); + return {}; } QTimeZonePrivate::Data QTimeZonePrivate::previousTransition(qint64 beforeMSecsSinceEpoch) const { Q_UNUSED(beforeMSecsSinceEpoch); - return invalidData(); + return {}; } QTimeZonePrivate::DataList QTimeZonePrivate::transitions(qint64 fromMSecsSinceEpoch, @@ -532,7 +605,8 @@ QList<QByteArray> QTimeZonePrivate::availableTimeZoneIds() const return QList<QByteArray>(); } -static QList<QByteArray> selectAvailable(QList<QByteArray>&& desired, const QList<QByteArray>& all) +static QList<QByteArray> selectAvailable(QList<QByteArrayView> &&desired, + const QList<QByteArray> &all) { std::sort(desired.begin(), desired.end()); const auto newEnd = std::unique(desired.begin(), desired.end()); @@ -547,13 +621,13 @@ static QList<QByteArray> selectAvailable(QList<QByteArray>&& desired, const QLis QList<QByteArray> QTimeZonePrivate::availableTimeZoneIds(QLocale::Territory territory) const { // Default fall-back mode, use the zoneTable to find Region of know Zones - QList<QByteArray> regions; + QList<QByteArrayView> regions; // First get all Zones in the Zones table belonging to the Region for (const ZoneData &data : zoneDataTable) { if (data.territory == territory) { for (auto l1 : data.ids()) - regions << QByteArray(l1.data(), l1.size()); + regions << QByteArrayView(l1.data(), l1.size()); } } return selectAvailable(std::move(regions), availableTimeZoneIds()); @@ -561,16 +635,16 @@ QList<QByteArray> QTimeZonePrivate::availableTimeZoneIds(QLocale::Territory terr QList<QByteArray> QTimeZonePrivate::availableTimeZoneIds(int offsetFromUtc) const { - // Default fall-back mode, use the zoneTable to find Offset of know Zones - QList<QByteArray> offsets; - // First get all Zones in the table using the Offset + // Default fall-back mode: use the zoneTable to find offsets of know zones. + QList<QByteArrayView> offsets; + // First get all Zones in the table using the given offset: for (const WindowsData &winData : windowsDataTable) { if (winData.offsetFromUtc == offsetFromUtc) { for (auto data = zoneStartForWindowsId(winData.windowsIdKey); data != std::end(zoneDataTable) && data->windowsIdKey == winData.windowsIdKey; ++data) { for (auto l1 : data->ids()) - offsets << QByteArray(l1.data(), l1.size()); + offsets << QByteArrayView(l1.data(), l1.size()); } } } @@ -586,37 +660,21 @@ void QTimeZonePrivate::serialize(QDataStream &ds) const // Static Utility Methods -QTimeZonePrivate::Data QTimeZonePrivate::invalidData() -{ - Data data; - data.atMSecsSinceEpoch = invalidMSecs(); - data.offsetFromUtc = invalidSeconds(); - data.standardTimeOffset = invalidSeconds(); - data.daylightTimeOffset = invalidSeconds(); - return data; -} - QTimeZone::OffsetData QTimeZonePrivate::invalidOffsetData() { - QTimeZone::OffsetData offsetData; - offsetData.atUtc = QDateTime(); - offsetData.offsetFromUtc = invalidSeconds(); - offsetData.standardTimeOffset = invalidSeconds(); - offsetData.daylightTimeOffset = invalidSeconds(); - return offsetData; + return { QString(), QDateTime(), + invalidSeconds(), invalidSeconds(), invalidSeconds() }; } QTimeZone::OffsetData QTimeZonePrivate::toOffsetData(const QTimeZonePrivate::Data &data) { - QTimeZone::OffsetData offsetData = invalidOffsetData(); - if (data.atMSecsSinceEpoch != invalidMSecs()) { - offsetData.atUtc = QDateTime::fromMSecsSinceEpoch(data.atMSecsSinceEpoch, QTimeZone::UTC); - offsetData.offsetFromUtc = data.offsetFromUtc; - offsetData.standardTimeOffset = data.standardTimeOffset; - offsetData.daylightTimeOffset = data.daylightTimeOffset; - offsetData.abbreviation = data.abbreviation; - } - return offsetData; + if (data.atMSecsSinceEpoch == invalidMSecs()) + return invalidOffsetData(); + + return { + data.abbreviation, + QDateTime::fromMSecsSinceEpoch(data.atMSecsSinceEpoch, QTimeZone::UTC), + data.offsetFromUtc, data.standardTimeOffset, data.daylightTimeOffset }; } // Is the format of the ID valid ? @@ -717,6 +775,18 @@ QString QTimeZonePrivate::isoOffsetFormat(int offsetFromUtc, QTimeZone::NameType return result; } +QByteArray QTimeZonePrivate::aliasToIana(QByteArrayView alias) +{ + const auto data = std::lower_bound(std::begin(aliasMappingTable), std::end(aliasMappingTable), + alias, earlierAliasId); + if (data != std::end(aliasMappingTable) && data->aliasId() == alias) + return data->ianaId().toByteArray(); + // Note: empty return means not an alias, which is true of an ID that others + // are aliases to, as the table omits self-alias entries. Let caller sort + // that out, rather than allocating to return alias.toByteArray(). + return {}; +} + QByteArray QTimeZonePrivate::ianaIdToWindowsId(const QByteArray &id) { const auto idUtf8 = QUtf8StringView(id); @@ -922,6 +992,19 @@ QTimeZonePrivate::Data QUtcTimeZonePrivate::data(qint64 forMSecsSinceEpoch) cons return d; } +// Override to shortcut past base's complications: +QTimeZonePrivate::Data QUtcTimeZonePrivate::data(QTimeZone::TimeType timeType) const +{ + Q_UNUSED(timeType); + return data(QDateTime::currentMSecsSinceEpoch()); +} + +bool QUtcTimeZonePrivate::isDataLocale(const QLocale &locale) const +{ + // Officially only supports C locale names; these are surely also viable for English. + return locale.language() == QLocale::C || locale.language() == QLocale::English; +} + void QUtcTimeZonePrivate::init(const QByteArray &zoneId) { m_id = zoneId; @@ -949,6 +1032,15 @@ QString QUtcTimeZonePrivate::comment() const return m_comment; } +// Override to bypass complications in base-class: +QString QUtcTimeZonePrivate::displayName(qint64 atMSecsSinceEpoch, + QTimeZone::NameType nameType, + const QLocale &locale) const +{ + Q_UNUSED(atMSecsSinceEpoch); + return displayName(QTimeZone::StandardTime, nameType, locale); +} + QString QUtcTimeZonePrivate::displayName(QTimeZone::TimeType timeType, QTimeZone::NameType nameType, const QLocale &locale) const |