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

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

    XMLWordPrintable

Details

    • 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

    Description

      Consider

          const char* tzMoscow = "Europe/Moscow";
          QTimeZone moscow(QByteArray::fromRawData(tzMoscow, qstrlen(tzMoscow)));
          Q_ASSERT(moscow.isValid());
          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)
                  break;
              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
              --year;
          } 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.

      Attachments

        Issue Links

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

          Activity

            People

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

              Dates

                Created:
                Updated:
                Resolved:

                Gerrit Reviews

                  There are no open Gerrit changes