• Skip to content
  • Skip to link menu
KDE 4.6 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             {
00138                 case 'a':  // Weekday Name Short
00139                 case 'A':  // Weekday Name Long
00140                     error = true;
00141                     j = 1;
00142                     while ( error && j <= calendar->d_ptr->maxDaysInWeek() ) {
00143                         shortName = calendar->weekDayName( j, KCalendarSystem::ShortDayName ).toLower();
00144                         longName = calendar->weekDayName( j, KCalendarSystem::LongDayName ).toLower();
00145                         if ( str.mid( strpos, longName.length() ) == longName ) {
00146                             strpos += longName.length();
00147                             error = false;
00148                         } else if ( str.mid( strpos, shortName.length() ) == shortName ) {
00149                             strpos += shortName.length();
00150                             error = false;
00151                         }
00152                         ++j;
00153                     }
00154                     break;
00155                 case 'b':  // Month Name Short
00156                 case 'h':  // Month Name Short
00157                 case 'B':  // Month Name Long
00158                     error = true;
00159                     j = 1;
00160                     while ( error && j <= calendar->d_ptr->maxMonthsInYear() ) {
00161                         // This may be a problem in calendar systems with variable number of months
00162                         // in the year and/or names of months that change depending on the year, e.g
00163                         // Hebrew.  We really need to know the correct year first, but we may not have
00164                         // read it yet and will be using the current year instead
00165                         int monthYear;
00166                         if ( parsedYear ) {
00167                             monthYear = yy;
00168                         } else {
00169                             monthYear = calendar->year( QDate::currentDate() );
00170                         }
00171                         if ( calendar->locale()->dateMonthNamePossessive() ) {
00172                             shortName = calendar->monthName( j, yy, KCalendarSystem::ShortNamePossessive ).toLower();
00173                             longName = calendar->monthName( j, yy, KCalendarSystem::LongNamePossessive ).toLower();
00174                         } else {
00175                             shortName = calendar->monthName( j, yy, KCalendarSystem::ShortName ).toLower();
00176                             longName = calendar->monthName( j, yy, KCalendarSystem::LongName ).toLower();
00177                         }
00178                         if ( str.mid( strpos, longName.length() ) == longName ) {
00179                             mm = j;
00180                             strpos += longName.length();
00181                             error = false;
00182                         } else if ( str.mid( strpos, shortName.length() ) == shortName ) {
00183                             mm = j;
00184                             strpos += shortName.length();
00185                             error = false;
00186                         }
00187                         ++j;
00188                     }
00189                     break;
00190                 case 'd': // Day Number Long
00191                 case 'e': // Day Number Short
00192                     dd = calendar->dayStringToInteger( str.mid( strpos ), readLength );
00193                     strpos += readLength;
00194                     error = readLength <= 0;
00195                     break;
00196                 case 'n':
00197                     // PosixFormat %n is Newline
00198                     // KdeFormat %n is Month Number Short
00199                     if ( standard == KLocale::KdeFormat ) {
00200                         mm = calendar->monthStringToInteger( str.mid( strpos ), readLength );
00201                         strpos += readLength;
00202                         error = readLength <= 0;
00203                     }
00204                     // standard == KLocale::PosixFormat
00205                     // all whitespace already 'eaten', no action required
00206                     break;
00207                 case 'm': // Month Number Long
00208                     mm = calendar->monthStringToInteger( str.mid( strpos ), readLength );
00209                     strpos += readLength;
00210                     error = readLength <= 0;
00211                     break;
00212                 case 'Y': // Year Number Long
00213                 case 'y': // Year Number Short
00214                     if ( modifierChar == QLatin1Char('E') ) {  // Year In Era
00215                         if ( fmtChar == QLatin1Char('y') ) {
00216                             ey = calendar->yearStringToInteger( str.mid( strpos ), readLength );
00217                             strpos += readLength;
00218                             error = readLength <= 0;
00219                         } else {
00220                             error = true;
00221                             j = calendar->eraList()->count() -1; // Start with the most recent
00222                             while ( error && j >= 0  ) {
00223                                 QString subFormat = calendar->eraList()->at( j ).format();
00224                                 QString subInput = str.mid( strpos );
00225                                 DateTimeComponents subResult = parseDatePosix( subInput, subFormat, calendar, locale, digitSet, standard );
00226                                 if ( !subResult.error ) {
00227                                     if ( subResult.parsedYear ) {
00228                                         yy = subResult.year;
00229                                         parsedYear = true;
00230                                         error = false;
00231                                         strpos += subResult.inputPosition;
00232                                     } else if ( !subResult.eraName.isEmpty() && subResult.yearInEra >= 0 ) {
00233                                         ee = subResult.eraName;
00234                                         ey = subResult.yearInEra;
00235                                         error = false;
00236                                         strpos += subResult.inputPosition;
00237                                     }
00238                                 }
00239                                 --j;
00240                             }
00241                         }
00242                     } else {
00243                         yy = calendar->yearStringToInteger( str.mid( strpos ), readLength );
00244                         strpos += readLength;
00245                         if ( fmtChar == QLatin1Char('y') ) {
00246                             yy = calendar->applyShortYearWindow( yy );
00247                         }
00248                         error = readLength <= 0;
00249                         if ( !error ) {
00250                             parsedYear = true;
00251                         }
00252                     }
00253                     break;
00254                 case 'C': // Era
00255                     error = true;
00256                     if ( modifierChar == QLatin1Char('E') ) {
00257                         j = calendar->eraList()->count() -1; // Start with the most recent
00258                         while ( error && j >= 0  ) {
00259                             shortName = calendar->d_ptr->m_eraList->at( j ).name( KLocale::ShortName ).toLower();
00260                             longName = calendar->eraList()->at( j ).name( KLocale::LongName ).toLower();
00261                             if ( str.mid( strpos, longName.length() ) == longName ) {
00262                                 strpos += longName.length();
00263                                 ee = longName;
00264                                 error = false;
00265                             } else if ( str.mid( strpos, shortName.length() ) == shortName ) {
00266                                 strpos += shortName.length();
00267                                 ee = shortName;
00268                                 error = false;
00269                             }
00270                             --j;
00271                         }
00272                     }
00273                     break;
00274                 case 'j': // Day Of Year Number
00275                     dayInYear = integerFromString( str.mid( strpos ), 3, readLength );
00276                     strpos += readLength;
00277                     error = readLength <= 0;
00278                     break;
00279                 case 'V': // ISO Week Number
00280                     isoWeekNumber = integerFromString( str.mid( strpos ), 2, readLength );
00281                     strpos += readLength;
00282                     error = readLength <= 0;
00283                     break;
00284                 case 'u': // ISO Day Of Week
00285                     dayOfIsoWeek = integerFromString( str.mid( strpos ), 1, readLength );
00286                     strpos += readLength;
00287                     error = readLength <= 0;
00288                     break;
00289             }
00290         }
00291     }
00292 
00293     DateTimeComponents result;
00294     result.error = error;
00295     result.inputPosition = strpos;
00296     result.formatPosition = fmtpos;
00297     if ( error ) {
00298         result.day = -1;
00299         result.month = -1;
00300         result.year = 0;
00301         result.parsedYear = false;
00302         result.eraName = QString();
00303         result.yearInEra = -1;
00304         result.dayInYear = -1;
00305         result.isoWeekNumber = -1;
00306         result.dayOfIsoWeek = -1;
00307     } else {
00308         result.day = dd;
00309         result.month = mm;
00310         result.year = yy;
00311         result.parsedYear = parsedYear;
00312         result.eraName = ee;
00313         result.yearInEra = ey;
00314         result.dayInYear = dayInYear;
00315         result.isoWeekNumber = isoWeekNumber;
00316         result.dayOfIsoWeek = dayOfIsoWeek;
00317     }
00318     return result;
00319 }
00320 
00321 // Parse an input string to match a UNICODE DateTime format string and return any components found
00322 DateTimeComponents KDateTimeParser::parseDateUnicode( const QString &inputString,
00323                                                       const QString &formatString,
00324                                                       const KCalendarSystem *calendar,
00325                                                       const KLocale *locale,
00326                                                       KLocale::DigitSet digitSet ) const
00327 {
00328     QString str = inputString.simplified().toLower();
00329     QString fmt = formatString.simplified();
00330     int dd = -1;
00331     int mm = -1;
00332     int yy = 0;
00333     bool parsedYear = false;
00334     int ey = -1;
00335     QString ee;
00336     int dayInYear = -1;
00337     int isoWeekNumber = -1;
00338     int dayOfIsoWeek = -1;
00339     int strpos = 0;
00340     int fmtpos = 0;
00341     int readLength; // Temporary variable used when reading input
00342     bool error = false;
00343 
00344     DateTimeComponents result;
00345     result.error = error;
00346     result.inputPosition = strpos;
00347     result.formatPosition = fmtpos;
00348     if ( error ) {
00349         result.day = -1;
00350         result.month = -1;
00351         result.year = 0;
00352         result.parsedYear = false;
00353         result.eraName = QString();
00354         result.yearInEra = -1;
00355         result.dayInYear = -1;
00356         result.isoWeekNumber = -1;
00357         result.dayOfIsoWeek = -1;
00358     } else {
00359         result.day = dd;
00360         result.month = mm;
00361         result.year = yy;
00362         result.parsedYear = parsedYear;
00363         result.eraName = ee;
00364         result.yearInEra = ey;
00365         result.dayInYear = dayInYear;
00366         result.isoWeekNumber = isoWeekNumber;
00367         result.dayOfIsoWeek = dayOfIsoWeek;
00368     }
00369     return result;
00370 }
00371 
00372 // Peel a number off the front of a string which may have other trailing chars after the number
00373 // Stop either at either maxLength, eos, or first non-digit char
00374 int KDateTimeParser::integerFromString( const QString &string, int maxLength, int &readLength ) const
00375 {
00376     int value = -1;
00377     int position = 0;
00378     readLength = 0;
00379     bool ok = false;
00380 
00381     if ( maxLength < 0 ) {
00382         maxLength = string.length();
00383     }
00384 
00385     while ( position < string.length() &&
00386             position < maxLength &&
00387             string.at( position ).isDigit() ) {
00388         position++;
00389     }
00390 
00391     if ( position > 0 ) {
00392         value = string.left( position ).toInt( &ok );
00393         if ( ok ) {
00394             readLength = position;
00395         } else {
00396             value = -1;
00397         }
00398     }
00399 
00400     return value;
00401 }

KDECore

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • 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.3
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