src/corelib/tools/qdatetime.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 ** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.
00004 **
00005 ** This file is part of the QtCore module of the Qt Toolkit.
00006 **
00007 ** This file may be used under the terms of the GNU General Public
00008 ** License version 2.0 as published by the Free Software Foundation
00009 ** and appearing in the file LICENSE.GPL included in the packaging of
00010 ** this file.  Please review the following information to ensure GNU
00011 ** General Public Licensing requirements will be met:
00012 ** http://www.trolltech.com/products/qt/opensource.html
00013 **
00014 ** If you are unsure which license is appropriate for your use, please
00015 ** review the following information:
00016 ** http://www.trolltech.com/products/qt/licensing.html or contact the
00017 ** sales department at sales@trolltech.com.
00018 **
00019 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00020 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00021 **
00022 ****************************************************************************/
00023 
00024 #include "qplatformdefs.h"
00025 #include "private/qdatetime_p.h"
00026 
00027 #include "qdatastream.h"
00028 #include "qset.h"
00029 #include "qlocale.h"
00030 #include "qdatetime.h"
00031 #include "qregexp.h"
00032 #include "qdebug.h"
00033 #if defined(Q_OS_WIN32)
00034 #include <windows.h>
00035 #endif
00036 #ifndef Q_WS_WIN
00037 #include <locale.h>
00038 #endif
00039 
00040 #include <time.h>
00041 
00042 //#define QDATETIMEPARSER_DEBUG
00043 #if defined (QDATETIMEPARSER_DEBUG) && !defined(QT_NO_DEBUG_STREAM)
00044 #  define QDTPDEBUG qDebug() << QString("%1:%2").arg(__FILE__).arg(__LINE__)
00045 #  define QDTPDEBUGN qDebug
00046 #else
00047 #  define QDTPDEBUG if (false) qDebug()
00048 #  define QDTPDEBUGN if (false) qDebug
00049 #endif
00050 
00051 #if defined(Q_WS_MAC)
00052 #include <private/qcore_mac_p.h>
00053 extern QString qt_mac_from_pascal_string(const Str255); // qglobal.cpp
00054 #endif
00055 
00056 enum {
00057     FIRST_YEAR = -4713,
00058     FIRST_MONTH = 1,
00059     FIRST_DAY = 2,  // ### Qt 5: make FIRST_DAY = 1, by support jd == 0 as valid
00060     SECS_PER_DAY = 86400,
00061     MSECS_PER_DAY = 86400000,
00062     SECS_PER_HOUR = 3600,
00063     MSECS_PER_HOUR = 3600000,
00064     SECS_PER_MIN = 60,
00065     MSECS_PER_MIN = 60000
00066 };
00067 
00068 static inline QDate strictDate(int y, int m, int d)
00069 {
00070     QDate result;
00071     result.setDate(y, m, d);
00072     return result;
00073 }
00074 
00075 static inline QDate fixedDate(int y, int m, int d)
00076 {
00077     QDate result(strictDate(y, m, 1));
00078     result.setDate(y, m, qMin(d, result.daysInMonth()));
00079     return result;
00080 }
00081 
00082 static uint julianDayFromDate(int year, int month, int day)
00083 {
00084     if (year < 0)
00085         ++year;
00086 
00087     if (year > 1582 || (year == 1582 && (month > 10 || (month == 10 && day >= 15)))) {
00088         // Gregorian calendar starting from October 15, 1582
00089         // Algorithm from Henry F. Fliegel and Thomas C. Van Flandern
00090         return (1461 * (year + 4800 + (month - 14) / 12)) / 4
00091                + (367 * (month - 2 - 12 * ((month - 14) / 12))) / 12
00092                - (3 * ((year + 4900 + (month - 14) / 12) / 100)) / 4
00093                + day - 32075;
00094     } else if (year < 1582 || (year == 1582 && (month < 10 || (month == 10 && day <= 4)))) {
00095         // Julian calendar until October 4, 1582
00096         // Algorithm from Frequently Asked Questions about Calendars by Claus Toendering
00097         int a = (14 - month) / 12;
00098         return (153 * (month + (12 * a) - 3) + 2) / 5
00099                + (1461 * (year + 4800 - a)) / 4
00100                + day - 32083;
00101     } else {
00102         // the day following October 4, 1582 is October 15, 1582
00103         return 0;
00104     }
00105 }
00106 
00107 static void getDateFromJulianDay(uint julianDay, int *year, int *month, int *day)
00108 {
00109     int y, m, d;
00110 
00111     if (julianDay >= 2299161) {
00112         // Gregorian calendar starting from October 15, 1582
00113         // This algorithm is from Henry F. Fliegel and Thomas C. Van Flandern
00114         qulonglong ell, n, i, j;
00115         ell = qulonglong(julianDay) + 68569;
00116         n = (4 * ell) / 146097;
00117         ell = ell - (146097 * n + 3) / 4;
00118         i = (4000 * (ell + 1)) / 1461001;
00119         ell = ell - (1461 * i) / 4 + 31;
00120         j = (80 * ell) / 2447;
00121         d = ell - (2447 * j) / 80;
00122         ell = j / 11;
00123         m = j + 2 - (12 * ell);
00124         y = 100 * (n - 49) + i + ell;
00125     } else {
00126         // Julian calendar until October 4, 1582
00127         // Algorithm from Frequently Asked Questions about Calendars by Claus Toendering
00128         julianDay += 32082;
00129         int dd = (4 * julianDay + 3) / 1461;
00130         int ee = julianDay - (1461 * dd) / 4;
00131         int mm = ((5 * ee) + 2) / 153;
00132         d = ee - (153 * mm + 2) / 5 + 1;
00133         m = mm + 3 - 12 * (mm / 10);
00134         y = dd - 4800 + (mm / 10);
00135         if (y <= 0)
00136             --y;
00137     }
00138     *year = y;
00139     *month = m;
00140     *day = d;
00141 }
00142 
00143 
00144 static const char monthDays[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
00145 
00146 #ifndef QT_NO_TEXTDATE
00147 static const char * const qt_shortMonthNames[] = {
00148     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
00149     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
00150 #endif
00151 #ifndef QT_NO_DATESTRING
00152 static QString fmtDateTime(const QString& f, const QTime* dt = 0, const QDate* dd = 0);
00153 #endif
00154 
00155 /*****************************************************************************
00156   QDate member functions
00157  *****************************************************************************/
00158 
00230 QDate::QDate(int y, int m, int d)
00231 {
00232     if (uint(y) <= 99u)
00233         y += 1900;
00234     setDate(y, m, d);
00235 }
00236 
00237 
00254 bool QDate::isValid() const
00255 {
00256     return !isNull();
00257 }
00258 
00259 
00268 int QDate::year() const
00269 {
00270     int y, m, d;
00271     getDateFromJulianDay(jd, &y, &m, &d);
00272     return y;
00273 }
00274 
00297 int QDate::month() const
00298 {
00299     int y, m, d;
00300     getDateFromJulianDay(jd, &y, &m, &d);
00301     return m;
00302 }
00303 
00310 int QDate::day() const
00311 {
00312     int y, m, d;
00313     getDateFromJulianDay(jd, &y, &m, &d);
00314     return d;
00315 }
00316 
00323 int QDate::dayOfWeek() const
00324 {
00325     return (jd % 7) + 1;
00326 }
00327 
00334 int QDate::dayOfYear() const
00335 {
00336     return jd - julianDayFromDate(year(), 1, 1) + 1;
00337 }
00338 
00345 int QDate::daysInMonth() const
00346 {
00347     int y, m, d;
00348     getDateFromJulianDay(jd, &y, &m, &d);
00349     if (m == 2 && isLeapYear(y))
00350         return 29;
00351     else
00352         return monthDays[m];
00353 }
00354 
00361 int QDate::daysInYear() const
00362 {
00363     int y, m, d;
00364     getDateFromJulianDay(jd, &y, &m, &d);
00365     return isLeapYear(y) ? 366 : 365;
00366 }
00367 
00401 int QDate::weekNumber(int *yearNumber) const
00402 {
00403     if (!isValid())
00404         return 0;
00405 
00406     int year = QDate::year();
00407     int yday = dayOfYear() - 1;
00408     int wday = dayOfWeek();
00409     if (wday == 7)
00410         wday = 0;
00411     int w;
00412 
00413     for (;;) {
00414         int len;
00415         int bot;
00416         int top;
00417 
00418         len = isLeapYear(year) ? 366 : 365;
00419         /*
00420         ** What yday (-3 ... 3) does
00421         ** the ISO year begin on?
00422         */
00423         bot = ((yday + 11 - wday) % 7) - 3;
00424         /*
00425         ** What yday does the NEXT
00426         ** ISO year begin on?
00427         */
00428         top = bot - (len % 7);
00429         if (top < -3)
00430             top += 7;
00431         top += len;
00432         if (yday >= top) {
00433             ++year;
00434             w = 1;
00435             break;
00436         }
00437         if (yday >= bot) {
00438             w = 1 + ((yday - bot) / 7);
00439             break;
00440         }
00441         --year;
00442         yday += isLeapYear(year) ? 366 : 365;
00443     }
00444     if (yearNumber != 0)
00445         *yearNumber = year;
00446     return w;
00447 }
00448 
00449 #ifndef QT_NO_TEXTDATE
00450 
00475 QString QDate::shortMonthName(int month)
00476 {
00477     if (month < 1 || month > 12) {
00478         qWarning("QDate::shortMonthName: Parameter out ouf range");
00479         month = 1;
00480     }
00481     return QLocale::system().monthName(month, QLocale::ShortFormat);
00482 }
00483 
00509 QString QDate::longMonthName(int month)
00510 {
00511     if (month < 1 || month > 12) {
00512         qWarning("QDate::longMonthName: Parameter out ouf range");
00513         month = 1;
00514     }
00515     return QLocale::system().monthName(month, QLocale::LongFormat);
00516 }
00517 
00538 QString QDate::shortDayName(int weekday)
00539 {
00540     if (weekday < 1 || weekday > 7) {
00541         qWarning("QDate::shortDayName: Parameter out of range");
00542         weekday = 1;
00543     }
00544     return QLocale::system().dayName(weekday, QLocale::ShortFormat);
00545 }
00546 
00567 QString QDate::longDayName(int weekday)
00568 {
00569     if (weekday < 1 || weekday > 7) {
00570         qWarning("QDate::longDayName: Parameter out of range");
00571         weekday = 1;
00572     }
00573     return QLocale::system().dayName(weekday, QLocale::LongFormat);
00574 }
00575 #endif //QT_NO_TEXTDATE
00576 
00577 #ifndef QT_NO_DATESTRING
00578 
00619 QString QDate::toString(Qt::DateFormat f) const
00620 {
00621     if (!isValid())
00622         return QString();
00623     int y, m, d;
00624     getDateFromJulianDay(jd, &y, &m, &d);
00625     switch (f) {
00626     case Qt::SystemLocaleDate:
00627         return QLocale::system().toString(*this, QLocale::ShortFormat);
00628     case Qt::LocaleDate:
00629         return QLocale().toString(*this, QLocale::ShortFormat);
00630     default:
00631 #ifndef QT_NO_TEXTDATE
00632     case Qt::TextDate:
00633         {
00634             return QString::fromLatin1("%0 %1 %2 %3")
00635                 .arg(shortDayName(dayOfWeek()))
00636                 .arg(shortMonthName(m))
00637                 .arg(d)
00638                 .arg(y);
00639         }
00640 #endif
00641     case Qt::ISODate:
00642         {
00643             if (year() < 0 || year() > 9999)
00644                 return QString();
00645             QString month(QString::number(m).rightJustified(2, QLatin1Char('0')));
00646             QString day(QString::number(d).rightJustified(2, QLatin1Char('0')));
00647             return QString::number(y) + QLatin1Char('-') + month + QLatin1Char('-') + day;
00648         }
00649     }
00650 }
00651 
00702 QString QDate::toString(const QString& format) const
00703 {
00704     if (uint(year()) > 9999)
00705         return QString();
00706     return fmtDateTime(format, 0, this);
00707 }
00708 #endif //QT_NO_DATESTRING
00709 
00721 bool QDate::setYMD(int y, int m, int d)
00722 {
00723     if (uint(y) <= 99)
00724         y += 1900;
00725     return setDate(y, m, d);
00726 }
00727 
00740 bool QDate::setDate(int year, int month, int day)
00741 {
00742     if (!isValid(year, month, day)) {
00743         jd = 0;
00744     } else {
00745         jd = julianDayFromDate(year, month, day);
00746     }
00747     return jd != 0;
00748 }
00749 
00757 QDate QDate::addDays(int ndays) const
00758 {
00759     QDate d;
00760     d.jd = jd + ndays;
00761     return d;
00762 }
00763 
00771 QDate QDate::addMonths(int nmonths) const
00772 {
00773     int y, m, d;
00774     getDateFromJulianDay(jd, &y, &m, &d);
00775 
00776     while (nmonths != 0) {
00777         if (nmonths < 0 && nmonths + 12 <= 0) {
00778             y--;
00779             nmonths+=12;
00780         } else if (nmonths < 0) {
00781             m+= nmonths;
00782             nmonths = 0;
00783             if (m <= 0) {
00784                 --y;
00785                 m += 12;
00786             }
00787         } else if (nmonths - 12 >= 0) {
00788             y++;
00789             nmonths -= 12;
00790         } else if (m == 12) {
00791             y++;
00792             m = 0;
00793         } else {
00794             m += nmonths;
00795             nmonths = 0;
00796             if (m > 12) {
00797                 ++y;
00798                 m -= 12;
00799             }
00800         }
00801     }
00802 
00803     return fixedDate(y, m, d);
00804 }
00805 
00813 QDate QDate::addYears(int nyears) const
00814 {
00815     int y, m, d;
00816     getDateFromJulianDay(jd, &y, &m, &d);
00817     y += nyears;
00818     return fixedDate(y, m, d);
00819 }
00820 
00836 int QDate::daysTo(const QDate &d) const
00837 {
00838     return d.jd - jd;
00839 }
00840 
00841 
00891 QDate QDate::currentDate()
00892 {
00893     QDate d;
00894 #if defined(Q_OS_WIN)
00895     SYSTEMTIME st;
00896     memset(&st, 0, sizeof(SYSTEMTIME));
00897     GetLocalTime(&st);
00898     d.jd = julianDayFromDate(st.wYear, st.wMonth, st.wDay);
00899 #else
00900     // posix compliant system
00901     time_t ltime;
00902     time(&ltime);
00903     tm *t;
00904 
00905 #if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS)
00906     // use the reentrant version of localtime() where available
00907     tm res;
00908     t = localtime_r(&ltime, &res);
00909 #else
00910     t = localtime(&ltime);
00911 #endif // !QT_NO_THREAD && _POSIX_THREAD_SAFE_FUNCTIONS
00912 
00913     d.jd = julianDayFromDate(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday);
00914 #endif
00915     return d;
00916 }
00917 
00918 #ifndef QT_NO_DATESTRING
00919 
00932 QDate QDate::fromString(const QString& s, Qt::DateFormat f)
00933 {
00934     if ((s.isEmpty()) || (f == Qt::LocalDate))
00935         return QDate();
00936 
00937     switch (f) {
00938     case Qt::ISODate:
00939         {
00940             int year(s.mid(0, 4).toInt());
00941             int month(s.mid(5, 2).toInt());
00942             int day(s.mid(8, 2).toInt());
00943             if (year && month && day)
00944                 return strictDate(year, month, day);
00945         }
00946         break;
00947     default:
00948 #ifndef QT_NO_TEXTDATE
00949     case Qt::TextDate:
00950         {
00951             /*
00952               This will fail gracefully if the input string doesn't
00953               contain any space.
00954             */
00955             int monthPos = s.indexOf(QLatin1Char(' ')) + 1;
00956             int dayPos = s.indexOf(QLatin1Char(' '), monthPos) + 1;
00957             int yearPos = s.indexOf(QLatin1Char(' '), dayPos) + 1;
00958 
00959             QString monthName(s.mid(monthPos, dayPos - monthPos - 1));
00960             int month = -1;
00961 
00962             // try English names first
00963             for (int i = 0; i < 12; i++) {
00964                 if (monthName == QLatin1String(qt_shortMonthNames[i])) {
00965                     month = i + 1;
00966                     break;
00967                 }
00968             }
00969 
00970             // try the localized names
00971             if (month == -1) {
00972                 for (int i = 0; i < 12; i++) {
00973                     if (monthName == shortMonthName(i + 1)) {
00974                         month = i + 1;
00975                         break;
00976                     }
00977                 }
00978             }
00979             if (month >= 1 && month <= 12) {
00980                 int day = s.mid(dayPos, 2).trimmed().toInt();
00981                 int year = s.mid(yearPos).toInt();
00982                 return strictDate(year, month, day);
00983             }
00984         }
00985 #else
00986         break;
00987 #endif
00988     }
00989     return QDate();
00990 }
00991 
01065 QDate QDate::fromString(const QString &string, const QString &format)
01066 {
01067     QDate date;
01068 #ifndef QT_BOOTSTRAPPED
01069     QDateTimeParser dt(QVariant::Date);
01070     if (dt.parseFormat(format))
01071         dt.fromString(string, &date, 0);
01072 #else
01073     Q_UNUSED(string);
01074     Q_UNUSED(format);
01075 #endif
01076     return date;
01077 }
01078 #endif // QT_NO_DATESTRING
01079 
01100 bool QDate::isValid(int year, int month, int day)
01101 {
01102     if (year < FIRST_YEAR
01103             || (year == FIRST_YEAR && (month < FIRST_MONTH || month == FIRST_MONTH && day < FIRST_DAY))
01104             || year == 0) // there is no year 0 in the Julian calendar
01105         return false;
01106 
01107     // passage from Julian to Gregorian calendar
01108     if (year == 1582 && month == 10 && day > 4 && day < 15)
01109         return 0;
01110 
01111     return (day > 0 && month > 0 && month <= 12) &&
01112            (day <= monthDays[month] || (day == 29 && month == 2 && isLeapYear(year)));
01113 }
01114 
01122 bool QDate::isLeapYear(int y)
01123 {
01124     if (y < 1582) {
01125         return qAbs(y) % 4 == 0;
01126     } else {
01127         return y % 4 == 0 && y % 100 != 0 || y % 400 == 0;
01128     }
01129 }
01130 
01138 uint QDate::gregorianToJulian(int y, int m, int d)
01139 {
01140     return julianDayFromDate(y, m, d);
01141 }
01142 
01150 void QDate::julianToGregorian(uint jd, int &y, int &m, int &d)
01151 {
01152     getDateFromJulianDay(jd, &y, &m, &d);
01153 }
01154 
01169 /*****************************************************************************
01170   QTime member functions
01171  *****************************************************************************/
01172 
01239 QTime::QTime(int h, int m, int s, int ms)
01240 {
01241     setHMS(h, m, s, ms);
01242 }
01243 
01244 
01262 bool QTime::isValid() const
01263 {
01264     return mds > NullTime && mds < MSECS_PER_DAY;
01265 }
01266 
01267 
01274 int QTime::hour() const
01275 {
01276     return ds() / MSECS_PER_HOUR;
01277 }
01278 
01285 int QTime::minute() const
01286 {
01287     return (ds() % MSECS_PER_HOUR) / MSECS_PER_MIN;
01288 }
01289 
01296 int QTime::second() const
01297 {
01298     return (ds() / 1000)%SECS_PER_MIN;
01299 }
01300 
01307 int QTime::msec() const
01308 {
01309     return ds() % 1000;
01310 }
01311 
01312 #ifndef QT_NO_DATESTRING
01313 
01344 QString QTime::toString(Qt::DateFormat f) const
01345 {
01346     if (!isValid())
01347         return QString();
01348 
01349     switch (f) {
01350     case Qt::SystemLocaleDate:
01351         return QLocale::system().toString(*this, QLocale::ShortFormat);
01352     case Qt::LocaleDate:
01353         return QLocale().toString(*this, QLocale::ShortFormat);
01354     default:
01355     case Qt::ISODate:
01356     case Qt::TextDate:
01357         return QString::fromLatin1("%1:%2:%3")
01358             .arg(hour(), 2, 10, QLatin1Char('0'))
01359             .arg(minute(), 2, 10, QLatin1Char('0'))
01360             .arg(second(), 2, 10, QLatin1Char('0'));
01361     }
01362 }
01363 
01409 QString QTime::toString(const QString& format) const
01410 {
01411     return fmtDateTime(format, this, 0);
01412 }
01413 #endif //QT_NO_DATESTRING
01414 
01425 bool QTime::setHMS(int h, int m, int s, int ms)
01426 {
01427     if (!isValid(h,m,s,ms)) {
01428         mds = NullTime;                // make this invalid
01429         return false;
01430     }
01431     mds = (h*SECS_PER_HOUR + m*SECS_PER_MIN + s)*1000 + ms;
01432     return true;
01433 }
01434 
01455 QTime QTime::addSecs(int nsecs) const
01456 {
01457     return addMSecs(nsecs * 1000);
01458 }
01459 
01471 int QTime::secsTo(const QTime &t) const
01472 {
01473     return (t.ds() - ds()) / 1000;
01474 }
01475 
01486 QTime QTime::addMSecs(int ms) const
01487 {
01488     QTime t;
01489     if (ms < 0) {
01490         // % not well-defined for -ve, but / is.
01491         int negdays = (MSECS_PER_DAY - ms) / MSECS_PER_DAY;
01492         t.mds = (ds() + ms + negdays * MSECS_PER_DAY) % MSECS_PER_DAY;
01493     } else {
01494         t.mds = (ds() + ms) % MSECS_PER_DAY;
01495     }
01496     return t;
01497 }
01498 
01511 int QTime::msecsTo(const QTime &t) const
01512 {
01513     return t.ds() - ds();
01514 }
01515 
01516 
01564 QTime QTime::currentTime()
01565 {
01566     QTime ct;
01567 
01568 #if defined(Q_OS_WIN)
01569     SYSTEMTIME st;
01570     memset(&st, 0, sizeof(SYSTEMTIME));
01571     GetLocalTime(&st);
01572     ct.mds = MSECS_PER_HOUR * st.wHour + MSECS_PER_MIN * st.wMinute + 1000 * st.wSecond
01573              + st.wMilliseconds;
01574 #elif defined(Q_OS_UNIX)
01575     // posix compliant system
01576     struct timeval tv;
01577     gettimeofday(&tv, 0);
01578     time_t ltime = tv.tv_sec;
01579     tm *t;
01580 
01581 #if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS)
01582     // use the reentrant version of localtime() where available
01583     tm res;
01584     t = localtime_r(&ltime, &res);
01585 #else
01586     t = localtime(&ltime);
01587 #endif
01588 
01589     ct.mds = MSECS_PER_HOUR * t->tm_hour + MSECS_PER_MIN * t->tm_min + 1000 * t->tm_sec
01590              + tv.tv_usec / 1000;
01591 #else
01592     time_t ltime; // no millisecond resolution
01593     ::time(&ltime);
01594     tm *t;
01595     localtime(&ltime);
01596     ct.mds = MSECS_PER_HOUR * t->tm_hour + MSECS_PER_MIN * t->tm_min + 1000 * t->tm_sec;
01597 #endif
01598     return ct;
01599 }
01600 
01601 #ifndef QT_NO_DATESTRING
01602 
01610 QTime QTime::fromString(const QString& s, Qt::DateFormat f)
01611 {
01612     if (s.isEmpty() || f == Qt::LocalDate) {
01613         qWarning("QTime::fromString: Parameter out of range");
01614         QTime t;
01615         t.mds = NullTime;
01616         return t;
01617     }
01618 
01619     const int hour(s.mid(0, 2).toInt());
01620     const int minute(s.mid(3, 2).toInt());
01621     const int second(s.mid(6, 2).toInt());
01622 
01623     const QString msec_s(QLatin1String("0.") + s.mid(9, 4));
01624     const float msec(msec_s.toFloat());
01625     return QTime(hour, minute, second, qMin(qRound(msec * 1000.0), 999));
01626 }
01627 
01687 QTime QTime::fromString(const QString &string, const QString &format)
01688 {
01689     QTime time;
01690 #ifndef QT_BOOTSTRAPPED
01691     QDateTimeParser dt(QVariant::Time);
01692     if (dt.parseFormat(format))
01693         dt.fromString(string, 0, &time);
01694 #else
01695     Q_UNUSED(string);
01696     Q_UNUSED(format);
01697 #endif
01698     return time;
01699 }
01700 
01701 #endif // QT_NO_DATESTRING
01702 
01703 
01721 bool QTime::isValid(int h, int m, int s, int ms)
01722 {
01723     return (uint)h < 24 && (uint)m < 60 && (uint)s < 60 && (uint)ms < 1000;
01724 }
01725 
01726 
01740 void QTime::start()
01741 {
01742     *this = currentTime();
01743 }
01744 
01765 int QTime::restart()
01766 {
01767     QTime t = currentTime();
01768     int n = msecsTo(t);
01769     if (n < 0)                                // passed midnight
01770         n += 86400*1000;
01771     *this = t;
01772     return n;
01773 }
01774 
01793 int QTime::elapsed() const
01794 {
01795     int n = msecsTo(currentTime());
01796     if (n < 0)                                // passed midnight
01797         n += 86400 * 1000;
01798     return n;
01799 }
01800 
01801 
01802 /*****************************************************************************
01803   QDateTime member functions
01804  *****************************************************************************/
01805 
01860 QDateTime::QDateTime()
01861 {
01862     d = new QDateTimePrivate;
01863 }
01864 
01865 
01871 QDateTime::QDateTime(const QDate &date)
01872 {
01873     d = new QDateTimePrivate;
01874     d->date = date;
01875     d->time = QTime(0, 0, 0);
01876 }
01877 
01885 QDateTime::QDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec)
01886 {
01887     d = new QDateTimePrivate;
01888     d->date = date;
01889     d->time = date.isValid() && !time.isValid() ? QTime(0, 0, 0) : time;
01890     d->spec = (spec == Qt::UTC) ? QDateTimePrivate::UTC : QDateTimePrivate::LocalUnknown;
01891 }
01892 
01897 QDateTime::QDateTime(const QDateTime &other)
01898 {
01899     d = other.d;
01900     d->ref.ref();
01901 }
01902 
01906 QDateTime::~QDateTime()
01907 {
01908     if (!d->ref.deref())
01909         delete d;
01910 }
01911 
01917 QDateTime &QDateTime::operator=(const QDateTime &other)
01918 {
01919     qAtomicAssign(d, other.d);
01920     return *this;
01921 }
01922 
01930 bool QDateTime::isNull() const
01931 {
01932     return d->date.isNull() && d->time.isNull();
01933 }
01934 
01942 bool QDateTime::isValid() const
01943 {
01944     return d->date.isValid() && d->time.isValid();
01945 }
01946 
01953 QDate QDateTime::date() const
01954 {
01955     return d->date;
01956 }
01957 
01964 QTime QDateTime::time() const
01965 {
01966     return d->time;
01967 }
01968 
01975 Qt::TimeSpec QDateTime::timeSpec() const
01976 {
01977     return d->spec == QDateTimePrivate::UTC ? Qt::UTC : Qt::LocalTime;
01978 }
01979 
01987 void QDateTime::setDate(const QDate &date)
01988 {
01989     detach();
01990     d->date = date;
01991     if (date.isValid() && !d->time.isValid())
01992         d->time = QTime(0, 0, 0);
01993 }
01994 
02001 void QDateTime::setTime(const QTime &time)
02002 {
02003     detach();
02004     d->time = time;
02005 }
02006 
02013 void QDateTime::setTimeSpec(Qt::TimeSpec spec)
02014 {
02015     detach();
02016     d->spec = (spec == Qt::UTC) ? QDateTimePrivate::UTC : QDateTimePrivate::LocalUnknown;
02017 }
02018 
02019 static uint toTime_t(const QDate &utcDate, const QTime &utcTime)
02020 {
02021     int days = QDate(1970, 1, 1).daysTo(utcDate);
02022     int secs = QTime().secsTo(utcTime);
02023     if (days < 0 || (days == 0 && secs < 0))
02024         return uint(-1);
02025 
02026     qlonglong retval = (qlonglong(days) * SECS_PER_DAY) + secs;
02027     if (retval >= Q_INT64_C(0xFFFFFFFF))
02028         return uint(-1);
02029     return uint(retval);
02030 }
02031 
02042 uint QDateTime::toTime_t() const
02043 {
02044     QDate utcDate;
02045     QTime utcTime;
02046     d->getUTC(utcDate, utcTime);
02047 
02048     return ::toTime_t(utcDate, utcTime);
02049 }
02050 
02062 void QDateTime::setTime_t(uint secsSince1Jan1970UTC)
02063 {
02064     detach();
02065 
02066     QDateTimePrivate::Spec oldSpec = d->spec;
02067 
02068     d->date = QDate(1970, 1, 1).addDays(secsSince1Jan1970UTC / SECS_PER_DAY);
02069     d->time = QTime().addSecs(secsSince1Jan1970UTC % SECS_PER_DAY);
02070     d->spec = QDateTimePrivate::UTC;
02071 
02072     if (oldSpec != QDateTimePrivate::UTC)
02073         d->spec = d->getLocal(d->date, d->time);
02074 }
02075 
02076 #ifndef QT_NO_DATESTRING
02077 
02115 QString QDateTime::toString(Qt::DateFormat f) const
02116 {
02117     QString buf;
02118     if (!isValid())
02119         return buf;
02120 
02121     if (f == Qt::ISODate) {
02122         buf = d->date.toString(Qt::ISODate);
02123         if (buf.isEmpty())
02124             return QString();   // failed to convert
02125         buf += QLatin1Char('T');
02126         buf += d->time.toString(Qt::ISODate);
02127     }
02128 #ifndef QT_NO_TEXTDATE
02129     else if (f == Qt::TextDate) {
02130 #ifndef Q_WS_WIN
02131         buf = d->date.shortDayName(d->date.dayOfWeek());
02132         buf += QLatin1Char(' ');
02133         buf += d->date.shortMonthName(d->date.month());
02134         buf += QLatin1Char(' ');
02135         buf += QString::number(d->date.day());
02136 #else
02137         QString winstr;
02138         QT_WA({
02139             TCHAR out[255];
02140             GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_ILDATE, out, 255);
02141             winstr = QString::fromUtf16((ushort*)out);
02142         } , {
02143             char out[255];
02144             GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ILDATE, (char*)&out, 255);
02145             winstr = QString::fromLocal8Bit(out);
02146         });
02147         switch (winstr.toInt()) {
02148         case 1:
02149             buf = d->date.shortDayName(d->date.dayOfWeek());
02150             buf += QLatin1Char(' ');
02151             buf += QString::number(d->date.day());
02152             buf += QLatin1String(". ");
02153             buf += d->date.shortMonthName(d->date.month());
02154             break;
02155         default:
02156             buf = d->date.shortDayName(d->date.dayOfWeek());
02157             buf += QLatin1Char(' ');
02158             buf += d->date.shortMonthName(d->date.month());
02159             buf += QLatin1Char(' ');
02160             buf += QString::number(d->date.day());
02161         }
02162 #endif
02163         buf += QLatin1Char(' ');
02164         buf += d->time.toString();
02165         buf += QLatin1Char(' ');
02166         buf += QString::number(d->date.year());
02167     }
02168 #endif
02169     else if (f == Qt::LocaleDate || f == Qt::SystemLocaleDate) {
02170         buf = d->date.toString(f);
02171         if (buf.isEmpty())
02172             return QString();   // failed to convert
02173         buf += QLatin1Char(' ');
02174         buf += d->time.toString(f);
02175     }
02176     return buf;
02177 }
02178 
02246 QString QDateTime::toString(const QString& format) const
02247 {
02248     return fmtDateTime(format, &d->time, &d->date);
02249 }
02250 #endif //QT_NO_DATESTRING
02251 
02260 QDateTime QDateTime::addDays(int ndays) const
02261 {
02262     return QDateTime(d->date.addDays(ndays), d->time, timeSpec());
02263 }
02264 
02273 QDateTime QDateTime::addMonths(int nmonths) const
02274 {
02275     return QDateTime(d->date.addMonths(nmonths), d->time, timeSpec());
02276 }
02277 
02286 QDateTime QDateTime::addYears(int nyears) const
02287 {
02288     return QDateTime(d->date.addYears(nyears), d->time, timeSpec());
02289 }
02290 
02291 
02292 QDateTime QDateTimePrivate::addMSecs(const QDateTime &dt, qint64 msecs)
02293 {
02294     QDate utcDate;
02295     QTime utcTime;
02296     dt.d->getUTC(utcDate, utcTime);
02297 
02298     uint dd = utcDate.jd;
02299     int tt = utcTime.ds();
02300     int sign = 1;
02301     if (msecs < 0) {
02302         msecs = -msecs;
02303         sign = -1;
02304     }
02305     if (msecs >= int(MSECS_PER_DAY)) {
02306         dd += sign * (msecs / MSECS_PER_DAY);
02307         msecs %= MSECS_PER_DAY;
02308     }
02309 
02310     tt += sign * msecs;
02311     if (tt < 0) {
02312         tt = MSECS_PER_DAY - tt - 1;
02313         dd -= tt / MSECS_PER_DAY;
02314         tt = tt % MSECS_PER_DAY;
02315         tt = MSECS_PER_DAY - tt - 1;
02316     } else if (tt >= int(MSECS_PER_DAY)) {
02317         dd += tt / MSECS_PER_DAY;
02318         tt = tt % MSECS_PER_DAY;
02319     }
02320 
02321     utcDate.jd = dd;
02322     utcTime.mds = tt;
02323     return QDateTime(utcDate, utcTime, Qt::UTC).toTimeSpec(dt.timeSpec());
02324 }
02325 
02334 QDateTime QDateTime::addSecs(int nsecs) const
02335 {
02336     return d->addMSecs(*this, qint64(nsecs) * 1000);
02337 }
02338 
02346 QDateTime QDateTime::addMSecs(qint64 msecs) const
02347 {
02348     return d->addMSecs(*this, msecs);
02349 }
02350 
02359 int QDateTime::daysTo(const QDateTime &other) const
02360 {
02361     return d->date.daysTo(other.d->date);
02362 }
02363 
02383 int QDateTime::secsTo(const QDateTime &other) const
02384 {
02385     QDate date1, date2;
02386     QTime time1, time2;
02387 
02388     d->getUTC(date1, time1);
02389     other.d->getUTC(date2, time2);
02390 
02391     return (date1.daysTo(date2) * SECS_PER_DAY) + time1.secsTo(time2);
02392 }
02393 
02403 QDateTime QDateTime::toTimeSpec(Qt::TimeSpec spec) const
02404 {
02405     if ((d->spec == QDateTimePrivate::UTC) == (spec == Qt::UTC))
02406         return *this;
02407 
02408     QDateTime ret;
02409     if (spec == Qt::UTC) {
02410         d->getUTC(ret.d->date, ret.d->time);
02411         ret.d->spec = QDateTimePrivate::UTC;
02412     } else {
02413         ret.d->spec = d->getLocal(ret.d->date, ret.d->time);
02414     }
02415     return ret;
02416 }
02417 
02425 bool QDateTime::operator==(const QDateTime &other) const
02426 {
02427     if (d->spec != other.d->spec) {
02428         if (d->spec == QDateTimePrivate::UTC || other.d->spec == QDateTimePrivate::UTC)
02429             return false;
02430         if (d->spec != QDateTimePrivate::LocalUnknown
02431                 && other.d->spec != QDateTimePrivate::LocalUnknown)
02432             return false;
02433 
02434         QDate date1, date2;
02435         QTime time1, time2;
02436         d->getUTC(date1, time1);
02437         other.d->getUTC(date2, time2);
02438         return time1 == time2 && date1 == date2;
02439     } else {
02440         return d->time == other.d->time && d->date == other.d->date;
02441     }
02442 }
02443 
02461 bool QDateTime::operator<(const QDateTime &other) const
02462 {
02463     if (d->spec == other.d->spec) {
02464         if (d->date != other.d->date)
02465             return d->date < other.d->date;
02466         return d->time < other.d->time;
02467     } else {
02468         QDate date1, date2;
02469         QTime time1, time2;
02470         d->getUTC(date1, time1);
02471         other.d->getUTC(date2, time2);
02472         if (date1 != date2)
02473             return date1 < date2;
02474         return time1 < time2;
02475     }
02476 }
02477 
02506 QDateTime QDateTime::currentDateTime()
02507 {
02508 #if defined(Q_OS_WIN)
02509     QDate d;
02510     QTime t;
02511     SYSTEMTIME st;
02512     memset(&st, 0, sizeof(SYSTEMTIME));
02513     GetLocalTime(&st);
02514     d.jd = julianDayFromDate(st.wYear, st.wMonth, st.wDay);
02515     t.mds = MSECS_PER_HOUR * st.wHour + MSECS_PER_MIN * st.wMinute + 1000 * st.wSecond
02516             + st.wMilliseconds;
02517     return QDateTime(d, t);
02518 #else
02519     QDateTime dt;
02520     QTime t;
02521     dt.setDate(QDate::currentDate());
02522     t = QTime::currentTime();
02523     if (t.ds() < MSECS_PER_MIN)                // midnight or right after?
02524         dt.setDate(QDate::currentDate());          // fetch date again
02525     dt.setTime(t);
02526     return dt;
02527 #endif
02528 }
02529 
02540 QDateTime QDateTime::fromTime_t(uint seconds)
02541 {
02542     QDateTime d;
02543     d.setTime_t(seconds);
02544     return d;
02545 }
02546 
02547 #ifndef QT_NO_DATESTRING
02548 
02560 QDateTime QDateTime::fromString(const QString& s, Qt::DateFormat f)
02561 {
02562     if (s.isEmpty() || f == Qt::LocalDate) {
02563         qWarning("QDateTime::fromString: Parameter out of range");
02564         return QDateTime();
02565     }
02566     if (f == Qt::ISODate) {
02567         QString tmp = s;
02568         Qt::TimeSpec ts = Qt::LocalTime;
02569 
02570         // Recognize UTC specifications
02571         if (tmp.endsWith(QLatin1Char('Z'))) {
02572             ts = Qt::UTC;
02573             tmp.chop(1);
02574         }
02575         return QDateTime(QDate::fromString(tmp.mid(0, 10), Qt::ISODate),
02576                          QTime::fromString(tmp.mid(11), Qt::ISODate), ts);
02577     }
02578 #if !defined(QT_NO_REGEXP) && !defined(QT_NO_TEXTDATE)
02579     else if (f == Qt::TextDate) {
02580         QString monthName(s.mid(4, 3));
02581         int month = -1;
02582         // Assume that English monthnames are the default
02583         for (int i = 0; i < 12; ++i) {
02584             if (monthName == QLatin1String(qt_shortMonthNames[i])) {
02585                 month = i + 1;
02586                 break;
02587             }
02588         }
02589         // If English names can't be found, search the localized ones
02590         if (month == -1) {
02591             for (int i = 1; i <= 12; ++i) {
02592                 if (monthName == QDate::shortMonthName(i)) {
02593                     month = i;
02594                     break;
02595                 }
02596             }
02597         }
02598         if (month < 1 || month > 12) {
02599             qWarning("QDateTime::fromString: Parameter out of range");
02600             return QDateTime();
02601         }
02602         int day = s.mid(8, 2).simplified().toInt();
02603         int yearPos = s.lastIndexOf(QLatin1Char(' ')) + 1;
02604         int year = s.mid(yearPos).toInt();
02605         QDate date = strictDate(year, month, day);
02606         QTime time;
02607         int hour, minute, second;
02608         int pivot = s.indexOf(QRegExp(QString::fromLatin1("[0-9][0-9]:[0-9][0-9]:[0-9][0-9]")));
02609         if (pivot != -1) {
02610             hour = s.mid(pivot, 2).toInt();
02611             minute = s.mid(pivot + 3, 2).toInt();
02612             second = s.mid(pivot + 6, 2).toInt();
02613             time.setHMS(hour, minute, second);
02614         }
02615         return QDateTime(date, time);
02616     }
02617 #endif //QT_NO_REGEXP
02618     return QDateTime();
02619 }
02620 
02727 QDateTime QDateTime::fromString(const QString &string, const QString &format)
02728 {
02729 #ifndef QT_BOOTSTRAPPED
02730     QTime time;
02731     QDate date;
02732 
02733     QDateTimeParser dt(QVariant::DateTime);
02734     if (dt.parseFormat(format) && dt.fromString(string, &date, &time))
02735         return QDateTime(date, time);
02736 #else
02737     Q_UNUSED(string);
02738     Q_UNUSED(format);
02739 #endif
02740     return QDateTime(QDate(), QTime(-1, -1, -1));
02741 }
02742 
02743 #endif // QT_NO_DATESTRING
02744 
02764 void QDateTime::detach()
02765 {
02766     qAtomicDetach(d);
02767 }
02768 
02769 /*****************************************************************************
02770   Date/time stream functions
02771  *****************************************************************************/
02772 
02773 #ifndef QT_NO_DATASTREAM
02774 
02782 QDataStream &operator<<(QDataStream &out, const QDate &date)
02783 {
02784     return out << (quint32)(date.jd);
02785 }
02786 
02795 QDataStream &operator>>(QDataStream &in, QDate &date)
02796 {
02797     quint32 jd;
02798     in >> jd;
02799     date.jd = jd;
02800     return in;
02801 }
02802 
02811 QDataStream &operator<<(QDataStream &out, const QTime &time)
02812 {
02813     return out << quint32(time.mds);
02814 }
02815 
02824 QDataStream &operator>>(QDataStream &in, QTime &time)
02825 {
02826     quint32 ds;
02827     in >> ds;
02828     time.mds = int(ds);
02829     return in;
02830 }
02831 
02839 QDataStream &operator<<(QDataStream &out, const QDateTime &dateTime)
02840 {
02841     out << dateTime.d->date << dateTime.d->time;
02842     if (out.version() >= 7)
02843         out << (qint8)dateTime.d->spec;
02844     return out;
02845 }
02846 
02855 QDataStream &operator>>(QDataStream &in, QDateTime &dateTime)
02856 {
02857     dateTime.detach();
02858 
02859     qint8 ts = (qint8)QDateTimePrivate::LocalUnknown;
02860     in >> dateTime.d->date >> dateTime.d->time;
02861     if (in.version() >= 7)
02862         in >> ts;
02863     dateTime.d->spec = (QDateTimePrivate::Spec)ts;
02864     return in;
02865 }
02866 #endif // QT_NO_DATASTREAM
02867 
02868 
02938 // checks if there is an unqoted 'AP' or 'ap' in the string
02939 static bool hasUnquotedAP(const QString &f)
02940 {
02941     const QLatin1Char quote('\'');
02942     bool inquote = false;
02943     for (int i=0; i < f.size(); ++i) {
02944         if (f.at(i) == quote) {
02945             inquote = !inquote;
02946         } else if (!inquote && f.at(i).toUpper() == QLatin1Char('A')) {
02947             return true;
02948         }
02949     }
02950     return false;
02951 }
02952 
02953 #ifndef QT_NO_DATESTRING
02954 /*****************************************************************************
02955   Some static function used by QDate, QTime and QDateTime
02956 *****************************************************************************/
02957 
02958 // Replaces tokens by their value. See QDateTime::toString() for a list of valid tokens
02959 static QString getFmtString(const QString& f, const QTime* dt = 0, const QDate* dd = 0, bool am_pm = false)
02960 {
02961     if (f.isEmpty())
02962         return QString();
02963 
02964     QString buf = f;
02965     int removed = 0;
02966 
02967     if (dt) {
02968         if (f.startsWith(QLatin1String("hh")) || f.startsWith(QLatin1String("HH"))) {
02969             const bool hour12 = f.at(0) == QLatin1Char('h') && am_pm;
02970             if (hour12 && dt->hour() > 12)
02971                 buf = QString::number(dt->hour() - 12).rightJustified(2, QLatin1Char('0'), true);
02972             else if (hour12 && dt->hour() == 0)
02973                 buf = QLatin1String("12");
02974             else
02975                 buf = QString::number(dt->hour()).rightJustified(2, QLatin1Char('0'), true);
02976             removed = 2;
02977         } else if (f.at(0) == QLatin1Char('h') || f.at(0) == QLatin1Char('H')) {
02978             const bool hour12 = f.at(0) == QLatin1Char('h') && am_pm;
02979             if (hour12 && dt->hour() > 12)
02980                 buf = QString::number(dt->hour() - 12);
02981             else if (hour12 && dt->hour() == 0)
02982                 buf = QLatin1String("12");
02983             else
02984                 buf = QString::number(dt->hour());
02985             removed = 1;
02986         } else if (f.startsWith(QLatin1String("mm"))) {
02987             buf = QString::number(dt->minute()).rightJustified(2, QLatin1Char('0'), true);
02988             removed = 2;
02989         } else if (f.at(0) == (QLatin1Char('m'))) {
02990             buf = QString::number(dt->minute());
02991             removed = 1;
02992         } else if (f.startsWith(QLatin1String("ss"))) {
02993             buf = QString::number(dt->second()).rightJustified(2, QLatin1Char('0'), true);
02994             removed = 2;
02995         } else if (f.at(0) == QLatin1Char('s')) {
02996             buf = QString::number(dt->second());
02997         } else if (f.startsWith(QLatin1String("zzz"))) {
02998             buf = QString::number(dt->msec()).rightJustified(3, QLatin1Char('0'), true);
02999             removed = 3;
03000         } else if (f.at(0) == QLatin1Char('z')) {
03001             buf = QString::number(dt->msec());
03002             removed = 1;
03003         } else if (f.at(0).toUpper() == QLatin1Char('A')) {
03004             const bool upper = f.at(0) == QLatin1Char('A');
03005             buf = dt->hour() < 12 ? QLatin1String("am") : QLatin1String("pm");
03006             if (upper)
03007                 buf = buf.toUpper();
03008             if (f.size() > 1 && f.at(1).toUpper() == QLatin1Char('P') &&
03009                 f.at(0).isUpper() == f.at(1).isUpper()) {
03010                 removed = 2;
03011             } else {
03012                 removed = 1;
03013             }
03014         }
03015     }
03016 
03017     if (dd) {
03018         if (f.startsWith(QLatin1String("dddd"))) {
03019             buf = dd->longDayName(dd->dayOfWeek());
03020             removed = 4;
03021         } else if (f.startsWith(QLatin1String("ddd"))) {
03022             buf = dd->shortDayName(dd->dayOfWeek());
03023             removed = 3;
03024         } else if (f.startsWith(QLatin1String("dd"))) {
03025             buf = QString::number(dd->day()).rightJustified(2, QLatin1Char('0'), true);
03026             removed = 2;
03027         } else if (f.at(0) == QLatin1Char('d')) {
03028             buf = QString::number(dd->day());
03029             removed = 1;
03030         } else if (f.startsWith(QLatin1String("MMMM"))) {
03031             buf = dd->longMonthName(dd->month());
03032             removed = 4;
03033         } else if (f.startsWith(QLatin1String("MMM"))) {
03034             buf = dd->shortMonthName(dd->month());
03035             removed = 3;
03036         } else if (f.startsWith(QLatin1String("MM"))) {
03037             buf = QString::number(dd->month()).rightJustified(2, QLatin1Char('0'), true);
03038             removed = 2;
03039         } else if (f.at(0) == QLatin1Char('M')) {
03040             buf = QString::number(dd->month());
03041             removed = 1;
03042         } else if (f.startsWith(QLatin1String("yyyy"))) {
03043             buf = QString::number(dd->year());
03044             removed = 4;
03045         } else if (f.startsWith(QLatin1String("yy"))) {
03046             buf = QString::number(dd->year()).right(2);
03047             removed = 2;
03048         }
03049     }
03050     if (removed == 0 || removed >= f.size()) {
03051         return buf;
03052     }
03053 
03054     return buf + getFmtString(f.mid(removed), dt, dd, am_pm);
03055 }
03056 
03057 // Parses the format string and uses getFmtString to get the values for the tokens. Ret
03058 static QString fmtDateTime(const QString& f, const QTime* dt, const QDate* dd)
03059 {
03060     const QLatin1Char quote('\'');
03061     if (f.isEmpty())
03062         return QString();
03063     if (dt && !dt->isValid())
03064         return QString();
03065     if (dd && !dd->isValid())
03066         return QString();
03067 
03068     const bool ap = hasUnquotedAP(f);
03069 
03070     QString buf;
03071     QString frm;
03072     QChar status = QLatin1Char('0');
03073 
03074     for (int i = 0; i < (int)f.length(); ++i) {
03075         if (f.at(i) == quote) {
03076             if (status == quote) {
03077                 status = QLatin1Char('0');
03078             } else {
03079                 if (!frm.isEmpty()) {
03080                     buf += getFmtString(frm, dt, dd, ap);
03081                     frm.clear();
03082                 }
03083                 status = quote;
03084             }
03085         } else if (status == quote) {
03086             buf += f.at(i);
03087         } else if (f.at(i) == status) {
03088             if ((ap) && ((f.at(i) == QLatin1Char('P')) || (f.at(i) == QLatin1Char('p'))))
03089                 status = QLatin1Char('0');
03090             frm += f.at(i);
03091         } else {
03092             buf += getFmtString(frm, dt, dd, ap);
03093             frm.clear();
03094             if ((f.at(i) == QLatin1Char('h')) || (f.at(i) == QLatin1Char('m'))
03095                 || (f.at(i) == QLatin1Char('H'))
03096                 || (f.at(i) == QLatin1Char('s')) || (f.at(i) == QLatin1Char('z'))) {
03097                 status = f.at(i);
03098                 frm += f.at(i);
03099             } else if ((f.at(i) == QLatin1Char('d')) || (f.at(i) == QLatin1Char('M')) || (f.at(i) == QLatin1Char('y'))) {
03100                 status = f.at(i);
03101                 frm += f.at(i);
03102             } else if ((ap) && (f.at(i) == QLatin1Char('A'))) {
03103                 status = QLatin1Char('P');
03104                 frm += f.at(i);
03105             } else  if((ap) && (f.at(i) == QLatin1Char('a'))) {
03106                 status = QLatin1Char('p');
03107                 frm += f.at(i);
03108             } else {
03109                 buf += f.at(i);
03110                 status = QLatin1Char('0');
03111             }
03112         }
03113     }
03114 
03115     buf += getFmtString(frm, dt, dd, ap);
03116 
03117     return buf;
03118 }
03119 #endif // QT_NO_DATESTRING
03120 
03121 #ifdef Q_OS_WIN
03122 static const int LowerYear = 1980;
03123 #else
03124 static const int LowerYear = 1970;
03125 #endif
03126 
03127 static QDateTimePrivate::Spec utcToLocal(QDate &date, QTime &time)
03128 {
03129     QDate lowerLimit(LowerYear, 1, 2);
03130     QDate upperLimit(2037, 12, 30);
03131 
03132     QDate fakeDate = date;
03133 
03134     if (fakeDate < lowerLimit) {
03135         fakeDate = lowerLimit;
03136     } else if (fakeDate > upperLimit) {
03137         fakeDate = upperLimit;
03138     }
03139 
03140     time_t secsSince1Jan1970UTC = toTime_t(fakeDate, time);
03141     tm *brokenDown = 0;
03142 
03143 #if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS)
03144     // use the reentrant version of localtime() where available
03145     tm res;
03146     brokenDown = localtime_r(&secsSince1Jan1970UTC, &res);
03147 #elif defined(_MSC_VER) && _MSC_VER >= 1400
03148     tm res;
03149     if (!_localtime64_s(&res, &secsSince1Jan1970UTC))
03150         brokenDown = &res;
03151 #else
03152     brokenDown = localtime(&secsSince1Jan1970UTC);
03153 #endif
03154     if (!brokenDown) {
03155         date = QDate(1970, 1, 1);
03156         time = QTime();
03157         return QDateTimePrivate::LocalUnknown;
03158     } else {
03159         int deltaDays = fakeDate.daysTo(date);
03160         date = QDate(brokenDown->tm_year + 1900, brokenDown->tm_mon + 1, brokenDown->tm_mday);
03161         time = QTime(brokenDown->tm_hour, brokenDown->tm_min, brokenDown->tm_sec, time.msec());
03162         date = date.addDays(deltaDays);
03163         if (brokenDown->tm_isdst > 0)
03164             return QDateTimePrivate::LocalDST;
03165         else if (brokenDown->tm_isdst < 0)
03166             return QDateTimePrivate::LocalUnknown;
03167         else
03168             return QDateTimePrivate::LocalStandard;
03169     }
03170 }
03171 
03172 static void localToUtc(QDate &date, QTime &time, int isdst)
03173 {
03174     if (!date.isValid())
03175         return;
03176 
03177     QDate lowerLimit(LowerYear, 1, 2);
03178     QDate upperLimit(2037, 12, 30);
03179 
03180     QDate fakeDate = date;
03181 
03182     if (fakeDate < lowerLimit) {
03183         fakeDate = lowerLimit;
03184         isdst = false;
03185     } else if (fakeDate > upperLimit) {
03186         fakeDate = upperLimit;
03187         isdst = false;
03188     }
03189 
03190     tm localTM;
03191     localTM.tm_sec = time.second();
03192     localTM.tm_min = time.minute();
03193     localTM.tm_hour = time.hour();
03194     localTM.tm_mday = fakeDate.day();
03195     localTM.tm_mon = fakeDate.month() - 1;
03196     localTM.tm_year = fakeDate.year() - 1900;
03197     localTM.tm_isdst = (int)isdst;
03198 
03199     time_t secsSince1Jan1970UTC = mktime(&localTM);
03200     tm *brokenDown = 0;
03201 
03202 #if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS)
03203     // use the reentrant version of gmtime() where available
03204     tm res;
03205     brokenDown = gmtime_r(&secsSince1Jan1970UTC, &res);
03206 #elif defined(_MSC_VER) && _MSC_VER >= 1400
03207     tm res;
03208     if (!_gmtime64_s(&res, &secsSince1Jan1970UTC))
03209         brokenDown = &res;
03210 #else
03211     brokenDown = gmtime(&secsSince1Jan1970UTC);
03212 #endif // !QT_NO_THREAD && _POSIX_THREAD_SAFE_FUNCTIONS
03213     if (!brokenDown) {
03214         date = QDate(1970, 1, 1);
03215         time = QTime();
03216     } else {
03217         int deltaDays = fakeDate.daysTo(date);
03218         date = QDate(brokenDown->tm_year + 1900, brokenDown->tm_mon + 1, brokenDown->tm_mday);
03219         time = QTime(brokenDown->tm_hour, brokenDown->tm_min, brokenDown->tm_sec, time.msec());
03220         date = date.addDays(deltaDays);
03221     }
03222 }
03223 
03224 QDateTimePrivate::Spec QDateTimePrivate::getLocal(QDate &outDate, QTime &outTime) const
03225 {
03226     outDate = date;
03227     outTime = time;
03228     if (spec == QDateTimePrivate::UTC)
03229         return utcToLocal(outDate, outTime);
03230     return spec;
03231 }
03232 
03233 void QDateTimePrivate::getUTC(QDate &outDate, QTime &outTime) const
03234 {
03235     outDate = date;
03236     outTime = time;
03237     if (spec != QDateTimePrivate::UTC)
03238         localToUtc(outDate, outTime, (int)spec);
03239 }
03240 
03241 #if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_NO_DATESTRING)
03242 QDebug operator<<(QDebug dbg, const QDate &date)
03243 {
03244     dbg.nospace() << "QDate(" << date.toString() << ")";
03245     return dbg.space();
03246 }
03247 
03248 QDebug operator<<(QDebug dbg, const QTime &time)
03249 {
03250     dbg.nospace() << "QTime(" << time.toString() << ")";
03251     return dbg.space();
03252 }
03253 
03254 QDebug operator<<(QDebug dbg, const QDateTime &date)
03255 {
03256     dbg.nospace() << "QDateTime(" << date.toString() << ")";
03257     return dbg.space();
03258 }
03259 #endif
03260 
03261 #ifndef QT_BOOTSTRAPPED
03262 bool QDateTimeParser::isSpecial(const QChar &c) const
03263 {
03264     switch (c.cell()) {
03265     case 'd': case 'M': case 'y':
03266         return (typ == QVariant::Date || typ == QVariant::DateTime);
03267     case 'H': case 'h': case 'm': case 's': case 'z': case 'a': case 'p': case 'A':
03268         return (typ == QVariant::Time || typ == QVariant::DateTime);
03269     case '\'': return true;
03270     default: return false;
03271     }
03272 }
03273 
03274 
03284 int QDateTimeParser::getDigit(const QVariant &t, Section s) const
03285 {
03286     switch (s) {
03287     case Hour24Section: case Hour12Section: return t.toTime().hour();
03288     case MinuteSection: return t.toTime().minute();
03289     case SecondSection: return t.toTime().second();
03290     case MSecSection: return t.toTime().msec();
03291     case YearSection: return t.toDate().year();
03292     case MonthSection: return t.toDate().month();
03293     case DaySection: return t.toDate().day();
03294     case AmPmSection: return t.toTime().hour() > 11 ? 1 : 0;
03295 
03296     default: break;
03297     }
03298     qFatal("%s passed to getDigit. This should never happen", sectionName(s).toLatin1().constData());
03299     return -1;
03300 }
03301 
03314 void QDateTimeParser::setDigit(QVariant &v, Section section, int newVal) const
03315 {
03316     int year, month, day, hour, minute, second, msec;
03317     const QDateTime &dt = v.toDateTime();
03318     year = dt.date().year();
03319     month = dt.date().month();
03320     day = dt.date().day();
03321     hour = dt.time().hour();
03322     minute = dt.time().minute();
03323     second = dt.time().second();
03324     msec = dt.time().msec();
03325 
03326     switch (section) {
03327     case Hour24Section: case Hour12Section: hour = newVal; break;
03328     case MinuteSection: minute = newVal; break;
03329     case SecondSection: second = newVal; break;
03330     case MSecSection: msec = newVal; break;
03331     case YearSection: year = newVal; break;
03332     case MonthSection: month = newVal; break;
03333     case DaySection: day = newVal; break;
03334     case AmPmSection: hour = (newVal == 0 ? hour % 12 : (hour % 12) + 12); break;
03335     default:
03336         qFatal("%s passed to setDigit. This should never happen", sectionName(section).toLatin1().constData());
03337         break;
03338     }
03339 
03340     if (section != DaySection) {
03341         day = qMax<int>(cachedDay, day);
03342     }
03343 
03344     v = QVariant(QDateTime(fixedDate(year, month, day), QTime(hour, minute, second, msec)));
03345 }
03346 
03347 
03348 
03355 int QDateTimeParser::absoluteMax(int s) const
03356 {
03357     const SectionNode sn = sectionNode(s);
03358     switch (sn.type) {
03359     case Hour24Section:
03360     case Hour12Section: return 23; // this is special-cased in parseSection. We want it to be 23 for the stepBy case.
03361     case MinuteSection:
03362     case SecondSection: return 59;
03363     case MSecSection: return 999;
03364     case YearSection: return sn.count == 2 ? 99 : 9999;
03365     case MonthSection: return 12;
03366     case DaySection: return 31;
03367     case AmPmSection: return 1;
03368     default: break;
03369     }
03370     qFatal("%s passed to max. This should never happen", sectionName(s).toLatin1().constData());
03371     return -1;
03372 
03373 }
03374 
03381 int QDateTimeParser::absoluteMin(int s) const
03382 {
03383     const SectionNode sn = sectionNode(s);
03384     switch (sn.type){
03385     case Hour24Section:
03386     case Hour12Section:
03387     case MinuteSection:
03388     case SecondSection:
03389     case MSecSection:
03390     case YearSection: return 0;
03391     case MonthSection:
03392     case DaySection: return 1;
03393     case AmPmSection: return 0;
03394     default: break;
03395     }
03396     qFatal("%s passed to min. This should never happen", sectionName(s).toLatin1().constData());
03397     return -1;
03398 }
03399 
03406 QDateTimeParser::SectionNode QDateTimeParser::sectionNode(int sectionIndex) const
03407 {
03408     if (sectionIndex == FirstSectionIndex) {
03409         return first;
03410     } else if (sectionIndex == LastSectionIndex) {
03411         return last;
03412     } else if (sectionIndex == NoSectionIndex) {
03413         return none;
03414     }
03415     Q_ASSERT(sectionIndex >= 0 && sectionIndex < sectionNodes.size());
03416     return sectionNodes.at(sectionIndex);
03417 }
03418 
03419 QDateTimeParser::Section QDateTimeParser::sectionType(int sectionIndex) const
03420 {
03421     return sectionNode(sectionIndex).type;
03422 }
03423 
03424 
03431 int QDateTimeParser::sectionPos(int sectionIndex) const
03432 {
03433     return sectionPos(sectionNode(sectionIndex));
03434 }
03435 
03436 int QDateTimeParser::sectionPos(const SectionNode &sn) const
03437 {
03438     switch (sn.type) {
03439     case FirstSection: return 0;
03440     case LastSection: return displayText().size() - 1;
03441     default: break;
03442     }
03443     if (sn.pos == -1)
03444         QDTPDEBUG << sectionName(sn.type) << sectionNodes.indexOf(sn);
03445     Q_ASSERT(sn.pos != -1);
03446     return sn.pos;
03447 }
03448 
03449 
03456 static QString unquote(const QString &str)
03457 {
03458     const QLatin1Char quote('\'');
03459     const QLatin1Char slash('\\');
03460     const QLatin1Char zero('0');
03461     QString ret;
03462     QChar status = zero;
03463     for (int i=0; i<str.size(); ++i) {
03464         if (str.at(i) == quote) {
03465             if (status != quote) {
03466                 status = quote;
03467             } else if (!ret.isEmpty() && str.at(i - 1) == slash) {
03468                 ret[ret.size() - 1] = quote;
03469             } else {
03470                 status = zero;
03471             }
03472         } else {
03473             ret += str.at(i);
03474         }
03475     }
03476     return ret;
03477 }
03486 static int countRepeat(const QString &str, int index)
03487 {
03488     Q_ASSERT(index >= 0 && index < str.size());
03489     int count = 1;
03490     const QChar ch = str.at(index);
03491     while (index + count < str.size() && str.at(index + count) == ch)
03492         ++count;
03493     return count;
03494 }
03495 
03496 bool QDateTimeParser::parseFormat(const QString &newFormat)
03497 {
03498     const QLatin1Char quote('\'');
03499     const QLatin1Char slash('\\');
03500     const QLatin1Char zero('0');
03501     if (newFormat == displayFormat && !newFormat.isEmpty()) {
03502         return true;
03503     }
03504 
03505     QDTPDEBUGN("parseFormat: %s", newFormat.toLatin1().constData());
03506 
03507     const bool ap = hasUnquotedAP(newFormat);
03508     QList<SectionNode> newSectionNodes;
03509     Sections newDisplay = 0;
03510     QStringList newSeparators;
03511     int i, index = 0;
03512     int add = 0;
03513     QChar status = zero;
03514     for (i = 0; i<newFormat.size(); ++i) {
03515         if (newFormat.at(i) == quote) {
03516             ++add;
03517             if (status != quote) {
03518                 status = quote;
03519             } else if (newFormat.at(i - 1) != slash) {
03520                 status = zero;
03521             }
03522         } else if (i < newFormat.size() && status != quote) {
03523             const int repeat = qMin(4, countRepeat(newFormat, i));
03524             if (isSpecial(newFormat.at(i))) {
03525                 const char sect = newFormat.at(i).toLatin1();
03526                 switch (sect) {
03527                 case 'H':
03528                 case 'h': {
03529                     const Section hour = (ap && sect == 'h') ? Hour12Section : Hour24Section;
03530                     const SectionNode sn = { hour, i - add, qMin(2, repeat) };
03531                     newSectionNodes << sn;
03532                     newSeparators << unquote(newFormat.mid(index, i - index));
03533                     i += sn.count - 1;
03534                     index = i + 1;
03535                     newDisplay |= hour;
03536                     break; }
03537                 case 'm': {
03538                     const SectionNode sn = { MinuteSection, i - add, qMin(2, repeat) };
03539                     newSectionNodes << sn;
03540                     newSeparators << unquote(newFormat.mid(index, i - index));
03541                     i += sn.count - 1;
03542                     index = i + 1;
03543                     newDisplay |= MinuteSection;
03544                     break; }
03545                 case 's': {
03546                     const SectionNode sn = { SecondSection, i - add, qMin(2, repeat) };
03547                     newSectionNodes << sn;
03548                     newSeparators << unquote(newFormat.mid(index, i - index));
03549                     i += qMin(2, repeat) - 1;
03550                     index = i + 1;
03551                     newDisplay |= SecondSection;
03552                     break; }
03553 
03554                 case 'z': {
03555                     const SectionNode sn = { MSecSection, i - add, (repeat < 3 ? 1 : 3) };
03556                     newSectionNodes << sn;
03557                     newSeparators << unquote(newFormat.mid(index, i - index));
03558                     i += sn.count - 1;
03559                     index = i + 1;
03560                     newDisplay |= MSecSection;
03561                     break; }
03562                 case 'A':
03563                 case 'a': {
03564                     const bool cap = newFormat.at(i) == QLatin1Char('A');
03565                     const SectionNode sn = { AmPmSection, i - add, (cap ? 1 : 0) };
03566                     newSectionNodes << sn;
03567                     newSeparators << unquote(newFormat.mid(index, i - index));
03568                     newDisplay |= AmPmSection;
03569                     if (i + 1 < newFormat.size()
03570                         && newFormat.at(i+1) == (cap ? QLatin1Char('P') : QLatin1Char('p'))) {
03571                         ++i;
03572                     }
03573                     index = i + 1;
03574                     break; }
03575                 case 'y':
03576                     if (repeat >= 2) {
03577                         const bool four = repeat >= 4;
03578                         const SectionNode sn = { YearSection, i - add, four ? 4 : 2 };
03579                         newSectionNodes << sn;
03580                         newSeparators << unquote(newFormat.mid(index, i - index));
03581                         i += sn.count - 1;
03582                         index = i + 1;
03583                         newDisplay |= YearSection;
03584                     }
03585                     break;
03586                 case 'M': {
03587                     const SectionNode sn = { MonthSection, i - add, repeat };
03588                     newSectionNodes << sn;
03589                     newSeparators << unquote(newFormat.mid(index, i - index));
03590                     i += sn.count - 1;
03591                     index = i + 1;
03592                     newDisplay |= MonthSection;
03593                     break; }
03594                 case 'd': {
03595                     const SectionNode sn = { DaySection, i - add, repeat };
03596                     newSectionNodes << sn;
03597                     newSeparators << unquote(newFormat.mid(index, i - index));
03598                     i += sn.count - 1;
03599                     index = i + 1;
03600                     newDisplay |= DaySection;
03601                     break; }
03602 
03603                 default:
03604                     break;
03605                 }
03606             }
03607         }
03608     }
03609     if (newSectionNodes.isEmpty() && !allowEmpty) {
03610         return false;
03611     }
03612 
03613     newSeparators << (index < newFormat.size() ? unquote(newFormat.mid(index)) : QString());
03614 
03615     displayFormat = newFormat;
03616     separators = newSeparators;
03617     sectionNodes = newSectionNodes;
03618     display = newDisplay;
03619     last.pos = -1;
03620 
03621 //     for (int i=0; i<sectionNodes.size(); ++i) {
03622 //         QDTPDEBUG << sectionName(sectionNodes.at(i).type) << sectionNodes.at(i).count;
03623 //     }
03624 
03625     QDTPDEBUG << newFormat << displayFormat;
03626     QDTPDEBUGN("separators:\n'%s'", separators.join(QLatin1String("\n")).toLatin1().constData());
03627 
03628     return true;
03629 }
03630 
03637 int QDateTimeParser::sectionSize(int sectionIndex) const
03638 {
03639     if (sectionIndex < 0)
03640         return 0;
03641     Q_ASSERT(sectionIndex < sectionNodes.size());
03642     if (sectionIndex == sectionNodes.size() - 1) {
03643         return displayText().size() - sectionPos(sectionIndex) - separators.last().size();
03644     } else {
03645         return sectionPos(sectionIndex + 1) - sectionPos(sectionIndex)
03646             - separators.at(sectionIndex + 1).size();
03647     }
03648 }
03649 
03650 
03651 int QDateTimeParser::sectionMaxSize(Section s, int count) const
03652 {
03653 #ifndef QT_NO_TEXTDATE
03654     int mcount = 12;
03655     QString(*nameFunction)(int) = 0;
03656 #endif
03657 
03658     switch (s) {
03659     case FirstSection:
03660     case NoSection:
03661     case LastSection: return 0;
03662 
03663     case AmPmSection: {
03664         const int lowerMax = qMin(getAmPmText(AmText, LowerCase).size(),
03665                                   getAmPmText(PmText, LowerCase).size());
03666         const int upperMax = qMin(getAmPmText(AmText, UpperCase).size(),
03667                                   getAmPmText(PmText, UpperCase).size());
03668         return qMin(4, qMin(lowerMax, upperMax));
03669     }
03670 
03671     case Hour24Section:
03672     case Hour12Section:
03673     case MinuteSection:
03674     case SecondSection: return 2;
03675     case DaySection:
03676 #ifdef QT_NO_TEXTDATE
03677         return 2;
03678 #else
03679         if (count <= 2)
03680             return 2;
03681         nameFunction = (count == 4 ? &QDate::longDayName : &QDate::shortDayName);
03682         mcount = 7;
03683         // fall through
03684 #endif
03685     case MonthSection:
03686         if (count <= 2)
03687             return 2;
03688 
03689 #ifdef QT_NO_TEXTDATE
03690         return 2;
03691 #else
03692         if (s == MonthSection) {
03693             nameFunction = count == 4
03694                            ? &QDate::longMonthName : &QDate::shortMonthName;
03695         }
03696         Q_ASSERT(nameFunction);
03697         {
03698             int ret = 0;
03699             for (int i=1; i<=mcount; ++i) {
03700                 ret = qMax(nameFunction(i).size(), ret);
03701             }
03702             return ret;
03703         }
03704 #endif
03705     case MSecSection: return 3;
03706     case YearSection: return count;
03707 
03708     case Internal:
03709     case TimeSectionMask:
03710     case DateSectionMask: qWarning("QDateTimeParser::sectionMaxSize: Invalid section %s", sectionName(s).toLatin1().constData());
03711     }
03712     return -1;
03713 }
03714 
03715 
03716 int QDateTimeParser::sectionMaxSize(int index) const
03717 {
03718     const SectionNode sn = sectionNode(index);
03719     return sectionMaxSize(sn.type, sn.count);
03720 }
03721 
03730 QString QDateTimeParser::sectionText(const QString &text, int sectionIndex, int index) const
03731 {
03732     const SectionNode &sn = sectionNode(sectionIndex);
03733     switch (sn.type) {
03734     case NoSectionIndex:
03735     case FirstSectionIndex:
03736     case LastSectionIndex:
03737         return QString();
03738     default: break;
03739     }
03740 
03741     return text.mid(index, sectionSize(sectionIndex));
03742 }
03743 
03744 #ifndef QT_NO_TEXTDATE
03745 
03753 int QDateTimeParser::parseSection(int sectionIndex, QString &text, int index,
03754                                   State &state, int *usedptr) const
03755 {
03756     state = Invalid;
03757     int num = 0;
03758     const SectionNode sn = sectionNode(sectionIndex);
03759     Q_ASSERT(sn.type != NoSection && sn.type != FirstSection && sn.type != LastSection);
03760 
03761     QString sectiontext = text.mid(index, sectionMaxSize(sectionIndex));
03762 
03763     QDTPDEBUG << "sectionValue for" << sectionName(sn.type)
03764               << "with text" << text << "and st" << sectiontext
03765               << text.mid(index, sectionMaxSize(sectionIndex))
03766               << index;
03767 
03768     int used = 0;
03769     if (false && sectiontext.trimmed().isEmpty()) {
03770         state = Intermediate;
03771     } else {
03772         switch (sn.type) {
03773         case AmPmSection: {
03774             const int ampm = findAmPm(sectiontext, sectionIndex, &used);
03775             switch (ampm) {
03776             case AM: // sectiontext == AM
03777             case PM: // sectiontext == PM
03778                 num = ampm;
03779                 state = Acceptable;
03780                 break;
03781             case PossibleAM: // sectiontext => AM
03782             case PossiblePM: // sectiontext => PM
03783                 num = ampm - 2;
03784                 state = Intermediate;
03785                 break;
03786             case PossibleBoth: // sectiontext => AM|PM
03787                 num = 0;
03788                 state = Intermediate;
03789                 break;
03790             case Neither:
03791                 state = Invalid;
03792                 QDTPDEBUG << "invalid because findAmPm(" << sectiontext << ") returned -1";
03793                 break;
03794             default:
03795                 QDTPDEBUGN("This should never happen(findAmPm returned %d", ampm);
03796                 break;
03797             }
03798             if (state != Invalid) {
03799                 QString str = text;
03800                 text.replace(index, used, sectiontext.left(used));
03801             }
03802             break;
03803         }
03804         case MonthSection:
03805         case DaySection:
03806             if (sn.count >= 3) {
03807                 if (sn.type == MonthSection) {
03808                     num = findMonth(sectiontext.toLower(), 1, sectionIndex, &sectiontext, &used);
03809                 } else {
03810                     num = findDay(sectiontext.toLower(), 1, sectionIndex, &sectiontext, &used);
03811                 }
03812 
03813                 if (num != -1) {
03814                     state = (used == sectiontext.size() ? Acceptable : Intermediate);
03815                     QString str = text;
03816                     text.replace(index, used, sectiontext.left(used));
03817                 } else {
03818                     state = Intermediate;
03819                 }
03820                 break;
03821             }
03822             // fall through
03823         case YearSection:
03824         case Hour12Section:
03825         case Hour24Section:
03826         case MinuteSection:
03827         case SecondSection:
03828         case MSecSection: {
03829             if (sectiontext.isEmpty()) {
03830                 num = 0;
03831                 used = 0;
03832                 state = Intermediate;
03833             } else {
03834                 const int absMax = absoluteMax(sectionIndex);
03835                 QLocale loc;
03836                 bool ok = true;
03837                 int last = -1;
03838                 used = -1;
03839 
03840                 const int max = qMin(sectionMaxSize(sectionIndex), sectiontext.size());
03841                 for (int digits=1; digits<=max; ++digits) {
03842                     if (sectiontext.at(digits - 1).isSpace()) // loc.toUInt will allow spaces at the end
03843                         break;
03844                     int tmp = (int)loc.toUInt(sectiontext.left(digits), &ok, 10);
03845                     if (ok && sn.type == Hour12Section) {
03846                         if (tmp > 12) {
03847                             tmp = -1;
03848                             ok = false;
03849                         } else if (tmp == 12) {
03850                             tmp = 0;
03851                         }
03852                     }
03853                     if (ok && tmp <= absMax) {
03854                         QDTPDEBUG << sectiontext.left(digits) << tmp << digits;
03855                         last = tmp;
03856                         used = digits;
03857                     } else {
03858                         break;
03859                     }
03860                 }
03861                 if (last == -1) {
03862                     const QChar &first = sectiontext.at(0);
03863                     if (separators.at(sectionIndex + 1).startsWith(first)) {
03864                         used = 0;
03865                         state = Intermediate;
03866                     } else {
03867                         state = Invalid;
03868                         QDTPDEBUG << "invalid because" << sectiontext << "can't become a uint" << last << ok;
03869                     }
03870                 } else {
03871                     num += last;
03872                     const bool done = (used == sectionMaxSize(sectionIndex));
03873                     if (num < absoluteMin(sectionIndex)) {
03874                         state = done ? Invalid : Intermediate;
03875                         if (done)
03876                             QDTPDEBUG << "invalid because" << num << "is less than absoluteMin" << absoluteMin(sectionIndex);
03877                     } else if (num > absMax) {
03878                         state = Intermediate;
03879                     } else if (!done && (fieldInfo(sectionIndex) & (FixedWidth|Numeric)) == (FixedWidth|Numeric)) {
03880                         state = Intermediate;
03881                     } else {
03882                         state = Acceptable;
03883                     }
03884                 }
03885             }
03886             break; }
03887         default: qFatal("NoSection or Internal. This should never happen"); break;
03888         }
03889     }
03890 
03891     if (usedptr)
03892         *usedptr = used;
03893 
03894     return (state != Invalid ? num : -1);
03895 }
03896 #endif // QT_NO_TEXTDATE
03897 
03898 #ifndef QT_NO_DATESTRING
03899 
03903 QDateTimeParser::StateNode QDateTimeParser::parse(const QString &inp,
03904                                                   const QVariant &currentValue, bool fixup) const
03905 {
03906     QString input = inp;
03907     State state = Acceptable;
03908     const QVariant maximum = getMaximum();
03909     const QVariant minimum = getMinimum();
03910 
03911     QVariant tmp;
03912     SectionNode sn = {NoSection, 0, false};
03913     int pos = 0;
03914     bool conflicts = false;
03915 
03916 //    QDTPDEBUG << "validateAndInterpret" << input;
03917     {
03918         int year, month, day, hour12, hour, minute, second, msec, ampm, dayofweek, year2digits;
03919         const QDateTime &dt = currentValue.toDateTime();
03920         year = dt.date().year();
03921         year2digits = year % 100;
03922         month = dt.date().month();
03923         day = dt.date().day();
03924         hour = dt.time().hour();
03925         hour12 = -1;
03926         minute = dt.time().minute();
03927         second = dt.time().second();
03928         msec = dt.time().msec();
03929         dayofweek = dt.date().dayOfWeek();
03930         ampm = -1;
03931         QSet<int*> isSet;
03932         int num;
03933         State tmpstate;
03934         int *current;
03935 
03936         state = Acceptable;
03937 
03938         for (int index=0; state != Invalid && index<sectionNodes.size(); ++index) {
03939             QString sep = input.mid(pos, separators.at(index).size());
03940 
03941             if (sep != separators.at(index)) {
03942                 QDTPDEBUG << "invalid because" << sep << "!=" << separators.at(index)
03943                           << index << pos << currentSectionIndex;
03944                 state = Invalid;
03945                 goto end;
03946             }
03947             pos += separators.at(index).size();
03948             sectionNodes[index].pos = pos;
03949             current = 0;
03950             sn = sectionNodes.at(index);
03951             int used;
03952 
03953             num = parseSection(index, input, pos, tmpstate, &used);
03954             QDTPDEBUG << "sectionValue" << sectionName(sectionType(index)) << input
03955                       << "pos" << pos << "used" << used << stateName(tmpstate);
03956             if (fixup && tmpstate == Intermediate && (fieldInfo(index) & (Numeric|FixedWidth)) == (Numeric|FixedWidth) && used < sn.count) {
03957                 input.insert(pos, QString().fill(QLatin1Char('0'), sn.count - used)); // ### ltor?
03958                 num = parseSection(index, input, pos, tmpstate, &used);
03959             }
03960             pos += qMax(0, used);
03961 
03962             state = qMin<State>(state, tmpstate);
03963             QDTPDEBUG << index << sectionName(sectionType(index)) << "is set to"
03964                       << pos << "state is" << stateName(state);
03965 
03966 
03967             if (state != Invalid) {
03968                 switch (sn.type) {
03969                 case Hour24Section: current = &hour; break;
03970                 case Hour12Section: current = &hour12; break;
03971                 case MinuteSection: current = &minute; break;
03972                 case SecondSection: current = &second; break;
03973                 case MSecSection: current = &msec; break;
03974                 case YearSection:
03975                     if (sn.count == 2) {
03976                         current = &year2digits;
03977                     } else {
03978                         current = &year;
03979                     }
03980                     break;
03981                 case MonthSection: current = &month; break;
03982                 case DaySection:
03983                     if (sn.count >= 3) {
03984                         current = &dayofweek;
03985                     } else {
03986                         current = &day; num = qMax<int>(1, num);
03987                     }
03988                     break;
03989                 case AmPmSection: current = &ampm; break;
03990                 default:
03991                     qFatal("%s found in sections validateAndInterpret. This should never happen",
03992                            sectionName(sn.type).toLatin1().constData());
03993                     break;
03994                 }
03995                 Q_ASSERT(current);
03996                 if (isSet.contains(current) && *current != num) {
03997                     QDTPDEBUG << "CONFLICT " << sectionName(sn.type) << *current << num;
03998                     conflicts = true;
03999                     if (index != currentSectionIndex || num == -1) {
04000                         continue;
04001                     }
04002                 }
04003                 if (num != -1)
04004                     *current = num;
04005                 isSet.insert(current);
04006             }
04007         }
04008 
04009         if (state != Invalid && input.mid(pos) != separators.last()) {
04010             QDTPDEBUG << "1invalid because" << input.mid(pos)
04011                       << "!=" << separators.last() << pos;
04012             state = Invalid;
04013         }
04014 
04015         if (state != Invalid) {
04016             if (typ != QVariant::Time) {
04017                 if (year % 100 != year2digits) {
04018                     if (isSet.contains(&year2digits) && !isSet.contains(&year)) {
04019                         year = (year / 100) * 100;
04020                         year += year2digits;
04021                     } else if (isSet.contains(&year2digits) && isSet.contains(&year)) {
04022                         conflicts = true;
04023                         SectionNode sn = sectionNode(currentSectionIndex);
04024                         if (sn.type == YearSection) {
04025                             if (sn.count == 2) {
04026                                 year = (year / 100) * 100;
04027                                 year += year2digits;
04028                             }
04029                         }
04030                     }
04031                 }
04032 
04033                 const QDate date = strictDate(year, month, day);
04034                 const int diff = dayofweek - date.dayOfWeek() && isSet.contains(&dayofweek);
04035                 if (diff != 0 && state == Acceptable) {
04036                     conflicts = true;
04037                     const SectionNode &sn = sectionNode(currentSectionIndex);
04038                     if (sn.type == DaySection && sn.count >= 3) {
04039                         day -= diff;
04040                         if (day < 0) {
04041                             day += 7;
04042                         } else if (day > date.daysInMonth()) {
04043                             day -= 7;
04044                         }
04045                         QDTPDEBUG << year << month << day << dayofweek
04046                                   << diff << strictDate(year, month, day).dayOfWeek();
04047                     }
04048                 }
04049                 bool needfixday = false;
04050                 if (sectionType(currentSectionIndex) == DaySection) {
04051                     cachedDay = day;
04052                 } else if (cachedDay > day) {
04053                     day = cachedDay;
04054                     needfixday = true;
04055                 }
04056 
04057                 if (!QDate::isValid(year, month, day)) {
04058                     if (day < 32) {
04059                         cachedDay = day;
04060                     }
04061                     if (day > 28 && QDate::isValid(year, month, 1)) {
04062                         needfixday = true;
04063                     }
04064                 }
04065                 if (needfixday) {
04066                     if (state == Acceptable && fixday) {
04067                         day = qMin<int>(day, strictDate(year, month, 1).daysInMonth());
04068 
04069                         const QLocale loc;
04070                         for (int i=0; i<sectionNodes.size(); ++i) {
04071                             if (sectionType(i) == DaySection) {
04072                                 input.replace(sectionPos(i), sectionSize(i), loc.toString(day));
04073                             }
04074                         }
04075                     } else {
04076                         state = qMin(Intermediate, state);
04077                     }
04078 
04079                 }
04080             }
04081 
04082             if (typ != QVariant::Date) {
04083                 if (isSet.contains(&hour12)) {
04084                     const bool hasHour = isSet.contains(&hour);
04085                     if (ampm == -1) {
04086                         if (hasHour) {
04087                             ampm = (hour < 12 ? 0 : 1);
04088                         } else {
04089                             ampm = 0; // no way to tell if this is am or pm so I assume am
04090                         }
04091                     }
04092                     hour12 = (ampm == 0 ? hour12 % 12 : (hour12 % 12) + 12);
04093                     if (!hasHour) {
04094                         hour = hour12;
04095                     } else if (hour != hour12) {
04096                         conflicts = true;
04097                     }
04098                 } else if (ampm != -1) {
04099                     if (!isSet.contains(&hour)) {
04100                         hour = (12 * ampm); // special case. Only ap section
04101                     } else if ((ampm == 0) != (hour < 12)) {
04102                         conflicts = true;
04103                     }
04104                 }
04105 
04106             }
04107 
04108             tmp = QVariant(QDateTime(strictDate(year, month, day), QTime(hour, minute, second, msec)));
04109             QDTPDEBUG << year << month << day << hour << minute << second << msec;
04110 
04111         }
04112         QDTPDEBUGN("'%s' => '%s'(%s)", input.toLatin1().constData(),
04113                    tmp.toString().toLatin1().constData(), stateName(state).toLatin1().constData());
04114     }
04115 end:
04116     if (tmp.toDateTime().isValid()) {
04117         if (state != Invalid && dateTimeCompare(tmp, minimum) < 0) {
04118             state = checkIntermediate(tmp.toDateTime(), input);
04119         } else {
04120             if (dateTimeCompare(tmp, maximum) > 0)
04121                 state = Invalid;
04122             QDTPDEBUG << "not checking intermediate because tmp is" << tmp  << minimum << maximum;
04123         }
04124     }
04125     StateNode node;
04126     node.input = input;
04127     node.state = state;
04128     node.conflicts = conflicts;
04129     node.value = tmp;
04130     text = input; // ### do I need this?
04131     return node;
04132 }
04133 #endif // QT_NO_DATESTRING
04134 
04135 #ifndef QT_NO_TEXTDATE
04136 
04141 int QDateTimeParser::findMonth(const QString &str1, int startMonth, int sectionIndex, QString *usedMonth, int *used) const
04142 {
04143     int bestMatch = -1;
04144     int bestCount = 0;
04145     if (!str1.isEmpty()) {
04146         const SectionNode sn = sectionNode(sectionIndex);
04147         Q_ASSERT(sn.type == MonthSection);
04148         QString(*nameFunction)(int) = sn.count == 3
04149                                       ? &QDate::shortMonthName
04150                                       : &QDate::longMonthName;
04151 
04152         for (int month=startMonth; month<=12; ++month) {
04153             for (int attempt=0; attempt<(sn.count == 3 ? 2 : 1); ++attempt) {
04154                 QString str2;
04155                 if (attempt == 0) {
04156                     str2 = nameFunction(month).toLower();
04157                 } else {
04158                     str2 = QString::fromAscii(qt_shortMonthNames[month - 1]).toLower();
04159                 }
04160 
04161                 if (str1.startsWith(str2)) {
04162                     if (used) {
04163                         QDTPDEBUG << "used is set to" << str2.size();
04164                         *used = str2.size();
04165                     }
04166                     if (usedMonth)
04167                         *usedMonth = nameFunction(month);
04168                     return month;
04169                 }
04170 
04171                 const int limit = qMin(str1.size(), str2.size());
04172 
04173                 QDTPDEBUG << "limit is" << limit << str1 << str2;
04174                 bool found = true;
04175                 for (int i=0; i<limit; ++i) {
04176                     if (str1.at(i) != str2.at(i)) {
04177                         if (i > bestCount) {
04178                             bestCount = i;
04179                             bestMatch = month;
04180                         }
04181                         found = false;
04182                         break;
04183                     }
04184 
04185                 }
04186                 if (found) {
04187                     if (used) {
04188                         *used = limit;
04189                     }
04190                     if (usedMonth)
04191                         *usedMonth = nameFunction(month);
04192                     QDTPDEBUG << "used is set to" << limit << *usedMonth;
04193 
04194                     return month;
04195                 }
04196             }
04197         }
04198         if (usedMonth && bestMatch != -1)
04199             *usedMonth = nameFunction(bestMatch);
04200 
04201     }
04202     if (used) {
04203         QDTPDEBUG << "used is set to" << bestCount;
04204         *used = bestCount;
04205     }
04206     return bestMatch;
04207 }
04208 
04209 int QDateTimeParser::findDay(const QString &str1, int startDay, int sectionIndex, QString *usedDay, int *used) const
04210 {
04211     int bestMatch = -1;
04212     int bestCount = 0;
04213     if (!str1.isEmpty()) {
04214     const SectionNode sn = sectionNode(sectionIndex);
04215     Q_ASSERT(sn.type == DaySection);
04216     QString(*nameFunction)(int) = sn.count == 3
04217                                   ? &QDate::shortDayName
04218                                   : &QDate::longDayName;
04219 
04220     for (int day=startDay; day<=7; ++day) {
04221         const QString str2 = nameFunction(day).toLower();
04222 
04223         if (str1.startsWith(str2)) {
04224             if (used)
04225                 *used = str2.size();
04226             if (usedDay)
04227                 *usedDay = nameFunction(day);
04228             return day;
04229         }
04230 
04231         const int limit = qMin(str1.size(), str2.size());
04232         bool found = true;
04233         for (int i=0; i<limit; ++i) {
04234             if (str1.at(i) != str2.at(i) && !str1.at(i).isSpace()) {
04235                 if (i > bestCount) {
04236                     bestCount = i;
04237                     bestMatch = day;
04238                 }
04239                 found = false;
04240                 break;
04241             }
04242 
04243         }
04244         if (found) {
04245             if (used)
04246                 *used = limit;
04247             if (usedDay)
04248                 *usedDay = nameFunction(day);
04249 
04250             return day;
04251         }
04252     }
04253     if (usedDay && bestMatch != -1)
04254         *usedDay = nameFunction(bestMatch);
04255     }
04256     if (used)
04257         *used = bestCount;
04258 
04259     return bestMatch;
04260 }
04261 #endif // QT_NO_TEXTDATE
04262 
04276 int QDateTimeParser::findAmPm(QString &str, int index, int *used) const
04277 {
04278     const SectionNode s = sectionNode(index);
04279     Q_ASSERT(s.type == AmPmSection);
04280     if (used)
04281         *used = str.size();
04282     if (str.trimmed().isEmpty()) {
04283         return PossibleBoth;
04284     }
04285     const QLatin1Char space(' ');
04286     int size = sectionMaxSize(index);
04287 
04288     enum {
04289         amindex = 0,
04290         pmindex = 1
04291     };
04292     QString ampm[2];
04293     ampm[amindex] = getAmPmText(AmText, s.count == 1 ? UpperCase : LowerCase);
04294     ampm[pmindex] = getAmPmText(PmText, s.count == 1 ? UpperCase : LowerCase);
04295     for (int i=0; i<2; ++i)
04296         ampm[i].truncate(size);
04297 
04298     QDTPDEBUG << "findAmPm" << str << ampm[0] << ampm[1];
04299 
04300     if (str.indexOf(ampm[amindex], 0, Qt::CaseInsensitive) == 0) {
04301         str = ampm[amindex];
04302         return AM;
04303     } else if (str.indexOf(ampm[pmindex], 0, Qt::CaseInsensitive) == 0) {
04304         str = ampm[pmindex];
04305         return PM;
04306     } else if (str.count(space) == 0 && str.size() >= size) {
04307         return Neither;
04308     }
04309     size = qMin(size, str.size());
04310 
04311     bool broken[2] = {false, false};
04312     for (int i=0; i<size; ++i) {
04313         if (str.at(i) != space) {
04314             for (int j=0; j<2; ++j) {
04315                 if (!broken[j]) {
04316                     int index = ampm[j].indexOf(str.at(i));
04317                     QDTPDEBUG << "looking for" << str.at(i)
04318                               << "in" << ampm[j] << "and got" << index;
04319                     if (index == -1) {
04320                         if (str.at(i).category() == QChar::Letter_Uppercase) {
04321                             index = ampm[j].indexOf(str.at(i).toLower());
04322                             QDTPDEBUG << "trying with" << str.at(i).toLower()
04323                                       << "in" << ampm[j] << "and got" << index;
04324                         } else if (str.at(i).category() == QChar::Letter_Lowercase) {
04325                             index = ampm[j].indexOf(str.at(i).toUpper());
04326                             QDTPDEBUG << "trying with" << str.at(i).toUpper()
04327                                       << "in" << ampm[j] << "and got" << index;
04328                         }
04329                         if (index == -1) {
04330                             broken[j] = true;
04331                             if (broken[amindex] && broken[pmindex]) {
04332                                 QDTPDEBUG << str << "didn't make it";
04333                                 return Neither;
04334                             }
04335                             continue;
04336                         } else {
04337                             str[i] = ampm[j].at(index); // fix case
04338                         }
04339                     }
04340                     ampm[j].remove(index, 1);
04341                 }
04342             }
04343         }
04344     }
04345     if (!broken[pmindex] && !broken[amindex])
04346         return PossibleBoth;
04347     return (!broken[amindex] ? PossibleAM : PossiblePM);
04348 }
04349 
04355 int QDateTimeParser::maxChange(int index) const
04356 {
04357     const SectionNode sn = sectionNode(index);
04358     switch (sn.type) {
04359         // Time. unit is msec
04360     case MSecSection: return 999;
04361     case SecondSection: return 59 * 1000;
04362     case MinuteSection: return 59 * 60 * 1000;
04363     case Hour24Section: case Hour12Section: return 59 * 60 * 60 * 1000;
04364 
04365         // Date. unit is day
04366     case DaySection: return 30;
04367     case MonthSection: return 365 - 31;
04368     case YearSection: return sn.count == 2
04369             ? 100 * 365
04370             : 9999 * 365;
04371     default: qFatal("%s passed to maxChange. This should never happen", sectionName(sectionType(index)).toLatin1().constData());
04372     }
04373     return -1;
04374 }
04375 
04376 QDateTimeParser::FieldInfo QDateTimeParser::fieldInfo(int index) const
04377 {
04378     FieldInfo ret = 0;
04379     const SectionNode sn = sectionNode(index);
04380     const Section s = sn.type;
04381     switch (s) {
04382     case MSecSection:
04383     case SecondSection:
04384     case MinuteSection:
04385     case Hour24Section:
04386     case Hour12Section:
04387     case YearSection:
04388         ret |= Numeric;
04389         if (s != YearSection) {
04390             ret |= AllowPartial;
04391         }
04392         if (sn.count != 1) {
04393             ret |= FixedWidth;
04394         }
04395         break;
04396     case MonthSection:
04397     case DaySection:
04398         switch (sn.count) {
04399         case 2:
04400             ret |= FixedWidth;
04401         case 1: // fallthrough
04402             ret |= (Numeric|AllowPartial);
04403             break;
04404         case 3:
04405             ret |= FixedWidth;
04406             break;
04407         case 4:
04408             break;
04409         default: qFatal("This should not happen %d %s %d",
04410                         index, qPrintable(sectionName(sn.type)), sn.count);
04411             break;
04412         }
04413         break;
04414     case AmPmSection:
04415         ret |= FixedWidth;
04416         break;
04417     default: qFatal("This should not happen %d %s",
04418                     index, qPrintable(sectionName(sn.type)));
04419     }
04420     return ret;
04421 }
04422 
04423 
04424 
04425 
04432 QString QDateTimeParser::sectionFormat(int index) const
04433 {
04434     const SectionNode sn = sectionNode(index);
04435     return sectionFormat(sn.type, sn.count);
04436 }
04437 
04438 QString QDateTimeParser::sectionFormat(Section s, int count) const
04439 {
04440     QChar fillChar;
04441     switch (s) {
04442     case AmPmSection: return count == 1 ? QLatin1String("AP") : QLatin1String("ap");
04443     case MSecSection: fillChar = QLatin1Char('z'); break;
04444     case SecondSection: fillChar = QLatin1Char('s'); break;
04445     case MinuteSection: fillChar = QLatin1Char('m'); break;
04446     case Hour24Section: fillChar = QLatin1Char('H'); break;
04447     case Hour12Section: fillChar = QLatin1Char('h'); break;
04448     case DaySection: fillChar = QLatin1Char('d'); break;
04449     case MonthSection: fillChar = QLatin1Char('M'); break;
04450     case YearSection: fillChar = QLatin1Char('y'); break;
04451     default:
04452         qFatal("%s passed to sectionFormat. This should never happen", sectionName(s).toLatin1().constData());
04453         return QString();
04454     }
04455     Q_ASSERT(!fillChar.isNull());
04456     QString str;
04457     str.fill(fillChar, count);
04458     return str;
04459 }
04460 
04466 int QDateTimeParser::potentialValue(const QString &str, int min, int max, int index,
04467                                     const QVariant &currentValue, int insert) const
04468 {
04469     const SectionNode sn = sectionNode(index);
04470 
04471     int size = sectionMaxSize(index);
04472     const int add = (sn.type == YearSection && sn.count == 2) ? currentValue.toDate().year() % 100 : 0;
04473     min -= add;
04474     max -= add; // doesn't matter if max is -1 checking for < 0
04475 
04476     const QString simplified = str.simplified();
04477     if (simplified.isEmpty()) {
04478         return min + add;
04479     } else if (simplified.toInt() > max && max >= 0) {
04480         return -1;
04481     }
04482 
04483     const int ret = potentialValueHelper(simplified, min, max, size, insert);
04484     if (ret == -1)
04485         return -1;
04486     return ret + add;
04487 }
04488 
04493 int QDateTimeParser::potentialValueHelper(const QString &str, int min, int max, int size, int insert) const
04494 {
04495     if (str.size() == size) {
04496         const int val = str.toInt();
04497         if (val < min || val > max)
04498             return -1;
04499         QDTPDEBUG << "SUCCESS" << val << "is >=" << min << "and <=" << max;
04500         return val;
04501     }
04502 
04503     for (int i=0; i<=str.size(); ++i) {
04504         for (int j=0; j<10; ++j) {
04505             int ret = potentialValueHelper(str + QLatin1Char('0' + j), min, max, size, insert);
04506             if (ret != -1) {
04507                 return ret;
04508             } else if (insert >= 0) {
04509                 QString tmp = str;
04510                 tmp.insert(insert, QLatin1Char('0' + j));
04511                 ret = potentialValueHelper(tmp, min, max, size, insert);
04512                 if (ret != -1)
04513                     return ret;
04514             }
04515         }
04516     }
04517     return -1;
04518 }
04519 
04520 #ifndef QT_NO_DATESTRING
04521 
04526 QDateTimeParser::State QDateTimeParser::checkIntermediate(const QDateTime &dt, const QString &s) const
04527 {
04528     const QLatin1Char space(' ');
04529 
04530     const QVariant minimum = getMinimum();
04531     const QVariant maximum = getMaximum();
04532     Q_ASSERT(dateTimeCompare(dt, minimum) < 0);
04533 
04534     bool found = false;
04535     for (int i=0; i<sectionNodes.size(); ++i) {
04536         const SectionNode &sn = sectionNodes.at(i);
04537         QString t = sectionText(s, i, sn.pos).toLower();
04538         if (t.contains(space) || t.size() < sectionMaxSize(i)) {
04539             found = true;
04540             switch (sn.type) {
04541             case AmPmSection:
04542                 switch (findAmPm(t, i)) {
04543                 case AM:
04544                 case PM: qFatal("%d This should not happen", __LINE__); return Acceptable;
04545                 case Neither: return Invalid;
04546                 case PossibleAM:
04547                 case PossiblePM:
04548                 case PossibleBoth: {
04549                     const QVariant copy(dt.addSecs(12 * 60 * 60));
04550                     if (dateTimeCompare(copy, minimum) >= 0 && dateTimeCompare(copy, maximum) <= 0)
04551                         return Intermediate;
04552                     return Invalid; }
04553                 }
04554             case MonthSection:
04555                 if (sn.count >= 3) {
04556                     int tmp = dt.date().month();
04557                     // I know the first possible month makes the date too early
04558                     while ((tmp = findMonth(t, tmp + 1, sn.count)) != -1) {
04559                         const QVariant copy(dt.addMonths(tmp - dt.date().month()));
04560                         if (dateTimeCompare(copy, minimum) >= 0 && dateTimeCompare(copy, maximum) <= 0)
04561                             break;
04562                     }
04563                     if (tmp == -1) {
04564                         return Invalid;
04565                     }
04566                 }
04567                 // fallthrough
04568 
04569             default: {
04570                 int toMin;
04571                 int toMax;
04572 
04573                 if (sn.type & TimeSectionMask) {
04574                     if (dt.daysTo(minimum.toDateTime()) != 0) {
04575                         QDTPDEBUG << "if (dt.daysTo(minimum.toDateTime()) != 0)" << dt.daysTo(minimum.toDateTime());
04576                         return Invalid;
04577                     }
04578                     toMin = dt.time().msecsTo(minimum.toDateTime().time());
04579                     if (dt.daysTo(maximum.toDateTime()) > 0) {
04580                         toMax = -1; // can't get to max
04581                     } else {
04582                         toMax = dt.time().msecsTo(maximum.toDateTime().time());
04583                     }
04584                 } else {
04585                     toMin = dt.daysTo(minimum.toDateTime());
04586                     toMax = dt.daysTo(maximum.toDateTime());
04587                 }
04588                 int maxChange = QDateTimeParser::maxChange(i);
04589                 if (toMin > maxChange) {
04590                     QDTPDEBUG << "invalid because toMin > maxChange" << toMin
04591                               << maxChange << t << dt << minimum.toDateTime();
04592 
04593                     return Invalid;
04594                 } else if (toMax > maxChange) {
04595                     toMax = -1; // can't get to max
04596                 }
04597 
04598                 int min = getDigit(minimum, sn.type);
04599                 int max = toMax != -1 ? getDigit(maximum, sn.type) : -1;
04600                 int pos = cursorPosition() - sn.pos;
04601                 if (pos < 0 || pos >= t.size())
04602                     pos = -1;
04603                 int tmp = potentialValue(t, min, max, i, dt, pos);
04604                 QDTPDEBUG << tmp << t << min << max << sectionName(sn.type)
04605                           << minimum.toDate() << maximum.toDate();
04606                 if (tmp == -1) {
04607                     QDTPDEBUG << "invalid because potentialValue(" << t << min << max
04608                               << sectionName(sn.type) << "returned" << tmp << toMax;
04609                     return Invalid;
04610                 } else if (tmp > absoluteMax(i)) {
04611                     QDTPDEBUG << "invalid because potentialValue(" << t << min << max
04612                               << sectionName(sn.type) << "returned a larger number than absoluteMax" << tmp << absoluteMax(i);
04613                     return Invalid;
04614                 }
04615 
04616                 QVariant var(dt);
04617                 setDigit(var, sn.type, tmp);
04618                 if (dateTimeCompare(var, maximum) > 0) {
04619                     QDTPDEBUG << "invalid because" << var.toString() << ">" << maximum.toString();
04620                     return Invalid;
04621                 }
04622                 break; }
04623             }
04624         }
04625     }
04626     return found ? Intermediate : Invalid;
04627 }
04628 #endif // QT_NO_DATESTRING
04629 
04635 QString QDateTimeParser::sectionName(int s) const
04636 {
04637     switch (s) {
04638     case QDateTimeParser::AmPmSection: return QLatin1String("AmPmSection");
04639     case QDateTimeParser::DaySection: return QLatin1String("DaySection");
04640     case QDateTimeParser::Hour24Section: return QLatin1String("Hour24Section");
04641     case QDateTimeParser::Hour12Section: return QLatin1String("Hour12Section");
04642     case QDateTimeParser::MSecSection: return QLatin1String("MSecSection");
04643     case QDateTimeParser::MinuteSection: return QLatin1String("MinuteSection");
04644     case QDateTimeParser::MonthSection: return QLatin1String("MonthSection");
04645     case QDateTimeParser::SecondSection: return QLatin1String("SecondSection");
04646     case QDateTimeParser::YearSection: return QLatin1String("YearSection");
04647     case QDateTimeParser::NoSection: return QLatin1String("NoSection");
04648     case QDateTimeParser::FirstSection: return QLatin1String("FirstSection");
04649     case QDateTimeParser::LastSection: return QLatin1String("LastSection");
04650     default: return QLatin1String("Unknown section ") + QString::number(s);
04651     }
04652 }
04653 
04659 QString QDateTimeParser::stateName(int s) const
04660 {
04661     switch (s) {
04662     case Invalid: return QLatin1String("Invalid");
04663     case Intermediate: return QLatin1String("Intermediate");
04664     case Acceptable: return QLatin1String("Acceptable");
04665     default: return QLatin1String("Unknown state ") + QString::number(s);
04666     }
04667 }
04668 
04669 #ifndef QT_NO_DATESTRING
04670 bool QDateTimeParser::fromString(const QString &text, QDate *date, QTime *time) const
04671 {
04672     QVariant val;
04673     if (date && time) {
04674         val = QDateTime(QDate(1900, 1, 1), QDATETIMEEDIT_TIME_MIN);
04675     } else if (date) {
04676         val = QDate(1900, 1, 1);
04677     } else {
04678         Q_ASSERT(time);
04679         val = QDATETIMEEDIT_TIME_MIN;
04680     }
04681     const StateNode tmp = parse(text, val, false);
04682     if (tmp.state != Acceptable || tmp.conflicts) {
04683         return false;
04684     }
04685     if (time) {
04686         const QTime t = tmp.value.toTime();
04687         if (!t.isValid()) {
04688             return false;
04689         }
04690         *time = t;
04691     }
04692 
04693     if (date) {
04694         const QDate d = tmp.value.toDate();
04695         if (!d.isValid()) {
04696             return false;
04697         }
04698         *date = d;
04699     }
04700     return true;
04701 }
04702 
04703 QVariant QDateTimeParser::getMinimum() const
04704 {
04705     switch (typ) {
04706     case QVariant::Time: return QDATETIMEEDIT_TIME_MIN;
04707     case QVariant::Date: return QDATETIMEEDIT_DATE_MIN;
04708     case QVariant::DateTime: return QDATETIMEEDIT_DATETIME_MIN;
04709     default: break;
04710     }
04711     return QVariant();
04712 }
04713 QVariant QDateTimeParser::getMaximum() const
04714 {
04715     switch (typ) {
04716     case QVariant::Time: return QDATETIMEEDIT_TIME_MAX;
04717     case QVariant::Date: return QDATETIMEEDIT_DATE_MAX;
04718     case QVariant::DateTime: return QDATETIMEEDIT_DATETIME_MAX;
04719     default: break;
04720     }
04721     return QVariant();
04722 }
04723 #endif // QT_NO_DATESTRING
04724 
04725 QString QDateTimeParser::getAmPmText(AmPm ap, Case cs) const
04726 {
04727     if (ap == AmText) {
04728         return (cs == UpperCase ? QLatin1String("AM") : QLatin1String("am"));
04729     } else {
04730         return (cs == UpperCase ? QLatin1String("PM") : QLatin1String("pm"));
04731     }
04732 }
04733 
04734 /*
04735   \internal
04736 
04737   I give arg2 preference because arg1 is always a QDateTime.
04738 */
04739 
04740 int QDateTimeParser::dateTimeCompare(const QVariant &arg1, const QVariant &arg2)
04741 {
04742     if ((arg1.type() == QVariant::Time && arg2.type() == QVariant::Date)
04743         || (arg1.type() == QVariant::Date && arg2.type() == QVariant::Time)) {
04744         qWarning("QDateTimeParser::dateTimeCompare: Different types (%s vs. %s)",
04745                  arg1.typeName(), arg2.typeName());
04746     }
04747     switch (arg2.type()) {
04748     case QVariant::Date:
04749         if (arg1.toDate() == arg2.toDate()) {
04750             return 0;
04751         } else if (arg1.toDate() < arg2.toDate()) {
04752             return -1;
04753         } else {
04754             return 1;
04755         }
04756     case QVariant::Time:
04757         if (arg1.toTime() == arg2.toTime()) {
04758             return 0;
04759         } else if (arg1.toTime() < arg2.toTime()) {
04760             return -1;
04761         } else {
04762             return 1;
04763         }
04764 
04765     case QVariant::DateTime:
04766         if (arg1.toDateTime() == arg2.toDateTime()) {
04767             return 0;
04768         } else if (arg1.toDateTime() < arg2.toDateTime()) {
04769             return -1;
04770         } else {
04771             return 1;
04772         }
04773     default: break;
04774     }
04775     qWarning("QDateTimeParser::dateTimeCompare: Unsupported types (%s, %s)",
04776              arg1.typeName(), arg2.typeName());
04777 
04778     return -2;
04779 }
04780 
04781 bool operator==(const QDateTimeParser::SectionNode &s1, const QDateTimeParser::SectionNode &s2)
04782 {
04783     return (s1.type == s2.type) && (s1.pos == s2.pos) && (s1.count == s2.count);
04784 }
04785 
04786 
04787 #endif // QT_BOOTSTRAPPED

Generated on Thu Mar 15 11:53:44 2007 for Qt 4.2 User's Guide by  doxygen 1.5.1