• Skip to content
  • Skip to link menu
KDE 4.7 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

KDECore

kdatetimeparser.cpp
Go to the documentation of this file.
00001 /*
00002     Copyright 2009, 2010 John Layt <john@layt.net>
00003 
00004     This library is free software; you can redistribute it and/or
00005     modify it under the terms of the GNU Library General Public
00006     License as published by the Free Software Foundation; either
00007     version 2 of the License, or (at your option) any later version.
00008 
00009     This library is distributed in the hope that it will be useful,
00010     but WITHOUT ANY WARRANTY; without even the implied warranty of
00011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012     Library General Public License for more details.
00013 
00014     You should have received a copy of the GNU Library General Public License
00015     along with this library; see the file COPYING.LIB.  If not, write to
00016     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017     Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include "kdatetimeparser_p.h"
00021 
00022 #include "kcalendarsystemprivate_p.h"
00023 #include "kcalendarsystem.h"
00024 #include "kcalendarera_p.h"
00025 
00026 #include "kdebug.h"
00027 
00028 KDateTimeParser::KDateTimeParser()
00029 {
00030 }
00031 
00032 KDateTimeParser::~KDateTimeParser()
00033 {
00034 }
00035 
00036 // Parse a DateTime input string and return just the Date component
00037 QDate KDateTimeParser::parseDate(const QString &inputString,
00038                                  const QString &formatString,
00039                                  const KCalendarSystem *calendar,
00040                                  const KLocale *locale,
00041                                  KLocale::DigitSet digitSet,
00042                                  KLocale::DateTimeFormatStandard formatStandard) const
00043 {
00044     DateTimeComponents result;
00045     if (formatStandard == KLocale::UnicodeFormat) {
00046         result = parseDateUnicode(inputString, formatString, calendar, locale, digitSet);
00047     } else {
00048         result = parseDatePosix(inputString, formatString, calendar, locale, digitSet, formatStandard);
00049     }
00050 
00051     QDate resultDate;
00052 
00053     if (!result.error &&
00054             formatString.simplified().length() <= result.formatPosition &&
00055             inputString.simplified().length() <= result.inputPosition) {
00056 
00057         // If there were no parsing errors, and we have reached the end of both the input and
00058         // format strings, then see if we have a valid date based on the components parsed
00059 
00060         // If we haven't parsed a year component, then assume this year
00061         if (!result.parsedYear) {
00062             result.year = calendar->year(QDate::currentDate());
00063         }
00064 
00065         if ((!result.eraName.isEmpty() || result.yearInEra > -1) && result.month > 0 && result.day > 0) {
00066             // Have parsed Era components as well as month and day components
00067             calendar->setDate(resultDate, result.eraName, result.yearInEra, result.month, result.day);
00068         } else if (result.month > 0 && result.day > 0) {
00069             // Have parsed month and day components
00070             calendar->setDate(resultDate, result.year, result.month, result.day);
00071         } else if (result.dayInYear > 0) {
00072             // Have parsed Day In Year component
00073             calendar->setDate(resultDate, result.year, result.dayInYear);
00074         } else if (result.isoWeekNumber > 0 && result.dayOfIsoWeek > 0) {
00075             // Have parsed ISO Week components
00076             calendar->setDateIsoWeek(resultDate, result.year, result.isoWeekNumber, result.dayOfIsoWeek);
00077         }
00078 
00079     }
00080 
00081     return resultDate;
00082 }
00083 
00084 DateTimeComponents KDateTimeParser::parseDatePosix(const QString &inputString,
00085                                                    const QString &formatString,
00086                                                    const KCalendarSystem *calendar,
00087                                                    const KLocale *locale,
00088                                                    KLocale::DigitSet digitSet,
00089                                                    KLocale::DateTimeFormatStandard standard) const
00090 {
00091     QString str = inputString.simplified().toLower();
00092     QString fmt = formatString.simplified();
00093     int dd = -1;
00094     int mm = -1;
00095     int yy = 0;
00096     bool parsedYear = false;
00097     int ey = -1;
00098     QString ee;
00099     int dayInYear = -1;
00100     int isoWeekNumber = -1;
00101     int dayOfIsoWeek = -1;
00102     int strpos = 0;
00103     int fmtpos = 0;
00104     int readLength; // Temporary variable used when reading input
00105     bool error = false;
00106 
00107     while (fmt.length() > fmtpos && str.length() > strpos && !error) {
00108 
00109         QChar fmtChar = fmt.at(fmtpos++);
00110 
00111         if (fmtChar != QLatin1Char('%')) {
00112 
00113             if (fmtChar.isSpace() && str.at(strpos).isSpace()) {
00114                 strpos++;
00115             } else if (fmtChar.toLower() == str.at(strpos)) {
00116                 strpos++;
00117             } else {
00118                 error = true;
00119             }
00120 
00121         } else {
00122             int j;
00123             QString shortName, longName;
00124             QChar modifierChar;
00125             // remove space at the beginning
00126             if (str.length() > strpos && str.at(strpos).isSpace()) {
00127                 strpos++;
00128             }
00129 
00130             fmtChar = fmt.at(fmtpos++);
00131             if (fmtChar == QLatin1Char('E')) {
00132                 modifierChar = fmtChar;
00133                 fmtChar = fmt.at(fmtpos++);
00134             }
00135 
00136             switch (fmtChar.unicode()) {
00137             case 'a':  // Weekday Name Short
00138             case 'A':  // Weekday Name Long
00139                 error = true;
00140                 j = 1;
00141                 while (error && j <= calendar->d_ptr->maxDaysInWeek()) {
00142                     shortName = calendar->weekDayName(j, KCalendarSystem::ShortDayName).toLower();
00143                     longName = calendar->weekDayName(j, KCalendarSystem::LongDayName).toLower();
00144                     if (str.mid(strpos, longName.length()) == longName) {
00145                         strpos += longName.length();
00146                         error = false;
00147                     } else if (str.mid(strpos, shortName.length()) == shortName) {
00148                         strpos += shortName.length();
00149                         error = false;
00150                     }
00151                     ++j;
00152                 }
00153                 break;
00154             case 'b':  // Month Name Short
00155             case 'h':  // Month Name Short
00156             case 'B':  // Month Name Long
00157                 error = true;
00158                 j = 1;
00159                 while (error && j <= calendar->d_ptr->maxMonthsInYear()) {
00160                     // This may be a problem in calendar systems with variable number of months
00161                     // in the year and/or names of months that change depending on the year, e.g
00162                     // Hebrew.  We really need to know the correct year first, but we may not have
00163                     // read it yet and will be using the current year instead
00164                     int monthYear;
00165                     if (parsedYear) {
00166                         monthYear = yy;
00167                     } else {
00168                         monthYear = calendar->year(QDate::currentDate());
00169                     }
00170                     if (calendar->locale()->dateMonthNamePossessive()) {
00171                         shortName = calendar->monthName(j, monthYear, KCalendarSystem::ShortNamePossessive).toLower();
00172                         longName = calendar->monthName(j, monthYear, KCalendarSystem::LongNamePossessive).toLower();
00173                     } else {
00174                         shortName = calendar->monthName(j, monthYear, KCalendarSystem::ShortName).toLower();
00175                         longName = calendar->monthName(j, monthYear, KCalendarSystem::LongName).toLower();
00176                     }
00177                     if (str.mid(strpos, longName.length()) == longName) {
00178                         mm = j;
00179                         strpos += longName.length();
00180                         error = false;
00181                     } else if (str.mid(strpos, shortName.length()) == shortName) {
00182                         mm = j;
00183                         strpos += shortName.length();
00184                         error = false;
00185                     }
00186                     ++j;
00187                 }
00188                 break;
00189             case 'd': // Day Number Long
00190             case 'e': // Day Number Short
00191                 dd = calendar->dayStringToInteger(str.mid(strpos), readLength);
00192                 strpos += readLength;
00193                 error = readLength <= 0;
00194                 break;
00195             case 'n':
00196                 // PosixFormat %n is Newline
00197                 // KdeFormat %n is Month Number Short
00198                 if (standard == KLocale::KdeFormat) {
00199                     mm = calendar->monthStringToInteger(str.mid(strpos), readLength);
00200                     strpos += readLength;
00201                     error = readLength <= 0;
00202                 }
00203                 // standard == KLocale::PosixFormat
00204                 // all whitespace already 'eaten', no action required
00205                 break;
00206             case 'm': // Month Number Long
00207                 mm = calendar->monthStringToInteger(str.mid(strpos), readLength);
00208                 strpos += readLength;
00209                 error = readLength <= 0;
00210                 break;
00211             case 'Y': // Year Number Long
00212             case 'y': // Year Number Short
00213                 if (modifierChar == QLatin1Char('E')) {    // Year In Era
00214                     if (fmtChar == QLatin1Char('y')) {
00215                         ey = calendar->yearStringToInteger(str.mid(strpos), readLength);
00216                         strpos += readLength;
00217                         error = readLength <= 0;
00218                     } else {
00219                         error = true;
00220                         j = calendar->eraList()->count() - 1; // Start with the most recent
00221                         while (error && j >= 0) {
00222                             QString subFormat = calendar->eraList()->at(j).format();
00223                             QString subInput = str.mid(strpos);
00224                             DateTimeComponents subResult = parseDatePosix(subInput, subFormat, calendar, locale, digitSet, standard);
00225                             if (!subResult.error) {
00226                                 if (subResult.parsedYear) {
00227                                     yy = subResult.year;
00228                                     parsedYear = true;
00229                                     error = false;
00230                                     strpos += subResult.inputPosition;
00231                                 } else if (!subResult.eraName.isEmpty() && subResult.yearInEra >= 0) {
00232                                     ee = subResult.eraName;
00233                                     ey = subResult.yearInEra;
00234                                     error = false;
00235                                     strpos += subResult.inputPosition;
00236                                 }
00237                             }
00238                             --j;
00239                         }
00240                     }
00241                 } else {
00242                     yy = calendar->yearStringToInteger(str.mid(strpos), readLength);
00243                     strpos += readLength;
00244                     if (fmtChar == QLatin1Char('y')) {
00245                         yy = calendar->applyShortYearWindow(yy);
00246                     }
00247                     error = readLength <= 0;
00248                     if (!error) {
00249                         parsedYear = true;
00250                     }
00251                 }
00252                 break;
00253             case 'C': // Era
00254                 error = true;
00255                 if (modifierChar == QLatin1Char('E')) {
00256                     j = calendar->eraList()->count() - 1; // Start with the most recent
00257                     while (error && j >= 0) {
00258                         shortName = calendar->d_ptr->m_eraList->at(j).name(KLocale::ShortName).toLower();
00259                         longName = calendar->eraList()->at(j).name(KLocale::LongName).toLower();
00260                         if (str.mid(strpos, longName.length()) == longName) {
00261                             strpos += longName.length();
00262                             ee = longName;
00263                             error = false;
00264                         } else if (str.mid(strpos, shortName.length()) == shortName) {
00265                             strpos += shortName.length();
00266                             ee = shortName;
00267                             error = false;
00268                         }
00269                         --j;
00270                     }
00271                 }
00272                 break;
00273             case 'j': // Day Of Year Number
00274                 dayInYear = integerFromString(str.mid(strpos), 3, readLength);
00275                 strpos += readLength;
00276                 error = readLength <= 0;
00277                 break;
00278             case 'V': // ISO Week Number
00279                 isoWeekNumber = integerFromString(str.mid(strpos), 2, readLength);
00280                 strpos += readLength;
00281                 error = readLength <= 0;
00282                 break;
00283             case 'u': // ISO Day Of Week
00284                 dayOfIsoWeek = integerFromString(str.mid(strpos), 1, readLength);
00285                 strpos += readLength;
00286                 error = readLength <= 0;
00287                 break;
00288             }
00289         }
00290     }
00291 
00292     DateTimeComponents result;
00293     result.error = error;
00294     result.inputPosition = strpos;
00295     result.formatPosition = fmtpos;
00296     if (error) {
00297         result.day = -1;
00298         result.month = -1;
00299         result.year = 0;
00300         result.parsedYear = false;
00301         result.eraName.clear();
00302         result.yearInEra = -1;
00303         result.dayInYear = -1;
00304         result.isoWeekNumber = -1;
00305         result.dayOfIsoWeek = -1;
00306     } else {
00307         result.day = dd;
00308         result.month = mm;
00309         result.year = yy;
00310         result.parsedYear = parsedYear;
00311         result.eraName = ee;
00312         result.yearInEra = ey;
00313         result.dayInYear = dayInYear;
00314         result.isoWeekNumber = isoWeekNumber;
00315         result.dayOfIsoWeek = dayOfIsoWeek;
00316     }
00317     return result;
00318 }
00319 
00320 // Parse an input string to match a UNICODE DateTime format string and return any components found
00321 DateTimeComponents KDateTimeParser::parseDateUnicode(const QString &inputString,
00322                                                      const QString &formatString,
00323                                                      const KCalendarSystem *calendar,
00324                                                      const KLocale *locale,
00325                                                      KLocale::DigitSet digitSet) const
00326 {
00327     Q_UNUSED(calendar);
00328     Q_UNUSED(locale);
00329     Q_UNUSED(digitSet);
00330     QString str = inputString.simplified().toLower();
00331     QString fmt = formatString.simplified();
00332     int dd = -1;
00333     int mm = -1;
00334     int yy = 0;
00335     bool parsedYear = false;
00336     int ey = -1;
00337     QString ee;
00338     int dayInYear = -1;
00339     int isoWeekNumber = -1;
00340     int dayOfIsoWeek = -1;
00341     int strpos = 0;
00342     int fmtpos = 0;
00343     //int readLength; // Temporary variable used when reading input
00344     bool error = false;
00345 
00346     DateTimeComponents result;
00347     result.error = error;
00348     result.inputPosition = strpos;
00349     result.formatPosition = fmtpos;
00350     if (error) {
00351         result.day = -1;
00352         result.month = -1;
00353         result.year = 0;
00354         result.parsedYear = false;
00355         result.eraName.clear();
00356         result.yearInEra = -1;
00357         result.dayInYear = -1;
00358         result.isoWeekNumber = -1;
00359         result.dayOfIsoWeek = -1;
00360     } else {
00361         result.day = dd;
00362         result.month = mm;
00363         result.year = yy;
00364         result.parsedYear = parsedYear;
00365         result.eraName = ee;
00366         result.yearInEra = ey;
00367         result.dayInYear = dayInYear;
00368         result.isoWeekNumber = isoWeekNumber;
00369         result.dayOfIsoWeek = dayOfIsoWeek;
00370     }
00371     return result;
00372 }
00373 
00374 // Peel a number off the front of a string which may have other trailing chars after the number
00375 // Stop either at either maxLength, eos, or first non-digit char
00376 int KDateTimeParser::integerFromString(const QString &string, int maxLength, int &readLength) const
00377 {
00378     int value = -1;
00379     int position = 0;
00380     readLength = 0;
00381     bool ok = false;
00382 
00383     if (maxLength < 0) {
00384         maxLength = string.length();
00385     }
00386 
00387     while (position < string.length() &&
00388             position < maxLength &&
00389             string.at(position).isDigit()) {
00390         position++;
00391     }
00392 
00393     if (position > 0) {
00394         value = string.left(position).toInt(&ok);
00395         if (ok) {
00396             readLength = position;
00397         } else {
00398             value = -1;
00399         }
00400     }
00401 
00402     return value;
00403 }

KDECore

Skip menu "KDECore"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.5
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal