Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-42021

Incorrect calculation of next/previous transition in time zone on Windows



    • Bug
    • Resolution: Done
    • P2: Important
    • 5.12.0 Alpha
    • 5.2.1
    • Core: Date/Time
    • None
    • Windows 7 SP1 x64 Professional, Qt 5.2.1, MinGW 4.8.
    • 6d3e5ac6d2f34a0da609f863bed95d3be571c589, 68bcccac228b73c54137304718c3c92460bc1f4b, 4cce7dc19d0243d4d8f6f5f06365e251dbe1e7aa



          const char* tzMoscow = "Europe/Moscow";
          QTimeZone moscow(QByteArray::fromRawData(tzMoscow, qstrlen(tzMoscow)));
          QTimeZone::OffsetDataList odl = moscow.transitions(QDateTime(QDate(2013, 1, 1)), QDateTime(QDate(2014, 12, 31)));

      returns empty list, even though there should be transitions in 2014.

      That's because QWinTimeZonePrivate::nextTransition(qint64 afterMSecsSinceEpoch) returns invalidData() if there are no transitions in the specified year, and

      QTimeZonePrivate::DataList QTimeZonePrivate::transitions(qint64 fromMSecsSinceEpoch,
                                                               qint64 toMSecsSinceEpoch) const

      quits if it gets invalid data during filling the list, even though there are transitions in year 2014 (but not in year 2013, which is the year this function starts with in my example).

      QWinTimeZonePrivate::previousTransition(qint64 beforeMSecsSinceEpoch) and QWinTimeZonePrivate::data(qint64 forMSecsSinceEpoch) have this bug too. They all look at the specified year only, but here in Russia we had several years without transitions at all.

      In addition, consider:

      QTimeZonePrivate::Data QWinTimeZonePrivate::data(qint64 forMSecsSinceEpoch) const
          // Convert MSecs to year to get transitions for, assumes no transitions around 31 Dec/1 Jan
          int year = msecsToDate(forMSecsSinceEpoch).year();
          qint64 first;
          qint64 second;
          qint64 next = maxMSecs();
          qint64 stdMSecs;
          qint64 dstMSecs;
          QWinTransitionRule rule;
          do {
              // Convert the transition rules into msecs for the year we want to try
              rule = ruleForYear(year);
              // If no transition rules to calculate then no DST, so just use rule for std
              if (rule.standardTimeRule.wMonth == 0 && rule.daylightTimeRule.wMonth == 0)
              calculateTransitionsForYear(rule, year, &stdMSecs, &dstMSecs);
              if (stdMSecs < dstMSecs) {
                  first = stdMSecs;
                  second = dstMSecs;
              } else {
                  first = dstMSecs;
                  second = stdMSecs;
              if (forMSecsSinceEpoch >= second && second != invalidMSecs())
                  next = second;
              else if (forMSecsSinceEpoch >= first && first != invalidMSecs())
                  next = first;
              // If didn't fall in this year, try the previous
          } while (next == maxMSecs() && year >= MIN_YEAR);
          return ruleToData(rule, forMSecsSinceEpoch, (next == dstMSecs) ? QTimeZone::DaylightTime : QTimeZone::StandardTime);

      If the function breaks out of the cycle on the 1st pass, it will then use uninitialized local dstMSecs variable.


        Issue Links

          No reviews matched the request. Check your Options in the drop-down menu of this sections header.



              Eddy Edward Welbourne
              azarubkin Alexandr Zarubkin
              0 Vote for this issue
              4 Start watching this issue



                Gerrit Reviews

                  There are no open Gerrit changes