8#include "private/qlocale_tools_p.h"
9#include "private/qlocking_p.h"
11#include <QtCore/QDataStream>
12#include <QtCore/QDateTime>
13#include <QtCore/QDirIterator>
14#include <QtCore/QFile>
15#include <QtCore/QCache>
17#include <QtCore/QMutex>
20#include <qplatformdefs.h>
68 while (!tzif.
atEnd()) {
88 zonesHash.
insert(
id, zone);
105 :
name.startsWith(
"posix/"_L1) ||
name.startsWith(
"right/"_L1)) {
127#define TZ_MAGIC "TZif"
128#define TZ_MAX_TIMES 1200
129#define TZ_MAX_TYPES 256
130#define TZ_MAX_CHARS 50
131#define TZ_MAX_LEAPS 50
217 ds >> transitions[
i].tz_time;
226 transitions[
i].tz_time =
val;
237 transitions[
i].tz_typeind = typeind;
251 ds >>
type.tz_gmtoff;
257 ds >>
type.tz_abbrind;
370 else if (dayOfWeek & ~7 || month < 1 || month > 12 || week < 1 || week > 5)
375 if (startDow <= dayOfWeek)
390 if (dateRule.
at(0) ==
'M') {
393 if (dateParts.
size() > 2) {
396 int week =
ok ? dateParts.
at(1).toInt(&
ok) : 0;
397 int dow =
ok ? dateParts.
at(2).toInt(&
ok) : 0;
401 }
else if (dateRule.
at(0) ==
'J') {
405 if (
ok && doy > 0 && doy < 366) {
416 if (
ok && doy >= 0 && doy < 366)
426 int hour, min = 0, sec = 0;
428 const int maxHour = 137;
431 if (!
r.ok() || hour < -maxHour || hour > maxHour ||
r.used > 2)
439 if (!
r.ok() || min < 0 || min > 59 ||
r.used > 2)
448 if (!
r.ok() || sec < 0 || sec > 59 ||
r.used > 2)
458 return (hour * 60 + min) * 60 + sec;
473 }
else if (*
begin ==
'-') {
479 if (
value == INT_MIN)
487 return ch >=
'a' &&
ch <=
'z';
495 InvalidOffset = INT_MIN,
501 static PosixZone invalid() {
return {
QString(), InvalidOffset}; }
502 static PosixZone parse(
const char *&
pos,
const char *
end);
504 bool hasValidOffset() const noexcept {
return offset != InvalidOffset; }
512PosixZone PosixZone::parse(
const char *&
pos,
const char *
end)
514 static const char offsetChars[] =
"0123456789:";
516 const char *nameBegin =
pos;
523 while (nameEnd <
end && *nameEnd !=
'>') {
534 if (nameEnd - nameBegin < 3)
538 const char *zoneBegin =
pos;
539 const char *zoneEnd =
pos;
540 if (zoneEnd <
end && (zoneEnd[0] ==
'+' || zoneEnd[0] ==
'-'))
542 while (zoneEnd <
end) {
543 if (strchr(offsetChars,
char(*zoneEnd)) ==
nullptr)
568 const auto parts = posixRule.
split(
',');
569 const struct {
bool isValid, hasDst; } fail{
false,
false}, good{
true, parts.
size() > 1};
577 const auto posix = PosixZone::parse(
begin, zoneinfo.
end());
578 if (posix.name.isEmpty())
580 if (requireOffset && !posix.hasValidOffset())
588 if (PosixZone::parse(
begin, zoneinfo.
end()).name.isEmpty())
595 if (parts.size() != 3 || parts.at(1).isEmpty() || parts.at(2).isEmpty())
597 for (
int i = 1;
i < 3; ++
i) {
598 const auto tran = parts.at(
i).split(
'/');
601 if (tran.size() > 1) {
602 const auto time = tran.at(1);
612 int startYear,
int endYear,
624 PosixZone stdZone, dstZone = PosixZone::invalid();
630 if (!stdZone.hasValidOffset()) {
634 if (!dstZone.hasValidOffset()) {
636 dstZone.offset = stdZone.offset + (60 * 60);
642 if (parts.
size() == 1 || !dstZone.hasValidOffset()) {
644 data.atMSecsSinceEpoch = lastTranMSecs;
645 data.offsetFromUtc = stdZone.offset;
646 data.standardTimeOffset = stdZone.offset;
647 data.daylightTimeOffset = 0;
652 if (parts.
size() < 3 || parts.
at(1).isEmpty() || parts.
at(2).isEmpty())
656 const int twoOClock = 7200;
657 const auto dstParts = parts.
at(1).split(
'/');
662 const auto stdParts = parts.
at(2).split(
'/');
666 if (dstDateRule.
isEmpty() || stdDateRule.
isEmpty() || dstTime == INT_MIN || stdTime == INT_MIN)
672 startYear =
qBound(minYear, startYear, maxYear);
673 endYear =
qBound(minYear, endYear, maxYear);
676 for (
int year = startYear; year <= endYear; ++year) {
699 if (year == startYear) {
721 const bool useStd =
std.isValid() &&
std.date().year() == year && !stdZone.name.isEmpty();
722 const bool useDst =
dst.isValid() &&
dst.date().year() == year && !dstZone.name.isEmpty();
723 if (useStd && useDst) {
725 result << dstData << stdData;
727 result << stdData << dstData;
738QTzTimeZonePrivate::QTzTimeZonePrivate()
739 : QTzTimeZonePrivate(staticSystemTimeZoneId())
743QTzTimeZonePrivate::~QTzTimeZonePrivate()
747QTzTimeZonePrivate *QTzTimeZonePrivate::clone()
const
752 return new QTzTimeZonePrivate(*
this);
761 QTzTimeZoneCacheEntry findEntry(
const QByteArray &ianaId);
766QTzTimeZoneCacheEntry QTzTimeZoneCache::findEntry(
const QByteArray &ianaId)
768 QTzTimeZoneCacheEntry
ret;
784 ret.m_hasDst = check.hasDst;
785 ret.m_posixRule = ianaId;
847 ret.m_posixRule = posixRule;
848 ret.m_hasDst = check.hasDst;
853 ret.m_abbreviations.clear();
854 ret.m_abbreviations.reserve(
size);
858 ret.m_abbreviations.append(
it.value());
870 ret.m_preZoneRule = { 0, 0, 0 };
874 int utcOffset =
ret.m_preZoneRule.stdOffset;
876 if (!
typeList.at(tran.tz_typeind).tz_isdst) {
877 utcOffset =
typeList.at(tran.tz_typeind).tz_gmtoff;
883 const int tranCount = tranList.
size();;
884 ret.m_tranTimes.reserve(tranCount);
886 int lastDstOff = 3600;
887 for (
int i = 0;
i < tranCount;
i++) {
889 QTzTransitionTime tran;
890 QTzTransitionRule
rule;
904 const int inferStd = tz_type.
tz_gmtoff - lastDstOff;
905 for (
int j =
i + 1;
j < tranCount;
j++) {
909 if (newUtc == utcOffset) {
912 }
else if (newUtc == inferStd) {
915 }
else if (tz_type.
tz_gmtoff - 3600 == utcOffset) {
917 }
else if (tz_type.
tz_gmtoff - 3600 == newUtc) {
923 ||
qAbs(newUtc - inferStd) <
qAbs(utcOffset - inferStd))
924 : (utcOffset >= tz_type.tz_gmtoff
925 &&
qAbs(newUtc - inferStd) <
qAbs(utcOffset - inferStd))) {
931 lastDstOff = tz_type.
tz_gmtoff - utcOffset;
933 rule.stdOffset = utcOffset;
938 int ruleIndex =
ret.m_tranRules.indexOf(
rule);
939 if (ruleIndex == -1) {
940 if (
rule.dstOffset != 0)
942 tran.ruleIndex =
ret.m_tranRules.size();
945 tran.ruleIndex = ruleIndex;
948 tran.atMSecsSinceEpoch = tz_tran.
tz_time * 1000;
949 ret.m_tranTimes.append(tran);
960 QTzTimeZoneCacheEntry *
obj = m_cache.
object(ianaId);
965 QTzTimeZoneCacheEntry
ret = findEntry(ianaId);
966 m_cache.
insert(ianaId,
new QTzTimeZoneCacheEntry(
ret));
971QTzTimeZonePrivate::QTzTimeZonePrivate(
const QByteArray &ianaId)
975 if (
entry.m_tranTimes.isEmpty() &&
entry.m_posixRule.isEmpty())
978 cached_data = std::move(
entry);
981 if (m_id.isEmpty()) {
987 m_icu =
new QIcuTimeZonePrivate();
999 return tzZones->value(m_id).territory;
1002QString QTzTimeZonePrivate::comment()
const
1007QString QTzTimeZonePrivate::displayName(
qint64 atMSecsSinceEpoch,
1008 QTimeZone::NameType nameType,
1014 m_icu =
new QIcuTimeZonePrivate(m_id);
1017 if (m_icu->isValid())
1018 return m_icu->displayName(atMSecsSinceEpoch, nameType, locale);
1028QString QTzTimeZonePrivate::displayName(QTimeZone::TimeType timeType,
1029 QTimeZone::NameType nameType,
1035 m_icu =
new QIcuTimeZonePrivate(m_id);
1038 if (m_icu->isValid())
1039 return m_icu->displayName(timeType, nameType, locale);
1048 if (timeType == QTimeZone::GenericTime)
1049 timeType = QTimeZone::StandardTime;
1061 tran = nextTransition(currentMSecs);
1069 tran = previousTransition(currentMSecs);
1079 auto it = std::partition_point(tranCache().cbegin(), tranCache().
cend(),
1080 [currentMSecs](
const QTzTransitionTime &
at) {
1081 return at.atMSecsSinceEpoch <= currentMSecs;
1084 while (
it != tranCache().cbegin()) {
1086 tran = dataForTzTransition(*
it);
1088 if ((timeType == QTimeZone::DaylightTime) != (
offset == 0))
1093 return data(currentMSecs).abbreviation;
1096QString QTzTimeZonePrivate::abbreviation(
qint64 atMSecsSinceEpoch)
const
1098 return data(atMSecsSinceEpoch).abbreviation;
1101int QTzTimeZonePrivate::offsetFromUtc(
qint64 atMSecsSinceEpoch)
const
1107int QTzTimeZonePrivate::standardTimeOffset(
qint64 atMSecsSinceEpoch)
const
1109 return data(atMSecsSinceEpoch).standardTimeOffset;
1112int QTzTimeZonePrivate::daylightTimeOffset(
qint64 atMSecsSinceEpoch)
const
1114 return data(atMSecsSinceEpoch).daylightTimeOffset;
1117bool QTzTimeZonePrivate::hasDaylightTime()
const
1119 return cached_data.m_hasDst;
1122bool QTzTimeZonePrivate::isDaylightTime(
qint64 atMSecsSinceEpoch)
const
1124 return (daylightTimeOffset(atMSecsSinceEpoch) != 0);
1129 return dataFromRule(cached_data.m_tranRules.at(tran.ruleIndex), tran.atMSecsSinceEpoch);
1133 qint64 msecsSinceEpoch)
const
1136 msecsSinceEpoch,
rule.stdOffset +
rule.dstOffset,
rule.stdOffset,
rule.dstOffset };
1143 qint64 atTime = tranCache().isEmpty() ? msNear : tranCache().last().atMSecsSinceEpoch;
1151 if (!cached_data.m_posixRule.isEmpty()
1152 && (tranCache().isEmpty() || tranCache().last().atMSecsSinceEpoch < forMSecsSinceEpoch)) {
1154 auto it = std::partition_point(posixTrans.
cbegin(), posixTrans.
cend(),
1156 return at.atMSecsSinceEpoch <= forMSecsSinceEpoch;
1159 if (
it > posixTrans.
cbegin() || (tranCache().isEmpty() &&
it < posixTrans.
cend())) {
1165 if (tranCache().isEmpty())
1169 auto last = std::partition_point(tranCache().cbegin(), tranCache().
cend(),
1170 [forMSecsSinceEpoch] (
const QTzTransitionTime &
at) {
1171 return at.atMSecsSinceEpoch <= forMSecsSinceEpoch;
1173 if (last == tranCache().cbegin())
1174 return dataFromRule(cached_data.m_preZoneRule, forMSecsSinceEpoch);
1177 return dataFromRule(cached_data.m_tranRules.at(last->ruleIndex), forMSecsSinceEpoch);
1180bool QTzTimeZonePrivate::hasTransitions()
const
1189 if (!cached_data.m_posixRule.isEmpty()
1190 && (tranCache().isEmpty() || tranCache().last().atMSecsSinceEpoch < afterMSecsSinceEpoch)) {
1192 auto it = std::partition_point(posixTrans.
cbegin(), posixTrans.
cend(),
1194 return at.atMSecsSinceEpoch <= afterMSecsSinceEpoch;
1201 auto last = std::partition_point(tranCache().cbegin(), tranCache().
cend(),
1202 [afterMSecsSinceEpoch] (
const QTzTransitionTime &
at) {
1203 return at.atMSecsSinceEpoch <= afterMSecsSinceEpoch;
1205 return last != tranCache().
cend() ? dataForTzTransition(*last) :
invalidData();
1212 if (!cached_data.m_posixRule.isEmpty()
1213 && (tranCache().isEmpty() || tranCache().last().atMSecsSinceEpoch < beforeMSecsSinceEpoch)) {
1215 auto it = std::partition_point(posixTrans.
cbegin(), posixTrans.
cend(),
1217 return at.atMSecsSinceEpoch < beforeMSecsSinceEpoch;
1222 return tranCache().
isEmpty() ?
invalidData() : dataForTzTransition(tranCache().last());
1226 auto last = std::partition_point(tranCache().cbegin(), tranCache().
cend(),
1227 [beforeMSecsSinceEpoch] (
const QTzTransitionTime &
at) {
1228 return at.atMSecsSinceEpoch < beforeMSecsSinceEpoch;
1230 return last > tranCache().cbegin() ? dataForTzTransition(*--last) :
invalidData();
1233bool QTzTimeZonePrivate::isTimeZoneIdAvailable(
const QByteArray &ianaId)
const
1254 if (
it.value().territory == territory)
1284 const StatIdent local = identify(
"/etc/localtime");
1285 const StatIdent
tz = identify(
"/etc/TZ");
1286 const StatIdent timezone = identify(
"/etc/timezone");
1287 if (!m_name.isEmpty() && m_last.isValid()
1288 && (m_last == local || m_last ==
tz || m_last == timezone)) {
1292 m_name = etcLocalTime();
1293 if (!m_name.isEmpty()) {
1300 if (!m_name.isEmpty()) {
1307 m_last = m_name.isEmpty() ? StatIdent() : timezone;
1315 static constexpr unsigned long bad = ~0ul;
1316 unsigned long m_dev, m_ino;
1317 constexpr StatIdent() : m_dev(bad), m_ino(bad) {}
1318 StatIdent(
const QT_STATBUF &
data) : m_dev(
data.st_dev), m_ino(
data.st_ino) {}
1319 bool isValid() {
return m_dev != bad || m_ino != bad; }
1321 {
return other.m_dev == m_dev &&
other.m_ino == m_ino; }
1325 static StatIdent identify(
const char *
path)
1328 return QT_STAT(
path, &
data) == -1 ? StatIdent() : StatIdent(
data);
1335 const auto zoneinfo =
"/zoneinfo/"_L1;
1337 long iteration = getSymloopMax();
1346 }
while (!
path.isEmpty() && --iteration > 0);
1355 return zone.readAll().trimmed();
1361 static long getSymloopMax()
1368 long result = sysconf(_SC_SYMLOOP_MAX);
1385QByteArray QTzTimeZonePrivate::systemTimeZoneId()
const
1387 return staticSystemTimeZoneId();
1390QByteArray QTzTimeZonePrivate::staticSystemTimeZoneId()
1399 if (ianaId ==
":/etc/localtime")
1402 ianaId = ianaId.
sliced(1);
1405 Q_CONSTINIT
thread_local static ZoneNameReader
reader;
const_iterator constEnd() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing just after the last byte in the ...
const_iterator constBegin() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first byte in the byte-ar...
int toInt(bool *ok=nullptr, int base=10) const
Returns the byte array converted to an int using base base, which is ten by default.
QList< QByteArray > split(char sep) const
Splits the byte array into subarrays wherever sep occurs, and returns the list of those arrays.
iterator end()
Returns an \l{STL-style iterators}{STL-style iterator} pointing just after the last byte in the byte-...
bool startsWith(QByteArrayView bv) const
char at(qsizetype i) const
Returns the byte at index position i in the byte array.
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
QByteArray sliced(qsizetype pos) const
void clear()
Clears the contents of the byte array and makes it null.
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first byte in the byte-array.
QByteArray & append(char c)
This is an overloaded member function, provided for convenience. It differs from the above function o...
T * object(const Key &key) const noexcept
bool insert(const Key &key, T *object, qsizetype cost=1)
\inmodule QtCore\reentrant
int readRawData(char *, int len)
Reads at most len bytes from the stream into s and returns the number of bytes read.
Status status() const
Returns the status of the data stream.
\inmodule QtCore\reentrant
static QDateTime fromMSecsSinceEpoch(qint64 msecs, const QTimeZone &timeZone)
static qint64 currentMSecsSinceEpoch() noexcept
QDate date() const
Returns the date part of the datetime.
\inmodule QtCore \reentrant
constexpr bool isValid() const
Returns true if this date is valid; otherwise returns false.
int month() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
QDate addDays(qint64 days) const
Returns a QDate object containing a date ndays later than the date of this object (or earlier if nday...
int year() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
int dayOfWeek() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
static bool isLeapYear(int year)
Returns true if the specified year is a leap year in the Gregorian calendar; otherwise returns false.
The QDirIterator class provides an iterator for directory entrylists.
bool hasNext() const
Returns true if there is at least one more entry in the directory; otherwise, false is returned.
QString relativeFilePath(const QString &fileName) const
Returns the path to fileName relative to the directory.
QString absoluteFilePath(const QString &fileName) const
Returns the absolute path name of a file in the directory.
bool atEnd() const override
Returns true if the end of the file has been reached; otherwise returns false.
\inmodule QtCore \reentrant
bool isSymLink() const
Returns true if this object points to a symbolic link, shortcut, or alias; otherwise returns false.
bool isFile() const
Returns true if this object points to a file or to a symbolic link to a file.
bool isDir() const
Returns true if this object points to a directory or to a symbolic link to a directory.
QString filePath() const
Returns the file name, including the path (which may be absolute or relative).
bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
QString symLinkTarget() const
static QByteArray encodeName(const QString &fileName)
Converts fileName to an 8-bit encoding that you can use in native APIs.
void setFileName(const QString &name)
Sets the name of the file.
bool exists() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
bool contains(const Key &key) const noexcept
Returns true if the hash contains an item with the key; otherwise returns false.
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
qint64 readLine(char *data, qint64 maxlen)
This function reads a line of ASCII characters from the device, up to a maximum of maxSize - 1 bytes,...
qint64 read(char *data, qint64 maxlen)
Reads at most maxSize bytes from the device into data, and returns the number of bytes read.
qsizetype size() const noexcept
const_reference at(qsizetype i) const noexcept
void reserve(qsizetype size)
void resize(qsizetype size)
const_iterator cend() const noexcept
void append(parameter_type t)
const_iterator cbegin() const noexcept
static QLocale::Territory codeToTerritory(QStringView code) noexcept
const_iterator cend() const
const_iterator cbegin() const
const_iterator cend() const noexcept
const_iterator cbegin() const noexcept
QByteArray toUtf8() const
Returns a UTF-8 representation of the string view as a QByteArray.
constexpr QStringView sliced(qsizetype pos) const noexcept
\macro QT_RESTRICTED_CAST_FROM_ASCII
static QString fromLocal8Bit(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QString first(qsizetype n) const
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
QString sliced(qsizetype pos) const
static QString static QString qsizetype indexOf(QChar c, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
virtual QString displayName(qint64 atMSecsSinceEpoch, QTimeZone::NameType nameType, const QLocale &locale) const
QTzTimeZoneCacheEntry fetchEntry(const QByteArray &ianaId)
QMap< QString, QString > map
[6]
QSet< QString >::iterator it
const PluginKeyMapConstIterator cend
Combined button and popup list for selecting options.
Lock qt_scoped_lock(Mutex &mutex)
Lock qt_unique_lock(Mutex &mutex)
QImageReader reader("image.png")
[1]
static jboolean cut(JNIEnv *, jobject)
DBusConnection const char * rule
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
static const qint64 invalidData
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
constexpr const T & qBound(const T &min, const T &val, const T &max)
constexpr T qAbs(const T &t)
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLsizei GLenum GLenum * types
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint GLintptr offset
GLsizei const GLchar *const * path
GLenum GLenum GLenum input
static QT_BEGIN_NAMESPACE const char * typeList[]
bool operator==(const QRandomGenerator &rng1, const QRandomGenerator &rng2)
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
#define QStringLiteral(str)
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
static int parsePosixTime(const char *begin, const char *end)
static QMap< int, QByteArray > parseTzAbbreviations(QDataStream &ds, int tzh_charcnt, const QList< QTzType > &types)
static QTzTimeZoneHash loadTzTimeZones()
static int parsePosixTransitionTime(const QByteArray &timeRule)
static bool isTzFile(const QString &name)
static void parseTzLeapSeconds(QDataStream &ds, int tzh_leapcnt, bool longTran)
static QTzHeader parseTzHeader(QDataStream &ds, bool *ok)
static bool asciiIsLetter(char ch)
static QDate calculateDowDate(int year, int month, int dayOfWeek, int week)
static auto validatePosixRule(const QByteArray &posixRule, bool requireOffset=false)
static QList< QTzType > parseTzIndicators(QDataStream &ds, const QList< QTzType > &types, int tzh_ttisstdcnt, int tzh_ttisgmtcnt)
static QDate calculatePosixDate(const QByteArray &dateRule, int year)
static QList< QTzType > parseTzTypes(QDataStream &ds, int tzh_typecnt)
static QList< QTimeZonePrivate::Data > calculatePosixTransitions(const QByteArray &posixRule, int startYear, int endYear, qint64 lastTranMSecs)
QHash< QByteArray, QTzTimeZone > QTzTimeZoneHash
static int parsePosixOffset(const char *begin, const char *end)
static QList< QTzTransition > parseTzTransitions(QDataStream &ds, int tzh_timecnt, bool longTran)
static QByteArray parseTzPosixRule(QDataStream &ds)
#define Q_DECLARE_TYPEINFO(TYPE, FLAGS)
QFileInfo info(fileName)
[8]
qsizetype indexOf(const AT &t, qsizetype from=0) const noexcept
QLocale::Territory territory