qtimezoneprivate_tz.cpp

Absolute File Name:/home/qt/qt5_coco/qt5/qtbase/src/corelib/tools/qtimezoneprivate_tz.cpp
Source codeSwitch to Preprocessed file
LineSourceCount
1/****************************************************************************-
2**-
3** Copyright (C) 2013 John Layt <jlayt@kde.org>-
4** Contact: https://www.qt.io/licensing/-
5**-
6** This file is part of the QtCore module of the Qt Toolkit.-
7**-
8** $QT_BEGIN_LICENSE:LGPL$-
9** Commercial License Usage-
10** Licensees holding valid commercial Qt licenses may use this file in-
11** accordance with the commercial license agreement provided with the-
12** Software or, alternatively, in accordance with the terms contained in-
13** a written agreement between you and The Qt Company. For licensing terms-
14** and conditions see https://www.qt.io/terms-conditions. For further-
15** information use the contact form at https://www.qt.io/contact-us.-
16**-
17** GNU Lesser General Public License Usage-
18** Alternatively, this file may be used under the terms of the GNU Lesser-
19** General Public License version 3 as published by the Free Software-
20** Foundation and appearing in the file LICENSE.LGPL3 included in the-
21** packaging of this file. Please review the following information to-
22** ensure the GNU Lesser General Public License version 3 requirements-
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.-
24**-
25** GNU General Public License Usage-
26** Alternatively, this file may be used under the terms of the GNU-
27** General Public License version 2.0 or (at your option) the GNU General-
28** Public license version 3 or any later version approved by the KDE Free-
29** Qt Foundation. The licenses are as published by the Free Software-
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3-
31** included in the packaging of this file. Please review the following-
32** information to ensure the GNU General Public License requirements will-
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and-
34** https://www.gnu.org/licenses/gpl-3.0.html.-
35**-
36** $QT_END_LICENSE$-
37**-
38****************************************************************************/-
39-
40#include "qtimezone.h"-
41#include "qtimezoneprivate_p.h"-
42-
43#include <QtCore/QFile>-
44#include <QtCore/QHash>-
45#include <QtCore/QDataStream>-
46#include <QtCore/QDateTime>-
47-
48#include <qdebug.h>-
49-
50#include "qlocale_tools_p.h"-
51-
52#include <algorithm>-
53-
54QT_BEGIN_NAMESPACE-
55-
56/*-
57 Private-
58-
59 tz file implementation-
60*/-
61-
62struct QTzTimeZone {-
63 QLocale::Country country;-
64 QByteArray comment;-
65};-
66-
67// Define as a type as Q_GLOBAL_STATIC doesn't like it-
68typedef QHash<QByteArray, QTzTimeZone> QTzTimeZoneHash;-
69-
70// Parse zone.tab table, assume lists all installed zones, if not will need to read directories-
71static QTzTimeZoneHash loadTzTimeZones()-
72{-
73 QString path = QStringLiteral("/usr/share/zoneinfo/zone.tab");-
74 if (!QFile::exists(path))
!QFile::exists(path)Description
TRUEnever evaluated
FALSEevaluated 1 time by 1 test
Evaluated by:
  • tst_QTimeZone
0-1
75 path = QStringLiteral("/usr/lib/zoneinfo/zone.tab");
never executed: path = ([]() -> QString { enum { Size = sizeof(u"" "/usr/lib/zoneinfo/zone.tab")/2 - 1 }; static const QStaticStringData<Size> qstring_literal = { { { { -1 } }, Size, 0, 0, sizeof(QStringData) }, u"" "/usr/lib/zoneinfo/zone.tab" }; QStringDataPtr holder = { qstring_literal.data_ptr() }; const QString qstring_literal_temp(holder); return qstring_literal_temp; }());
never executed: return qstring_literal_temp;
0
76-
77 QFile tzif(path);-
78 if (!tzif.open(QIODevice::ReadOnly))
!tzif.open(QIO...ice::ReadOnly)Description
TRUEnever evaluated
FALSEevaluated 1 time by 1 test
Evaluated by:
  • tst_QTimeZone
0-1
79 return QTzTimeZoneHash();
never executed: return QTzTimeZoneHash();
0
80-
81 QTzTimeZoneHash zonesHash;-
82 // TODO QTextStream inefficient, replace later-
83 QTextStream ts(&tzif);-
84 while (!ts.atEnd()) {
!ts.atEnd()Description
TRUEevaluated 445 times by 1 test
Evaluated by:
  • tst_QTimeZone
FALSEevaluated 1 time by 1 test
Evaluated by:
  • tst_QTimeZone
1-445
85 const QString line = ts.readLine();-
86 // Comment lines are prefixed with a #-
87 if (!line.isEmpty() && line.at(0) != '#') {
!line.isEmpty()Description
TRUEevaluated 445 times by 1 test
Evaluated by:
  • tst_QTimeZone
FALSEnever evaluated
line.at(0) != '#'Description
TRUEevaluated 421 times by 1 test
Evaluated by:
  • tst_QTimeZone
FALSEevaluated 24 times by 1 test
Evaluated by:
  • tst_QTimeZone
0-445
88 // Data rows are tab-separated columns Region, Coordinates, ID, Optional Comments-
89 const QStringListauto parts = line.splitsplitRef(QLatin1Char('\t');));-
90 QTzTimeZone zone;-
91 zone.country = QLocalePrivate::codeToCountry(parts.at(0));-
92 if (parts.size() > 3)
parts.size() > 3Description
TRUEevaluated 204 times by 1 test
Evaluated by:
  • tst_QTimeZone
FALSEevaluated 217 times by 1 test
Evaluated by:
  • tst_QTimeZone
204-217
93 zone.comment = parts.at(3).toUtf8();
executed 204 times by 1 test: zone.comment = parts.at(3).toUtf8();
Executed by:
  • tst_QTimeZone
204
94 zonesHash.insert(parts.at(2).toUtf8(), zone);-
95 }
executed 421 times by 1 test: end of block
Executed by:
  • tst_QTimeZone
421
96 }
executed 445 times by 1 test: end of block
Executed by:
  • tst_QTimeZone
445
97 return zonesHash;
executed 1 time by 1 test: return zonesHash;
Executed by:
  • tst_QTimeZone
1
98}-
99-
100// Hash of available system tz files as loaded by loadTzTimeZones()-
101Q_GLOBAL_STATIC_WITH_ARGS(const QTzTimeZoneHash, tzZones, (loadTzTimeZones()));-
102-
103/*-
104 The following is copied and modified from tzfile.h which is in the public domain.-
105 Copied as no compatibility guarantee and is never system installed.-
106 See https://github.com/eggert/tz/blob/master/tzfile.h-
107*/-
108-
109#define TZ_MAGIC "TZif"-
110#define TZ_MAX_TIMES 1200-
111#define TZ_MAX_TYPES 256 // Limited by what (unsigned char)'s can hold-
112#define TZ_MAX_CHARS 50 // Maximum number of abbreviation characters-
113#define TZ_MAX_LEAPS 50 // Maximum number of leap second corrections-
114-
115struct QTzHeader {-
116 char tzh_magic[4]; // TZ_MAGIC-
117 char tzh_version; // '\0' or '2' as of 2005-
118 char tzh_reserved[15]; // reserved--must be zero-
119 quint32 tzh_ttisgmtcnt; // number of trans. time flags-
120 quint32 tzh_ttisstdcnt; // number of trans. time flags-
121 quint32 tzh_leapcnt; // number of leap seconds-
122 quint32 tzh_timecnt; // number of transition times-
123 quint32 tzh_typecnt; // number of local time types-
124 quint32 tzh_charcnt; // number of abbr. chars-
125};-
126-
127struct QTzTransition {-
128 qint64 tz_time; // Transition time-
129 quint8 tz_typeind; // Type Index-
130};-
131Q_DECLARE_TYPEINFO(QTzTransition, Q_PRIMITIVE_TYPE);-
132-
133struct QTzType {-
134 int tz_gmtoff; // UTC offset in seconds-
135 bool tz_isdst; // Is DST-
136 quint8 tz_abbrind; // abbreviation list index-
137 bool tz_ttisgmt; // Is in UTC time-
138 bool tz_ttisstd; // Is in Standard time-
139};-
140Q_DECLARE_TYPEINFO(QTzType, Q_PRIMITIVE_TYPE);-
141-
142-
143// TZ File parsing-
144-
145static QTzHeader parseTzHeader(QDataStream &ds, bool *ok)-
146{-
147 QTzHeader hdr;-
148 quint8 ch;-
149 *ok = false;-
150-
151 // Parse Magic, 4 bytes-
152 ds.readRawData(hdr.tzh_magic, 4);-
153-
154 if (memcmp(hdr.tzh_magic, TZ_MAGIC, 4) != 0 || ds.status() != QDataStream::Ok)-
155 return hdr;-
156-
157 // Parse Version, 1 byte, before 2005 was '\0', since 2005 a '2', since 2013 a '3'-
158 ds >> ch;-
159 hdr.tzh_version = ch;-
160 if (ds.status() != QDataStream::Ok-
161 || (hdr.tzh_version != '2' && hdr.tzh_version != '\0' && hdr.tzh_version != '3')) {-
162 return hdr;-
163 }-
164-
165 // Parse reserved space, 15 bytes-
166 ds.readRawData(hdr.tzh_reserved, 15);-
167 if (ds.status() != QDataStream::Ok)-
168 return hdr;-
169-
170 // Parse rest of header, 6 x 4-byte transition counts-
171 ds >> hdr.tzh_ttisgmtcnt >> hdr.tzh_ttisstdcnt >> hdr.tzh_leapcnt >> hdr.tzh_timecnt-
172 >> hdr.tzh_typecnt >> hdr.tzh_charcnt;-
173-
174 // Check defined maximums-
175 if (ds.status() != QDataStream::Ok-
176 || hdr.tzh_timecnt > TZ_MAX_TIMES-
177 || hdr.tzh_typecnt > TZ_MAX_TYPES-
178 || hdr.tzh_charcnt > TZ_MAX_CHARS-
179 || hdr.tzh_leapcnt > TZ_MAX_LEAPS-
180 || hdr.tzh_ttisgmtcnt > hdr.tzh_typecnt-
181 || hdr.tzh_ttisstdcnt > hdr.tzh_typecnt) {-
182 return hdr;-
183 }-
184-
185 *ok = true;-
186 return hdr;-
187}-
188-
189static QVector<QTzTransition> parseTzTransitions(QDataStream &ds, int tzh_timecnt, bool longTran)-
190{-
191 QVector<QTzTransition> transitions(tzh_timecnt);-
192-
193 if (longTran) {-
194 // Parse tzh_timecnt x 8-byte transition times-
195 for (int i = 0; i < tzh_timecnt && ds.status() == QDataStream::Ok; ++i) {-
196 ds >> transitions[i].tz_time;-
197 if (ds.status() != QDataStream::Ok)-
198 transitions.resize(i);-
199 }-
200 } else {-
201 // Parse tzh_timecnt x 4-byte transition times-
202 int val;-
203 for (int i = 0; i < tzh_timecnt && ds.status() == QDataStream::Ok; ++i) {-
204 ds >> val;-
205 transitions[i].tz_time = val;-
206 if (ds.status() != QDataStream::Ok)-
207 transitions.resize(i);-
208 }-
209 }-
210-
211 // Parse tzh_timecnt x 1-byte transition type index-
212 for (int i = 0; i < tzh_timecnt && ds.status() == QDataStream::Ok; ++i) {-
213 quint8 typeind;-
214 ds >> typeind;-
215 if (ds.status() == QDataStream::Ok)-
216 transitions[i].tz_typeind = typeind;-
217 }-
218-
219 return transitions;-
220}-
221-
222static QVector<QTzType> parseTzTypes(QDataStream &ds, int tzh_typecnt)-
223{-
224 QVector<QTzType> types(tzh_typecnt);-
225-
226 // Parse tzh_typecnt x transition types-
227 for (int i = 0; i < tzh_typecnt && ds.status() == QDataStream::Ok; ++i) {-
228 QTzType &type = types[i];-
229 // Parse UTC Offset, 4 bytes-
230 ds >> type.tz_gmtoff;-
231 // Parse Is DST flag, 1 byte-
232 if (ds.status() == QDataStream::Ok)-
233 ds >> type.tz_isdst;-
234 // Parse Abbreviation Array Index, 1 byte-
235 if (ds.status() == QDataStream::Ok)-
236 ds >> type.tz_abbrind;-
237 // Set defaults in case not populated later-
238 type.tz_ttisgmt = false;-
239 type.tz_ttisstd = false;-
240 if (ds.status() != QDataStream::Ok)-
241 types.resize(i);-
242 }-
243-
244 return types;-
245}-
246-
247static QMap<int, QByteArray> parseTzAbbreviations(QDataStream &ds, int tzh_charcnt, const QVector<QTzType> &types)-
248{-
249 // Parse the abbreviation list which is tzh_charcnt long with '\0' separated strings. The-
250 // QTzType.tz_abbrind index points to the first char of the abbreviation in the array, not the-
251 // occurrence in the list. It can also point to a partial string so we need to use the actual typeList-
252 // index values when parsing. By using a map with tz_abbrind as ordered key we get both index-
253 // methods in one data structure and can convert the types afterwards.-
254 QMap<int, QByteArray> map;-
255 quint8 ch;-
256 QByteArray input;-
257 // First parse the full abbrev string-
258 for (int i = 0; i < tzh_charcnt && ds.status() == QDataStream::Ok; ++i) {
i < tzh_charcntDescription
TRUEevaluated 14643 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
FALSEevaluated 908 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
ds.status() == QDataStream::OkDescription
TRUEevaluated 14643 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
FALSEnever evaluated
0-14643
259 ds >> ch;-
260 if (ds.status() == QDataStream::Ok)
ds.status() == QDataStream::OkDescription
TRUEevaluated 14643 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
FALSEnever evaluated
0-14643
261 input.append(char(ch));
executed 14643 times by 2 tests: input.append(char(ch));
Executed by:
  • tst_QDateTime
  • tst_QTimeZone
14643
262 else-
263 return map;
never executed: return map;
0
264 }-
265 // Then extract all the substrings pointed to by types-
266 foreachfor (const QTzType &type ,: types) {-
267 QByteArray abbrev;-
268 for (int i = type.tz_abbrind; input.at(i) != '\0'; ++i)
input.at(i) != '\0'Description
TRUEevaluated 17454 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
FALSEevaluated 5130 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
5130-17454
269 abbrev.append(input.at(i));
executed 17454 times by 2 tests: abbrev.append(input.at(i));
Executed by:
  • tst_QDateTime
  • tst_QTimeZone
17454
270 // Have reached end of an abbreviation, so add to map-
271 map[type.tz_abbrind] = abbrev;-
272 }
executed 5130 times by 2 tests: end of block
Executed by:
  • tst_QDateTime
  • tst_QTimeZone
5130
273 return map;
executed 908 times by 2 tests: return map;
Executed by:
  • tst_QDateTime
  • tst_QTimeZone
908
274}-
275-
276static void parseTzLeapSeconds(QDataStream &ds, int tzh_leapcnt, bool longTran)-
277{-
278 // Parse tzh_leapcnt x pairs of leap seconds-
279 // We don't use leap seconds, so only read and don't store-
280 qint64 val;-
281 if (longTran) {-
282 qint64 time;-
283 for (int i = 0; i < tzh_leapcnt && ds.status() == QDataStream::Ok; ++i) {-
284 // Parse Leap Occurrence Time, 8 bytes-
285 ds >> time;-
286 // Parse Leap Seconds To Apply, 4 bytes-
287 if (ds.status() == QDataStream::Ok)-
288 ds >> val;-
289 }-
290 } else {-
291 for (int i = 0; i < tzh_leapcnt && ds.status() == QDataStream::Ok; ++i) {-
292 // Parse Leap Occurrence Time, 4 bytes-
293 ds >> val;-
294 // Parse Leap Seconds To Apply, 4 bytes-
295 if (ds.status() == QDataStream::Ok)-
296 ds >> val;-
297 }-
298 }-
299}-
300-
301static QVector<QTzType> parseTzIndicators(QDataStream &ds, const QVector<QTzType> &types, int tzh_ttisstdcnt, int tzh_ttisgmtcnt)-
302{-
303 QVector<QTzType> result = types;-
304 bool temp;-
305-
306 // Parse tzh_ttisstdcnt x 1-byte standard/wall indicators-
307 for (int i = 0; i < tzh_ttisstdcnt && ds.status() == QDataStream::Ok; ++i) {-
308 ds >> temp;-
309 if (ds.status() == QDataStream::Ok)-
310 result[i].tz_ttisstd = temp;-
311 }-
312-
313 // Parse tzh_ttisgmtcnt x 1-byte UTC/local indicators-
314 for (int i = 0; i < tzh_ttisgmtcnt && ds.status() == QDataStream::Ok; ++i) {-
315 ds >> temp;-
316 if (ds.status() == QDataStream::Ok)-
317 result[i].tz_ttisgmt = temp;-
318 }-
319-
320 return result;-
321}-
322-
323static QByteArray parseTzPosixRule(QDataStream &ds)-
324{-
325 // Parse POSIX rule, variable length '\n' enclosed-
326 QByteArray rule;-
327-
328 quint8 ch;-
329 ds >> ch;-
330 if (ch != '\n' || ds.status() != QDataStream::Ok)-
331 return rule;-
332 ds >> ch;-
333 while (ch != '\n' && ds.status() == QDataStream::Ok) {-
334 rule.append((char)ch);-
335 ds >> ch;-
336 }-
337-
338 return rule;-
339}-
340-
341static QDate calculateDowDate(int year, int month, int dayOfWeek, int week)-
342{-
343 QDate date(year, month, 1);-
344 int startDow = date.dayOfWeek();-
345 if (startDow <= dayOfWeek)-
346 date = date.addDays(dayOfWeek - startDow - 7);-
347 else-
348 date = date.addDays(dayOfWeek - startDow);-
349 date = date.addDays(week * 7);-
350 while (date.month() != month)-
351 date = date.addDays(-7);-
352 return date;-
353}-
354-
355static QDate calculatePosixDate(const QByteArray &dateRule, int year)-
356{-
357 // Can start with M, J, or a digit-
358 if (dateRule.at(0) == 'M') {-
359 // nth week in month format "Mmonth.week.dow"-
360 QList<QByteArray> dateParts = dateRule.split('.');-
361 int month = dateParts.at(0).mid(1).toInt();-
362 int week = dateParts.at(1).toInt();-
363 int dow = dateParts.at(2).toInt();-
364 if (dow == 0)-
365 ++dow;-
366 return calculateDowDate(year, month, dow, week);-
367 } else if (dateRule.at(0) == 'J') {-
368 // Day of Year ignores Feb 29-
369 int doy = dateRule.mid(1).toInt();-
370 QDate date = QDate(year, 1, 1).addDays(doy - 1);-
371 if (QDate::isLeapYear(date.year()))-
372 date = date.addDays(-1);-
373 return date;-
374 } else {-
375 // Day of Year includes Feb 29-
376 int doy = dateRule.toInt();-
377 return QDate(year, 1, 1).addDays(doy - 1);-
378 }-
379}-
380-
381// returns the time in seconds, INT_MIN if we failed to parse-
382static int parsePosixTime(const char *begin, const char *end)-
383{-
384 // Format "hh[:mm[:ss]]"-
385 int hour, min = 0, sec = 0;-
386-
387 // Note that the calls to qstrtoll do *not* check the end pointer, which-
388 // means they proceed until they find a non-digit. We check that we're-
389 // still in range at the end, but we may have read from past end. It's the-
390 // caller's responsibility to ensure that begin is part of a-
391 // null-terminated string.-
392-
393 bool ok = false;-
394 hour = qstrtoll(begin, &begin, 10, &ok);-
395 if (!ok || hour < 0)-
396 return INT_MIN;-
397 if (begin < end && *begin == ':') {-
398 // minutes-
399 ++begin;-
400 min = qstrtoll(begin, &begin, 10, &ok);-
401 if (!ok || min < 0)-
402 return INT_MIN;-
403-
404 if (begin < end && *begin == ':') {-
405 // seconds-
406 ++begin;-
407 sec = qstrtoll(begin, &begin, 10, &ok);-
408 if (!ok || sec < 0)-
409 return INT_MIN;-
410 }-
411 }-
412-
413 // we must have consumed everything-
414 if (begin != end)-
415 return INT_MIN;-
416-
417 return (hour * 60 + min) * 60 + sec;-
418}-
419-
420static QTime parsePosixTransitionTime(const QByteArray &timeRule)-
421{-
422 // Format "hh[:mm[:ss]]"-
423 int value = parsePosixTime(timeRule.constBegin(), timeRule.constEnd());-
424 if (value == INT_MIN) {-
425 // if we failed to parse, return 02:00-
426 return QTime(2, 0, 0);-
427 }-
428 return QTime::fromMSecsSinceStartOfDay(value * 1000);-
429}-
430-
431static int parsePosixOffset(const char *begin, const char *end)-
432{-
433 // Format "[+|-]hh[:mm[:ss]]"-
434 // note that the sign is inverted because POSIX counts in hours West of GMT-
435 bool negate = true;-
436 if (*begin == '+') {-
437 ++begin;-
438 } else if (*begin == '-') {-
439 negate = false;-
440 ++begin;-
441 }-
442-
443 int value = parsePosixTime(begin, end);-
444 if (value == INT_MIN)-
445 return value;-
446 return negate ? -value : value;-
447}-
448-
449static inline bool asciiIsLetter(char ch)-
450{-
451 ch |= 0x20; // lowercases if it is a letter, otherwise just corrupts ch-
452 return ch >= 'a' && ch <= 'z';-
453}-
454-
455// Returns the zone name, the offset (in seconds) and advances \a begin to-
456// where the parsing ended. Returns a zone of INT_MIN in case an offset-
457// couldn't be read.-
458static QPair<QString, int> parsePosixZoneNameAndOffset(const char *&pos, const char *end)-
459{-
460 static const char offsetChars[] = "0123456789:";-
461 QPair<QString, int> result = qMakePair(QString(), INT_MIN);-
462-
463 const char *nameBegin = pos;-
464 const char *nameEnd;-
465 Q_ASSERT(pos < end);-
466-
467 if (*pos == '<') {-
468 nameBegin = pos + 1; // skip the '<'-
469 nameEnd = nameBegin;-
470 while (nameEnd < end && *nameEnd != '>') {-
471 // POSIX says only alphanumeric, but we allow anything-
472 ++nameEnd;-
473 }-
474 pos = nameEnd + 1; // skip the '>'-
475 } else {-
476 nameBegin = pos;-
477 nameEnd = nameBegin;-
478 while (nameEnd < end && asciiIsLetter(*nameEnd))-
479 ++nameEnd;-
480 pos = nameEnd;-
481 }-
482 if (nameEnd - nameBegin < 3)-
483 return result; // name must be at least 3 characters long-
484-
485 // zone offset, form [+-]hh:mm:ss-
486 const char *zoneBegin = pos;-
487 const char *zoneEnd = pos;-
488 if (zoneEnd < end && (zoneEnd[0] == '+' || zoneEnd[0] == '-'))-
489 ++zoneEnd;-
490 while (zoneEnd < end) {-
491 if (strchr(offsetChars, char(*zoneEnd)) == NULL)-
492 break;-
493 ++zoneEnd;-
494 }-
495-
496 result.first = QString::fromUtf8(nameBegin, nameEnd - nameBegin);-
497 if (zoneEnd > zoneBegin)-
498 result.second = parsePosixOffset(zoneBegin, zoneEnd);-
499 pos = zoneEnd;-
500 return result;-
501}-
502-
503static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArray &posixRule,-
504 int startYear, int endYear,-
505 int lastTranMSecs)-
506{-
507 QVector<QTimeZonePrivate::Data> result;-
508-
509 // Limit year by qint64 max size for msecs-
510 if (startYear > 292278994)-
511 startYear = 292278994;-
512 if (endYear > 292278994)-
513 endYear = 292278994;-
514-
515 // POSIX Format is like "TZ=CST6CDT,M3.2.0/2:00:00,M11.1.0/2:00:00"-
516 // i.e. "std offset dst [offset],start[/time],end[/time]"-
517 // See the section about TZ at http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html-
518 QList<QByteArray> parts = posixRule.split(',');-
519-
520 QPair<QString, int> stdZone, dstZone;-
521 {-
522 const QByteArray &zoneinfo = parts.at(0);-
523 const char *begin = zoneinfo.constBegin();-
524-
525 stdZone = parsePosixZoneNameAndOffset(begin, zoneinfo.constEnd());-
526 if (stdZone.second == INT_MIN) {-
527 stdZone.second = 0; // reset to UTC if we failed to parse-
528 } else if (begin < zoneinfo.constEnd()) {-
529 dstZone = parsePosixZoneNameAndOffset(begin, zoneinfo.constEnd());-
530 if (dstZone.second == INT_MIN) {-
531 // if the dst offset isn't provided, it is 1 hour ahead of the standard offset-
532 dstZone.second = stdZone.second + (60 * 60);-
533 }-
534 }-
535 }-
536-
537 // If only the name part then no transitions-
538 if (parts.count() == 1) {-
539 QTimeZonePrivate::Data data;-
540 data.atMSecsSinceEpoch = lastTranMSecs;-
541 data.offsetFromUtc = stdZone.second;-
542 data.standardTimeOffset = stdZone.second;-
543 data.daylightTimeOffset = 0;-
544 data.abbreviation = stdZone.first;-
545 result << data;-
546 return result;-
547 }-
548-
549-
550 // Get the std to dst transtion details-
551 QList<QByteArray> dstParts = parts.at(1).split('/');-
552 QByteArray dstDateRule = dstParts.at(0);-
553 QTime dstTime;-
554 if (dstParts.count() > 1)-
555 dstTime = parsePosixTransitionTime(dstParts.at(1));-
556 else-
557 dstTime = QTime(2, 0, 0);-
558-
559 // Get the dst to std transtion details-
560 QList<QByteArray> stdParts = parts.at(2).split('/');-
561 QByteArray stdDateRule = stdParts.at(0);-
562 QTime stdTime;-
563 if (stdParts.count() > 1)-
564 stdTime = parsePosixTransitionTime(stdParts.at(1));-
565 else-
566 stdTime = QTime(2, 0, 0);-
567-
568 for (int year = startYear; year <= endYear; ++year) {-
569 QTimeZonePrivate::Data dstData;-
570 QDateTime dst(calculatePosixDate(dstDateRule, year), dstTime, Qt::UTC);-
571 dstData.atMSecsSinceEpoch = dst.toMSecsSinceEpoch() - (stdZone.second * 1000);-
572 dstData.offsetFromUtc = dstZone.second;-
573 dstData.standardTimeOffset = stdZone.second;-
574 dstData.daylightTimeOffset = dstZone.second - stdZone.second;-
575 dstData.abbreviation = dstZone.first;-
576 QTimeZonePrivate::Data stdData;-
577 QDateTime std(calculatePosixDate(stdDateRule, year), stdTime, Qt::UTC);-
578 stdData.atMSecsSinceEpoch = std.toMSecsSinceEpoch() - (dstZone.second * 1000);-
579 stdData.offsetFromUtc = stdZone.second;-
580 stdData.standardTimeOffset = stdZone.second;-
581 stdData.daylightTimeOffset = 0;-
582 stdData.abbreviation = stdZone.first;-
583 // Part of the high year will overflow-
584 if (year == 292278994 && (dstData.atMSecsSinceEpoch < 0 || stdData.atMSecsSinceEpoch < 0)) {-
585 if (dstData.atMSecsSinceEpoch > 0) {-
586 result << dstData;-
587 } else if (stdData.atMSecsSinceEpoch > 0) {-
588 result << stdData;-
589 }-
590 } else if (dst < std) {-
591 result << dstData << stdData;-
592 } else {-
593 result << stdData << dstData;-
594 }-
595 }-
596 return result;-
597}-
598-
599// Create the system default time zone-
600QTzTimeZonePrivate::QTzTimeZonePrivate()-
601#ifdef QT_USE_ICU-
602 : m_icu(0)-
603#endif // QT_USE_ICU-
604{-
605 init(systemTimeZoneId());-
606}-
607-
608// Create a named time zone-
609QTzTimeZonePrivate::QTzTimeZonePrivate(const QByteArray &ianaId)-
610#ifdef QT_USE_ICU-
611 : m_icu(0)-
612#endif // QT_USE_ICU-
613{-
614 init(ianaId);-
615}-
616-
617QTzTimeZonePrivate::QTzTimeZonePrivate(const QTzTimeZonePrivate &other)-
618 : QTimeZonePrivate(other), m_tranTimes(other.m_tranTimes),-
619 m_tranRules(other.m_tranRules), m_abbreviations(other.m_abbreviations),-
620#ifdef QT_USE_ICU-
621 m_icu(other.m_icu),-
622#endif // QT_USE_ICU-
623 m_posixRule(other.m_posixRule)-
624{-
625}-
626-
627QTzTimeZonePrivate::~QTzTimeZonePrivate()-
628{-
629}-
630-
631QTimeZonePrivate *QTzTimeZonePrivate::clone()-
632{-
633 return new QTzTimeZonePrivate(*this);-
634}-
635-
636void QTzTimeZonePrivate::init(const QByteArray &ianaId)-
637{-
638 QFile tzif;-
639 if (ianaId.isEmpty()) {
ianaId.isEmpty()Description
TRUEnever evaluated
FALSEevaluated 457 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
0-457
640 // Open system tz-
641 tzif.setFileName(QStringLiteral("/etc/localtime"));-
642 if (!tzif.open(QIODevice::ReadOnly))
!tzif.open(QIO...ice::ReadOnly)Description
TRUEnever evaluated
FALSEnever evaluated
0
643 return;
never executed: return;
0
644 } else {
never executed: end of block
0
645 // Open named tz, try modern path first, if fails try legacy path-
646 tzif.setFileName(QLatin1String("/usr/share/zoneinfo/") + QString::fromLocal8Bit(ianaId));-
647 if (!tzif.open(QIODevice::ReadOnly)) {
!tzif.open(QIO...ice::ReadOnly)Description
TRUEevaluated 3 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
FALSEevaluated 454 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
3-454
648 tzif.setFileName(QLatin1String("/usr/lib/zoneinfo/") + QString::fromLocal8Bit(ianaId));-
649 if (!tzif.open(QIODevice::ReadOnly))
!tzif.open(QIO...ice::ReadOnly)Description
TRUEevaluated 3 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
FALSEnever evaluated
0-3
650 return;
executed 3 times by 2 tests: return;
Executed by:
  • tst_QDateTime
  • tst_QTimeZone
3
651 }
never executed: end of block
0
652 }
executed 454 times by 2 tests: end of block
Executed by:
  • tst_QDateTime
  • tst_QTimeZone
454
653-
654 QDataStream ds(&tzif);-
655-
656 // Parse the old version block of data-
657 bool ok = false;-
658 QTzHeader hdr = parseTzHeader(ds, &ok);-
659 if (!ok || ds.status() != QDataStream::Ok)
!okDescription
TRUEnever evaluated
FALSEevaluated 454 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
ds.status() != QDataStream::OkDescription
TRUEnever evaluated
FALSEevaluated 454 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
0-454
660 return;
never executed: return;
0
661 QVector<QTzTransition> tranList = parseTzTransitions(ds, hdr.tzh_timecnt, false);-
662 if (ds.status() != QDataStream::Ok)
ds.status() != QDataStream::OkDescription
TRUEnever evaluated
FALSEevaluated 454 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
0-454
663 return;
never executed: return;
0
664 QVector<QTzType> typeList = parseTzTypes(ds, hdr.tzh_typecnt);-
665 if (ds.status() != QDataStream::Ok)
ds.status() != QDataStream::OkDescription
TRUEnever evaluated
FALSEevaluated 454 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
0-454
666 return;
never executed: return;
0
667 QMap<int, QByteArray> abbrevMap = parseTzAbbreviations(ds, hdr.tzh_charcnt, typeList);-
668 if (ds.status() != QDataStream::Ok)
ds.status() != QDataStream::OkDescription
TRUEnever evaluated
FALSEevaluated 454 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
0-454
669 return;
never executed: return;
0
670 parseTzLeapSeconds(ds, hdr.tzh_leapcnt, false);-
671 if (ds.status() != QDataStream::Ok)
ds.status() != QDataStream::OkDescription
TRUEnever evaluated
FALSEevaluated 454 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
0-454
672 return;
never executed: return;
0
673 typeList = parseTzIndicators(ds, typeList, hdr.tzh_ttisstdcnt, hdr.tzh_ttisgmtcnt);-
674 if (ds.status() != QDataStream::Ok)
ds.status() != QDataStream::OkDescription
TRUEnever evaluated
FALSEevaluated 454 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
0-454
675 return;
never executed: return;
0
676-
677 // If version 2 then parse the second block of data-
678 if (hdr.tzh_version == '2' || hdr.tzh_version == '3') {
hdr.tzh_version == '2'Description
TRUEevaluated 447 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
FALSEevaluated 7 times by 1 test
Evaluated by:
  • tst_QTimeZone
hdr.tzh_version == '3'Description
TRUEevaluated 7 times by 1 test
Evaluated by:
  • tst_QTimeZone
FALSEnever evaluated
0-447
679 ok = false;-
680 QTzHeader hdr2 = parseTzHeader(ds, &ok);-
681 if (!ok || ds.status() != QDataStream::Ok)
!okDescription
TRUEnever evaluated
FALSEevaluated 454 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
ds.status() != QDataStream::OkDescription
TRUEnever evaluated
FALSEevaluated 454 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
0-454
682 return;
never executed: return;
0
683 tranList = parseTzTransitions(ds, hdr2.tzh_timecnt, true);-
684 if (ds.status() != QDataStream::Ok)
ds.status() != QDataStream::OkDescription
TRUEnever evaluated
FALSEevaluated 454 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
0-454
685 return;
never executed: return;
0
686 typeList = parseTzTypes(ds, hdr2.tzh_typecnt);-
687 if (ds.status() != QDataStream::Ok)
ds.status() != QDataStream::OkDescription
TRUEnever evaluated
FALSEevaluated 454 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
0-454
688 return;
never executed: return;
0
689 abbrevMap = parseTzAbbreviations(ds, hdr2.tzh_charcnt, typeList);-
690 if (ds.status() != QDataStream::Ok)
ds.status() != QDataStream::OkDescription
TRUEnever evaluated
FALSEevaluated 454 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
0-454
691 return;
never executed: return;
0
692 parseTzLeapSeconds(ds, hdr2.tzh_leapcnt, true);-
693 if (ds.status() != QDataStream::Ok)
ds.status() != QDataStream::OkDescription
TRUEnever evaluated
FALSEevaluated 454 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
0-454
694 return;
never executed: return;
0
695 typeList = parseTzIndicators(ds, typeList, hdr2.tzh_ttisstdcnt, hdr2.tzh_ttisgmtcnt);-
696 if (ds.status() != QDataStream::Ok)
ds.status() != QDataStream::OkDescription
TRUEnever evaluated
FALSEevaluated 454 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
0-454
697 return;
never executed: return;
0
698 m_posixRule = parseTzPosixRule(ds);-
699 if (ds.status() != QDataStream::Ok)
ds.status() != QDataStream::OkDescription
TRUEnever evaluated
FALSEevaluated 454 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
0-454
700 return;
never executed: return;
0
701 }
executed 454 times by 2 tests: end of block
Executed by:
  • tst_QDateTime
  • tst_QTimeZone
454
702-
703 // Translate the TZ file into internal format-
704-
705 // Translate the array index based tz_abbrind into list index-
706 m_abbreviationsconst int size = abbrevMap.valuessize();-
707 QListm_abbreviations.clear();-
708 m_abbreviations.reserve(size);-
709 QVector<int> abbrindList;-
710 abbrindList.reserve(size);-
711 for (auto it
it != endDescription
TRUEevaluated 1827 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
FALSEevaluated 454 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
= abbrevMap.keyscbegin(), end = abbrevMap.cend(); it != end; ++it) {
it != endDescription
TRUEevaluated 1827 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
FALSEevaluated 454 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
454-1827
712 m_abbreviations.append(it.value());-
713 abbrindList.append(it.key());-
714 }
executed 1827 times by 2 tests: end of block
Executed by:
  • tst_QDateTime
  • tst_QTimeZone
1827
715 for (int i = 0; i < typeList.size(); ++i)
i < typeList.size()Description
TRUEevaluated 2700 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
FALSEevaluated 454 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
454-2700
716 typeList[i].tz_abbrind = abbrindList.indexOf(typeList.at(i).tz_abbrind);
executed 2700 times by 2 tests: typeList[i].tz_abbrind = abbrindList.indexOf(typeList.at(i).tz_abbrind);
Executed by:
  • tst_QDateTime
  • tst_QTimeZone
2700
717-
718 // Offsets are stored as total offset, want to know separate UTC and DST offsets-
719 // so find the first non-dst transition to use as base UTC Offset-
720 int utcOffset = 0;-
721 foreachfor (const QTzTransition &tran ,: qAsConst(tranList))) {-
722 if (!typeList.at(tran.tz_typeind).tz_isdst) {
!typeList.at(t...eind).tz_isdstDescription
TRUEevaluated 454 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
FALSEevaluated 3 times by 1 test
Evaluated by:
  • tst_QTimeZone
3-454
723 utcOffset = typeList.at(tran.tz_typeind).tz_gmtoff;-
724 break;
executed 454 times by 2 tests: break;
Executed by:
  • tst_QDateTime
  • tst_QTimeZone
454
725 }-
726 }
executed 3 times by 1 test: end of block
Executed by:
  • tst_QTimeZone
3
727-
728 // Now for each transition time calculate our rule and save them-
729 m_tranTimes.reserve(tranList.count());-
730 foreachfor (const QTzTransition &tz_tran ,: qAsConst(tranList))) {-
731 QTzTransitionTime tran;-
732 QTzTransitionRule rule;-
733 const QTzType tz_type = typeList.at(tz_tran.tz_typeind);-
734-
735 // Calculate the associated Rule-
736 if (!tz_type.tz_isdst)
!tz_type.tz_isdstDescription
TRUEevaluated 16244 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
FALSEevaluated 15309 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
15309-16244
737 utcOffset = tz_type.tz_gmtoff;
executed 16244 times by 2 tests: utcOffset = tz_type.tz_gmtoff;
Executed by:
  • tst_QDateTime
  • tst_QTimeZone
16244
738 rule.stdOffset = utcOffset;-
739 rule.dstOffset = tz_type.tz_gmtoff - utcOffset;-
740 rule.abbreviationIndex = tz_type.tz_abbrind;-
741 // If the rule already exist then use that, otherwise add it-
742 int ruleIndex = m_tranRules.indexOf(rule);-
743 if (ruleIndex == -1) {
ruleIndex == -1Description
TRUEevaluated 1704 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
FALSEevaluated 29849 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
1704-29849
744 m_tranRules.append(rule);-
745 tran.ruleIndex = m_tranRules.size() - 1;-
746 } else {
executed 1704 times by 2 tests: end of block
Executed by:
  • tst_QDateTime
  • tst_QTimeZone
1704
747 tran.ruleIndex = ruleIndex;-
748 }
executed 29849 times by 2 tests: end of block
Executed by:
  • tst_QDateTime
  • tst_QTimeZone
29849
749-
750 // TODO convert to UTC if not in UTC-
751 if (tz_type.tz_ttisgmt)
tz_type.tz_ttisgmtDescription
TRUEevaluated 8759 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
FALSEevaluated 22794 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
8759-22794
752 tran.atMSecsSinceEpoch = tz_tran.tz_time * 1000;
executed 8759 times by 2 tests: tran.atMSecsSinceEpoch = tz_tran.tz_time * 1000;
Executed by:
  • tst_QDateTime
  • tst_QTimeZone
8759
753 else if (tz_type.tz_ttisstd)
tz_type.tz_ttisstdDescription
TRUEevaluated 7286 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
FALSEevaluated 15508 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
7286-15508
754 tran.atMSecsSinceEpoch = tz_tran.tz_time * 1000;
executed 7286 times by 2 tests: tran.atMSecsSinceEpoch = tz_tran.tz_time * 1000;
Executed by:
  • tst_QDateTime
  • tst_QTimeZone
7286
755 else-
756 tran.atMSecsSinceEpoch = tz_tran.tz_time * 1000;
executed 15508 times by 2 tests: tran.atMSecsSinceEpoch = tz_tran.tz_time * 1000;
Executed by:
  • tst_QDateTime
  • tst_QTimeZone
15508
757-
758 m_tranTimes.append(tran);-
759 }
executed 31553 times by 2 tests: end of block
Executed by:
  • tst_QDateTime
  • tst_QTimeZone
31553
760-
761 if (ianaId.isEmpty())
ianaId.isEmpty()Description
TRUEnever evaluated
FALSEevaluated 454 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
0-454
762 m_id = systemTimeZoneId();
never executed: m_id = systemTimeZoneId();
0
763 else-
764 m_id = ianaId;
executed 454 times by 2 tests: m_id = ianaId;
Executed by:
  • tst_QDateTime
  • tst_QTimeZone
454
765}-
766-
767QLocale::Country QTzTimeZonePrivate::country() const-
768{-
769 return tzZones->value(m_id).country;-
770}-
771-
772QString QTzTimeZonePrivate::comment() const-
773{-
774 return QString::fromUtf8(tzZones->value(m_id).comment);-
775}-
776-
777QString QTzTimeZonePrivate::displayName(qint64 atMSecsSinceEpoch,-
778 QTimeZone::NameType nameType,-
779 const QLocale &locale) const-
780{-
781#ifdef QT_USE_ICU-
782 if (!m_icu)-
783 m_icu = new QIcuTimeZonePrivate(m_id);-
784 // TODO small risk may not match if tran times differ due to outdated files-
785 // TODO Some valid TZ names are not valid ICU names, use translation table?-
786 if (m_icu->isValid())-
787 return m_icu->displayName(atMSecsSinceEpoch, nameType, locale);-
788#else-
789 Q_UNUSED(nameType)-
790 Q_UNUSED(locale)-
791#endif // QT_USE_ICU-
792 return abbreviation(atMSecsSinceEpoch);-
793}-
794-
795QString QTzTimeZonePrivate::displayName(QTimeZone::TimeType timeType,-
796 QTimeZone::NameType nameType,-
797 const QLocale &locale) const-
798{-
799#ifdef QT_USE_ICU-
800 if (!m_icu)-
801 m_icu = new QIcuTimeZonePrivate(m_id);-
802 // TODO small risk may not match if tran times differ due to outdated files-
803 // TODO Some valid TZ names are not valid ICU names, use translation table?-
804 if (m_icu->isValid())-
805 return m_icu->displayName(timeType, nameType, locale);-
806#else-
807 Q_UNUSED(timeType)-
808 Q_UNUSED(nameType)-
809 Q_UNUSED(locale)-
810#endif // QT_USE_ICU-
811 // If no ICU available then have to use abbreviations instead-
812 // Abbreviations don't have GenericTime-
813 if (timeType == QTimeZone::GenericTime)-
814 timeType = QTimeZone::StandardTime;-
815-
816 // Get current tran, if valid and is what we want, then use it-
817 const qint64 currentMSecs = QDateTime::currentMSecsSinceEpoch();-
818 QTimeZonePrivate::Data tran = data(currentMSecs);-
819 if (tran.atMSecsSinceEpoch != invalidMSecs()-
820 && ((timeType == QTimeZone::DaylightTime && tran.daylightTimeOffset != 0)-
821 || (timeType == QTimeZone::StandardTime && tran.daylightTimeOffset == 0))) {-
822 return tran.abbreviation;-
823 }-
824-
825 // Otherwise get next tran and if valid and is what we want, then use it-
826 tran = nextTransition(currentMSecs);-
827 if (tran.atMSecsSinceEpoch != invalidMSecs()-
828 && ((timeType == QTimeZone::DaylightTime && tran.daylightTimeOffset != 0)-
829 || (timeType == QTimeZone::StandardTime && tran.daylightTimeOffset == 0))) {-
830 return tran.abbreviation;-
831 }-
832-
833 // Otherwise get prev tran and if valid and is what we want, then use it-
834 tran = previousTransition(currentMSecs);-
835 if (tran.atMSecsSinceEpoch != invalidMSecs())-
836 tran = previousTransition(tran.atMSecsSinceEpoch);-
837 if (tran.atMSecsSinceEpoch != invalidMSecs()-
838 && ((timeType == QTimeZone::DaylightTime && tran.daylightTimeOffset != 0)-
839 || (timeType == QTimeZone::StandardTime && tran.daylightTimeOffset == 0))) {-
840 return tran.abbreviation;-
841 }-
842-
843 // Otherwise is strange sequence, so work backwards through trans looking for first match, if any-
844 for (int i = m_tranTimes.size() - 1; i >= 0; --i) {-
845 if (m_tranTimes.at(i).atMSecsSinceEpoch <= currentMSecs) {-
846 tran = dataForTzTransition(m_tranTimes.at(i));-
847 if ((timeType == QTimeZone::DaylightTime && tran.daylightTimeOffset != 0)-
848 || (timeType == QTimeZone::StandardTime && tran.daylightTimeOffset == 0)) {-
849 return tran.abbreviation;-
850 }-
851 }-
852 }-
853-
854 // Otherwise if no match use current data-
855 return data(currentMSecs).abbreviation;-
856}-
857-
858QString QTzTimeZonePrivate::abbreviation(qint64 atMSecsSinceEpoch) const-
859{-
860 return data(atMSecsSinceEpoch).abbreviation;-
861}-
862-
863int QTzTimeZonePrivate::offsetFromUtc(qint64 atMSecsSinceEpoch) const-
864{-
865 const QTimeZonePrivate::Data tran = data(atMSecsSinceEpoch);-
866 return tran.standardTimeOffset + tran.daylightTimeOffset;-
867}-
868-
869int QTzTimeZonePrivate::standardTimeOffset(qint64 atMSecsSinceEpoch) const-
870{-
871 return data(atMSecsSinceEpoch).standardTimeOffset;-
872}-
873-
874int QTzTimeZonePrivate::daylightTimeOffset(qint64 atMSecsSinceEpoch) const-
875{-
876 return data(atMSecsSinceEpoch).daylightTimeOffset;-
877}-
878-
879bool QTzTimeZonePrivate::hasDaylightTime() const-
880{-
881 // TODO Perhaps cache as frequently accessed?-
882 foreachfor (const QTzTransitionRule &rule ,: m_tranRules) {-
883 if (rule.dstOffset != 0)
rule.dstOffset != 0Description
TRUEevaluated 1519 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
FALSEevaluated 3635 times by 2 tests
Evaluated by:
  • tst_QDateTime
  • tst_QTimeZone
1519-3635
884 return true;
executed 1519 times by 2 tests: return true;
Executed by:
  • tst_QDateTime
  • tst_QTimeZone
1519
885 }
executed 3635 times by 2 tests: end of block
Executed by:
  • tst_QDateTime
  • tst_QTimeZone
3635
886 return false;
executed 660 times by 1 test: return false;
Executed by:
  • tst_QTimeZone
660
887}-
888-
889bool QTzTimeZonePrivate::isDaylightTime(qint64 atMSecsSinceEpoch) const-
890{-
891 return (daylightTimeOffset(atMSecsSinceEpoch) != 0);-
892}-
893-
894QTimeZonePrivate::Data QTzTimeZonePrivate::dataForTzTransition(QTzTransitionTime tran) const-
895{-
896 QTimeZonePrivate::Data data;-
897 data.atMSecsSinceEpoch = tran.atMSecsSinceEpoch;-
898 QTzTransitionRule rule = m_tranRules.at(tran.ruleIndex);-
899 data.standardTimeOffset = rule.stdOffset;-
900 data.daylightTimeOffset = rule.dstOffset;-
901 data.offsetFromUtc = rule.stdOffset + rule.dstOffset;-
902 data.abbreviation = QString::fromUtf8(m_abbreviations.at(rule.abbreviationIndex));-
903 return data;-
904}-
905-
906QTimeZonePrivate::Data QTzTimeZonePrivate::data(qint64 forMSecsSinceEpoch) const-
907{-
908 // If the required time is after the last transition and we have a POSIX rule then use it-
909 if (m_tranTimes.size() > 0 && m_tranTimes.last().atMSecsSinceEpoch < forMSecsSinceEpoch-
910 && !m_posixRule.isEmpty() && forMSecsSinceEpoch >= 0) {-
911 const int year = QDateTime::fromMSecsSinceEpoch(forMSecsSinceEpoch, Qt::UTC).date().year();-
912 QVector<QTimeZonePrivate::Data> posixTrans =-
913 calculatePosixTransitions(m_posixRule, year - 1, year + 1,-
914 m_tranTimes.last().atMSecsSinceEpoch);-
915 for (int i = posixTrans.size() - 1; i >= 0; --i) {-
916 if (posixTrans.at(i).atMSecsSinceEpoch <= forMSecsSinceEpoch) {-
917 QTimeZonePrivate::Data data = posixTrans.at(i);-
918 data.atMSecsSinceEpoch = forMSecsSinceEpoch;-
919 return data;-
920 }-
921 }-
922 }-
923-
924 // Otherwise if we can find a valid tran then use its rule-
925 for (int i = m_tranTimes.size() - 1; i >= 0; --i) {-
926 if (m_tranTimes.at(i).atMSecsSinceEpoch <= forMSecsSinceEpoch) {-
927 Data data = dataForTzTransition(m_tranTimes.at(i));-
928 data.atMSecsSinceEpoch = forMSecsSinceEpoch;-
929 return data;-
930 }-
931 }-
932-
933 // Otherwise use the earliest transition we have-
934 if (m_tranTimes.size() > 0) {-
935 Data data = dataForTzTransition(m_tranTimes.at(0));-
936 data.atMSecsSinceEpoch = forMSecsSinceEpoch;-
937 return data;-
938 }-
939-
940 // Otherwise we have no rules, so probably an invalid tz, so return invalid data-
941 return invalidData();-
942}-
943-
944bool QTzTimeZonePrivate::hasTransitions() const-
945{-
946 return true;-
947}-
948-
949QTimeZonePrivate::Data QTzTimeZonePrivate::nextTransition(qint64 afterMSecsSinceEpoch) const-
950{-
951 // If the required time is after the last transition and we have a POSIX rule then use it-
952 if (m_tranTimes.size() > 0 && m_tranTimes.last().atMSecsSinceEpoch < afterMSecsSinceEpoch-
953 && !m_posixRule.isEmpty() && afterMSecsSinceEpoch >= 0) {-
954 const int year = QDateTime::fromMSecsSinceEpoch(afterMSecsSinceEpoch, Qt::UTC).date().year();-
955 QVector<QTimeZonePrivate::Data> posixTrans =-
956 calculatePosixTransitions(m_posixRule, year - 1, year + 1,-
957 m_tranTimes.last().atMSecsSinceEpoch);-
958 for (int i = 0; i < posixTrans.size(); ++i) {-
959 if (posixTrans.at(i).atMSecsSinceEpoch > afterMSecsSinceEpoch)-
960 return posixTrans.at(i);-
961 }-
962 }-
963-
964 // Otherwise if we can find a valid tran then use its rule-
965 for (int i = 0; i < m_tranTimes.size(); ++i) {-
966 if (m_tranTimes.at(i).atMSecsSinceEpoch > afterMSecsSinceEpoch) {-
967 return dataForTzTransition(m_tranTimes.at(i));-
968 }-
969 }-
970-
971 // Otherwise we have no rule, or there is no next transition, so return invalid data-
972 return invalidData();-
973}-
974-
975QTimeZonePrivate::Data QTzTimeZonePrivate::previousTransition(qint64 beforeMSecsSinceEpoch) const-
976{-
977 // If the required time is after the last transition and we have a POSIX rule then use it-
978 if (m_tranTimes.size() > 0 && m_tranTimes.last().atMSecsSinceEpoch < beforeMSecsSinceEpoch-
979 && !m_posixRule.isEmpty() && beforeMSecsSinceEpoch > 0) {-
980 const int year = QDateTime::fromMSecsSinceEpoch(beforeMSecsSinceEpoch, Qt::UTC).date().year();-
981 QVector<QTimeZonePrivate::Data> posixTrans =-
982 calculatePosixTransitions(m_posixRule, year - 1, year + 1,-
983 m_tranTimes.last().atMSecsSinceEpoch);-
984 for (int i = posixTrans.size() - 1; i >= 0; --i) {-
985 if (posixTrans.at(i).atMSecsSinceEpoch < beforeMSecsSinceEpoch)-
986 return posixTrans.at(i);-
987 }-
988 }-
989-
990 // Otherwise if we can find a valid tran then use its rule-
991 for (int i = m_tranTimes.size() - 1; i >= 0; --i) {-
992 if (m_tranTimes.at(i).atMSecsSinceEpoch < beforeMSecsSinceEpoch) {-
993 return dataForTzTransition(m_tranTimes.at(i));-
994 }-
995 }-
996-
997 // Otherwise we have no rule, so return invalid data-
998 return invalidData();-
999}-
1000-
1001// TODO Could cache the value and monitor the required files for any changes-
1002QByteArray QTzTimeZonePrivate::systemTimeZoneId() const-
1003{-
1004 // Check TZ env var first, if not populated try find it-
1005 QByteArray ianaId = qgetenv("TZ");-
1006 if (!ianaId.isEmpty() && ianaId.at(0) == ':')-
1007 ianaId = ianaId.mid(1);-
1008-
1009 // The TZ value can be ":/etc/localtime" which libc considers-
1010 // to be a "default timezone", in which case it will be read-
1011 // by one of the blocks below, so unset it here so it is not-
1012 // considered as a valid/found ianaId-
1013 if (ianaId == "/etc/localtime")-
1014 ianaId.clear();-
1015-
1016 // On Debian Etch and later /etc/localtime is real file with name held in /etc/timezone-
1017 if (ianaId.isEmpty()) {-
1018 QFile tzif(QStringLiteral("/etc/timezone"));-
1019 if (tzif.open(QIODevice::ReadOnly)) {-
1020 // TODO QTextStream inefficient, replace later-
1021 QTextStream ts(&tzif);-
1022 if (!ts.atEnd())-
1023 ianaId = ts.readLine().toUtf8();-
1024 }-
1025 }-
1026-
1027 // On other distros /etc/localtime is symlink to real file so can extract name from the path-
1028 if (ianaId.isEmpty()) {-
1029 const QString path = QFile::symLinkTarget(QStringLiteral("/etc/localtime"));-
1030 if (!path.isEmpty()) {-
1031 // /etc/localtime is a symlink to the current TZ file, so extract from path-
1032 int index = path.indexOf(QLatin1String("/zoneinfo/")) + 10;-
1033 ianaId = path.mid(index).toUtf8();-
1034 }-
1035 }-
1036-
1037 // On some Red Hat distros /etc/localtime is real file with name held in /etc/sysconfig/clock-
1038 // in a line like ZONE="Europe/Oslo" or TIMEZONE="Europe/Oslo"-
1039 if (ianaId.isEmpty()) {-
1040 QFile tzif(QStringLiteral("/etc/sysconfig/clock"));-
1041 if (tzif.open(QIODevice::ReadOnly)) {-
1042 // TODO QTextStream inefficient, replace later-
1043 QTextStream ts(&tzif);-
1044 QString line;-
1045 while (ianaId.isEmpty() && !ts.atEnd() && ts.status() == QTextStream::Ok) {-
1046 line = ts.readLine();-
1047 if (line.startsWith(QLatin1String("ZONE="))) {-
1048 ianaId = line.mid(6, line.size() - 7).toUtf8();-
1049 } else if (line.startsWith(QLatin1String("TIMEZONE="))) {-
1050 ianaId = line.mid(10, line.size() - 11).toUtf8();-
1051 }-
1052 }-
1053 }-
1054 }-
1055-
1056 // Give up for now and return UTC-
1057 if (ianaId.isEmpty())-
1058 ianaId = utcQByteArray();-
1059-
1060 return ianaId;-
1061}-
1062-
1063QList<QByteArray> QTzTimeZonePrivate::availableTimeZoneIds() const-
1064{-
1065 QList<QByteArray> result = tzZones->keys();-
1066 std::sort(result.begin(), result.end());-
1067 return result;-
1068}-
1069-
1070QList<QByteArray> QTzTimeZonePrivate::availableTimeZoneIds(QLocale::Country country) const-
1071{-
1072 // TODO AnyCountry-
1073 QList<QByteArray> result;-
1074 foreachfor (const QByteArray &key,auto it = tzZones->keys())cbegin(), end = tzZones->cend(); it != end; ++it) {
it != endDescription
TRUEevaluated 421 times by 1 test
Evaluated by:
  • tst_QTimeZone
FALSEevaluated 1 time by 1 test
Evaluated by:
  • tst_QTimeZone
1-421
1075 if (tzZones->it.value(key).().country == country)
it.value().country == countryDescription
TRUEevaluated 29 times by 1 test
Evaluated by:
  • tst_QTimeZone
FALSEevaluated 392 times by 1 test
Evaluated by:
  • tst_QTimeZone
29-392
1076 result << it.key;();
executed 29 times by 1 test: result << it.key();
Executed by:
  • tst_QTimeZone
29
1077 }
executed 421 times by 1 test: end of block
Executed by:
  • tst_QTimeZone
421
1078 std::sort(result.begin(), result.end());-
1079 return result;
executed 1 time by 1 test: return result;
Executed by:
  • tst_QTimeZone
1
1080}-
1081-
1082QT_END_NAMESPACE-
Source codeSwitch to Preprocessed file

Generated by Squish Coco Non-Commercial 4.3.0-BETA-master-30-08-2018-4cb69e9