KDECore
kdatetimeformatter.cpp
Go to the documentation of this file.
00001 /* 00002 Copyright 2009-2010 John Layt <john@layt.net> 00003 Copyright 2005-2010 David Jarvie <djarvie@kde.org> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License as published by the Free Software Foundation; either 00008 version 2 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 Boston, MA 02110-1301, USA. 00019 */ 00020 00021 #include "kdatetimeformatter_p.h" 00022 00023 #include <QtCore/QDate> 00024 #include <QtCore/QString> 00025 #include <QtCore/QStringList> 00026 #include <QtCore/QChar> 00027 00028 #include "kdatetime.h" 00029 #include "ktimezone.h" 00030 #include "kcalendarsystem.h" 00031 #include "kdayperiod_p.h" 00032 #include "klocale_p.h" 00033 #include "kdebug.h" 00034 00035 KDateTimeFormatter::KDateTimeFormatter() 00036 : m_englishLocale(0), 00037 m_englishCalendar(0) 00038 { 00039 } 00040 00041 KDateTimeFormatter::~KDateTimeFormatter() 00042 { 00043 delete m_englishCalendar; 00044 delete m_englishLocale; 00045 } 00046 00047 QString KDateTimeFormatter::formatDate( const QDate &fromDate, 00048 const QString &toFormat, 00049 const KCalendarSystem *calendar, 00050 const KLocale *locale, 00051 KLocale::DigitSet digitSet, 00052 KLocale::DateTimeFormatStandard formatStandard ) const 00053 { 00054 // If not valid input, don't waste our time 00055 if ( !calendar->isValid( fromDate ) || toFormat.isEmpty() ) { 00056 return QString(); 00057 } 00058 00059 return formatDateTime( KDateTime( fromDate ), toFormat, 0, calendar, locale, digitSet, formatStandard ); 00060 } 00061 00062 QString KDateTimeFormatter::formatTime( const QTime &fromTime, 00063 const QString &toFormat, 00064 KLocale::TimeFormatOptions timeOptions, 00065 const KCalendarSystem *calendar, 00066 const KLocale *locale, 00067 KLocale::DigitSet digitSet, 00068 KLocale::DateTimeFormatStandard formatStandard ) const 00069 { 00070 // If not valid input, don't waste our time 00071 if ( fromTime.isValid() || toFormat.isEmpty() ) { 00072 return QString(); 00073 } 00074 00075 return formatDateTime( KDateTime( QDate::currentDate(), fromTime ), toFormat, timeOptions, calendar, locale, digitSet, formatStandard ); 00076 } 00077 00078 // Format an input date to match a POSIX date format string 00079 QString KDateTimeFormatter::formatDateTime( const KDateTime &fromDateTime, 00080 const QString &toFormat, 00081 KLocale::TimeFormatOptions timeOptions, 00082 const KCalendarSystem *calendar, 00083 const KLocale *locale, 00084 KLocale::DigitSet digitSet, 00085 KLocale::DateTimeFormatStandard formatStandard ) const 00086 { 00087 // If not valid input, don't waste our time 00088 if ( !fromDateTime.isValid() || !calendar->isValid( fromDateTime.date() ) || toFormat.isEmpty() ) { 00089 return QString(); 00090 } 00091 00092 if ( formatStandard == KLocale::UnicodeFormat ) { 00093 return formatDateTimeUnicode( fromDateTime, toFormat, timeOptions, calendar, locale, digitSet ); 00094 } else { 00095 return formatDateTimePosix( fromDateTime, toFormat, timeOptions, calendar, locale, digitSet, formatStandard ); 00096 } 00097 } 00098 00099 // Format an input date to match a POSIX date format string 00100 QString KDateTimeFormatter::formatDateTimePosix( const KDateTime &fromDateTime, 00101 const QString &toFormat, 00102 KLocale::TimeFormatOptions timeOptions, 00103 const KCalendarSystem *calendar, 00104 const KLocale *locale, 00105 KLocale::DigitSet digitSet, 00106 KLocale::DateTimeFormatStandard formatStandard ) const 00107 { 00108 //kDebug() << "formatDateTimePosix(" << fromDateTime << toFormat << ")"; 00109 // If not valid input, don't waste our time 00110 if ( !fromDateTime.isValid() || toFormat.isEmpty() ) { 00111 return QString(); 00112 } 00113 00114 QChar thisChar; // Current toFormat char being processed 00115 QString result; // Output string 00116 00117 int padWidth = 0; // The width to pad numbers to 00118 QChar padChar = QLatin1Char('0'); // The char to use when padding numbers 00119 QChar signChar; // The sign to use when formatting numbers 00120 QChar caseChar; // The case modifier to use 00121 00122 bool escape = false; // Are we processing an escape char (%) 00123 bool escapeWidth = false; // Are we processing an escape width 00124 bool escapePad = false; // Are we processing an escape pad char 00125 bool escapeMod = false; // Are we processing an escape modifier 00126 int escapeIndex = 0; // Position in string of current escape char (%) 00127 00128 QChar modifierChar = QChar(); 00129 bool invalidModifier = false; 00130 00131 // Pre-fetch the core date components as they get used a lot 00132 // and it is 1/3rd more efficient than 3 separatre calls 00133 int year, month, day; 00134 calendar->getDate( fromDateTime.date(), &year, &month, &day ); 00135 00136 for ( int formatIndex = 0; formatIndex < toFormat.length(); ++formatIndex ) { 00137 00138 thisChar = toFormat.at( formatIndex ); 00139 00140 if ( !escape ) { 00141 00142 if ( thisChar == QLatin1Char('%') ) { 00143 escape = true; 00144 escapeIndex = formatIndex; 00145 } else { 00146 result.append( toFormat.at( formatIndex ) ); 00147 } 00148 00149 } else if ( !escapeMod && !escapeWidth && thisChar == QLatin1Char('-') ) { // no padding 00150 00151 padChar = QChar(); 00152 escapePad = true; 00153 00154 } else if ( !escapeMod && !escapeWidth && thisChar == QLatin1Char('_') ) { // space padding 00155 00156 padChar = QLatin1Char(' '); 00157 escapePad = true; 00158 00159 } else if ( !escapeMod && !escapeWidth && thisChar == QLatin1Char('0') ) { // 0 padding 00160 00161 padChar = QLatin1Char('0'); 00162 escapePad = true; 00163 00164 } else if ( !escapeMod && !escapeWidth && ( thisChar == QLatin1Char('^') || thisChar == QLatin1Char('#') ) ) { // Change case 00165 00166 caseChar = thisChar; 00167 00168 } else if ( !escapeMod && 00169 ( ( !escapeWidth && thisChar >= QLatin1Char('1') && thisChar <= QLatin1Char('9') ) || 00170 ( escapeWidth && thisChar >= QLatin1Char('0') && thisChar <= QLatin1Char('9') ) ) ) { // Change width 00171 00172 if ( escapeWidth ) { 00173 padWidth = padWidth * 10; 00174 } 00175 padWidth = padWidth + QString( thisChar ).toInt(); 00176 escapeWidth = true; 00177 00178 } else if ( !escapeMod && ( thisChar == QLatin1Char('E') || thisChar == QLatin1Char('O') || thisChar == QLatin1Char(':') ) ) { // Set modifier 00179 00180 escapeMod = true; 00181 modifierChar = thisChar; 00182 if ( thisChar == QLatin1Char(':') ) { 00183 invalidModifier = true; 00184 } 00185 00186 } else { 00187 00188 bool invalidComponent = false; 00189 QString componentString; 00190 int componentInteger = 0; 00191 int minWidth = 0; 00192 int isoWeekYear = year; 00193 QDate yearDate; 00194 KDateTime::SpecType timeSpecType; 00195 00196 //Default settings unless overridden by pad and case flags and width: are 0 pad to 0 width no sign 00197 //Names will override 0 pad with no pad unless flagged 00198 //Numbers will override with correct width unless flagged 00199 QChar thisChar = toFormat.at( formatIndex ).unicode(); 00200 switch ( thisChar.unicode() ) { 00201 case '%': //Literal % 00202 if ( modifierChar != QLatin1Char(':') ) { // E and O mods are ignored if not used, but : is treated as literal 00203 componentString = QLatin1Char('%'); 00204 if ( !escapePad ) { 00205 padChar = QChar(); 00206 } 00207 } 00208 break; 00209 case 't': //Tab 00210 if ( modifierChar != QLatin1Char(':') ) { 00211 componentString = QString::fromLatin1("\t"); 00212 if ( !escapePad ) { 00213 padChar = QChar(); 00214 } 00215 } 00216 break; 00217 case 'Y': 00218 if ( modifierChar == QLatin1Char('E') ) { //Era Year, default no pad to 0 places no sign 00219 if ( !escapePad ) { 00220 padChar = QLatin1Char(' '); 00221 } 00222 componentString = calendar->eraYear( fromDateTime.date() ); 00223 } else if ( modifierChar != QLatin1Char(':') ) { //Long year numeric, default 0 pad to 4 places with sign 00224 componentInteger = qAbs( year ); 00225 minWidth = 4; 00226 if ( year < 0 ) { 00227 signChar = QLatin1Char('-'); 00228 } 00229 } 00230 break; 00231 case 'C': 00232 if ( modifierChar == QLatin1Char('E') ) { //Era name, default no pad to 0 places no sign 00233 if ( !escapePad ) { 00234 padChar = QLatin1Char(' '); 00235 } 00236 componentString = calendar->eraName( fromDateTime.date() ); 00237 } else if ( modifierChar != QLatin1Char(':') ) { //Century numeric, default 0 pad to 2 places with sign 00238 componentInteger = qAbs( year ) / 100 ; 00239 minWidth = 2; 00240 if ( year < 0 ) { 00241 signChar = QLatin1Char('-'); 00242 } 00243 } 00244 break; 00245 case 'y': 00246 if ( modifierChar == QLatin1Char('E') ) { //Year in Era number, default 0 pad to 1 places no sign 00247 componentInteger = calendar->yearInEra( fromDateTime.date() ); 00248 minWidth = 1; 00249 } else if ( modifierChar != QLatin1Char(':') ) { //Short year numeric, default 0 pad to 2 places with sign 00250 componentInteger = qAbs( year ) % 100; 00251 minWidth = 2; 00252 if ( year < 0 ) { 00253 signChar = QLatin1Char('-'); 00254 } 00255 } 00256 break; 00257 case 'm': // Month numeric 00258 componentInteger = month; 00259 if ( modifierChar == QLatin1Char(':') ) { //Short month numeric, default no pad to 1 places no sign 00260 minWidth = 1; 00261 if ( !escapePad ) { 00262 padChar = QChar(); 00263 } 00264 invalidModifier = false; 00265 } else { //Long month numeric, default 0 pad to 2 places no sign 00266 componentInteger = month; 00267 minWidth = 2; 00268 } 00269 break; 00270 case 'n': 00271 //PosixFormat %n is newline 00272 //KdeFormat %n is short month numeric 00273 if ( modifierChar != QLatin1Char(':') ) { 00274 if ( formatStandard == KLocale::KdeFormat ) { 00275 //Copy what %e does, no padding by default 00276 //Short month numeric, default no pad to 1 places no sign 00277 componentInteger = month; 00278 minWidth = 1; 00279 if ( !escapePad ) { 00280 padChar = QChar(); 00281 } 00282 } else { // formatStandard == KLocale::PosixFormat 00283 componentString = QLatin1Char('\n'); 00284 } 00285 } 00286 break; 00287 case 'd': //Long day numeric, default 0 pad to 2 places no sign 00288 if ( modifierChar != QLatin1Char(':') ) { 00289 componentInteger = day; 00290 minWidth = 2; 00291 } 00292 break; 00293 case 'e': //Short day numeric, default no sign 00294 //PosixFormat %e is space pad to 2 places 00295 //KdeFormat %e is no pad to 1 place 00296 if ( modifierChar != QLatin1Char(':') ) { 00297 componentInteger = day; 00298 if ( formatStandard == KLocale::KdeFormat ) { 00299 minWidth = 1; 00300 if ( !escapePad ) { 00301 padChar = QChar(); 00302 } 00303 } else { // formatStandard == KLocale::PosixFormat 00304 minWidth = 2; 00305 if ( !escapePad ) { 00306 padChar = QLatin1Char(' '); 00307 } 00308 } 00309 } 00310 break; 00311 case 'B': //Long month name, default space pad to 0 places no sign 00312 if ( locale->dateMonthNamePossessive() ) { 00313 if ( modifierChar == QLatin1Char(':') ) { 00314 invalidModifier = false; 00315 initEnglish( calendar, locale ); 00316 componentString = m_englishCalendar->monthName( month, year, KCalendarSystem::LongNamePossessive ); 00317 } else { 00318 componentString = calendar->monthName( month, year, KCalendarSystem::LongNamePossessive ); 00319 } 00320 } else { 00321 if ( modifierChar == QLatin1Char(':') ) { 00322 invalidModifier = false; 00323 initEnglish( calendar, locale ); 00324 componentString = m_englishCalendar->monthName( month, year, KCalendarSystem::LongName ); 00325 } else { 00326 componentString = calendar->monthName( month, year, KCalendarSystem::LongName ); 00327 } 00328 } 00329 if ( !escapePad ) { 00330 padChar = QLatin1Char(' '); 00331 } 00332 break; 00333 case 'h': //Short month name, default space pad to 0 places no sign 00334 case 'b': //Short month name, default space pad to 0 places no sign 00335 if ( locale->dateMonthNamePossessive() ) { 00336 if ( modifierChar == QLatin1Char(':') ) { 00337 invalidModifier = false; 00338 initEnglish( calendar, locale ); 00339 componentString = m_englishCalendar->monthName( month, year, KCalendarSystem::ShortNamePossessive ); 00340 } else { 00341 componentString = calendar->monthName( month, year, KCalendarSystem::ShortNamePossessive ); 00342 } 00343 } else { 00344 if ( modifierChar == QLatin1Char(':') ) { 00345 invalidModifier = false; 00346 initEnglish( calendar, locale ); 00347 componentString = m_englishCalendar->monthName( month, year, KCalendarSystem::ShortName ); 00348 } else { 00349 componentString = calendar->monthName( month, year, KCalendarSystem::ShortName ); 00350 } 00351 } 00352 if ( !escapePad ) { 00353 padChar = QLatin1Char(' '); 00354 } 00355 break; 00356 case 'A': //Long weekday name, default space pad to 0 places no sign 00357 if ( modifierChar == QLatin1Char(':') ) { 00358 invalidModifier = false; 00359 initEnglish( calendar, locale ); 00360 componentString = m_englishCalendar->weekDayName( fromDateTime.date(), KCalendarSystem::LongDayName ); 00361 } else { 00362 componentString = calendar->weekDayName( fromDateTime.date(), KCalendarSystem::LongDayName ); 00363 } 00364 if ( !escapePad ) { 00365 padChar = QLatin1Char(' '); 00366 } 00367 break; 00368 case 'a': //Short weekday name, default space pad to 0 places no sign 00369 if ( modifierChar == QLatin1Char(':') ) { 00370 invalidModifier = false; 00371 initEnglish( calendar, locale ); 00372 componentString = m_englishCalendar->weekDayName( fromDateTime.date(), KCalendarSystem::ShortDayName ); 00373 } else { 00374 componentString = calendar->weekDayName( fromDateTime.date(), KCalendarSystem::ShortDayName ); 00375 } 00376 if ( !escapePad ) { 00377 padChar = QLatin1Char(' '); 00378 } 00379 break; 00380 case 'j': //Long day of year numeric, default 0 pad to 3 places no sign 00381 if ( modifierChar != QLatin1Char(':') ) { 00382 componentInteger = calendar->dayOfYear( fromDateTime.date() ); 00383 minWidth = 3; 00384 } 00385 break; 00386 case 'V': //Long ISO week of year numeric, default 0 pad to 2 places no sign 00387 if ( modifierChar != QLatin1Char(':') ) { 00388 componentInteger = calendar->weekNumber( fromDateTime.date() ); 00389 minWidth = 2; 00390 } 00391 break; 00392 case 'G': //Long year of ISO week of year numeric, default 0 pad to 4 places with sign 00393 if ( modifierChar != QLatin1Char(':') ) { 00394 calendar->weekNumber( fromDateTime.date(), &isoWeekYear ); 00395 calendar->setDate( yearDate, isoWeekYear, 1, 1 ); 00396 componentInteger = qAbs( isoWeekYear ); 00397 minWidth = 4; 00398 if ( isoWeekYear < 0 ) { 00399 signChar = QLatin1Char('-'); 00400 } 00401 } 00402 break; 00403 case 'g': //Short year of ISO week of year numeric, default 0 pad to 2 places with sign 00404 if ( modifierChar != QLatin1Char(':') ) { 00405 calendar->weekNumber( fromDateTime.date(), &isoWeekYear ); 00406 calendar->setDate( yearDate, isoWeekYear, 1, 1 ); 00407 componentInteger = qAbs( isoWeekYear ) % 100; 00408 minWidth = 2; 00409 if ( isoWeekYear < 0 ) { 00410 signChar = QLatin1Char('-'); 00411 } 00412 } 00413 break; 00414 case 'u': 00415 if ( modifierChar == QLatin1Char(':') ) { // TZ UTC offset hours 00416 invalidModifier = false; 00417 KDateTime::SpecType timeSpecType = fromDateTime.timeType(); 00418 if ( timeSpecType == KDateTime::UTC || timeSpecType == KDateTime::TimeZone || 00419 timeSpecType == KDateTime::OffsetFromUTC ) { 00420 componentInteger = fromDateTime.utcOffset() / 3600; 00421 if ( componentInteger >= 0 ) { 00422 signChar = QLatin1Char('+'); 00423 } else { 00424 componentInteger = -componentInteger; 00425 signChar = QLatin1Char('-'); 00426 } 00427 minWidth = 2; 00428 } 00429 } else { // Short day of week numeric 00430 componentInteger = calendar->dayOfWeek( fromDateTime.date() ); 00431 minWidth = 1; 00432 } 00433 break; 00434 case 'D': // US short date format, ignore any overrides 00435 if ( modifierChar != QLatin1Char(':') ) { 00436 componentString = formatDateTimePosix( fromDateTime, QString::fromLatin1("%m/%d/%y"), timeOptions, calendar, locale, digitSet, formatStandard ); 00437 padWidth = 0; 00438 padChar = QChar(); 00439 caseChar = QChar(); 00440 } 00441 break; 00442 case 'F': // Full or ISO short date format, ignore any overrides 00443 if ( modifierChar != QLatin1Char(':') ) { 00444 componentString = formatDateTimePosix( fromDateTime, QString::fromLatin1("%Y-%m-%d"), timeOptions, calendar, locale, digitSet, formatStandard ); 00445 padWidth = 0; 00446 padChar = QChar(); 00447 caseChar = QChar(); 00448 } 00449 break; 00450 case 'x': // Locale short date format, ignore any overrides 00451 if ( modifierChar != QLatin1Char(':') ) { 00452 componentString = formatDateTimePosix( fromDateTime, locale->dateFormatShort(), timeOptions, calendar, locale, digitSet, formatStandard ); 00453 padWidth = 0; 00454 padChar = QChar(); 00455 caseChar = QChar(); 00456 } 00457 break; 00458 case 'H': // Long 24 hour 00459 case 'k': // Short 24 hour 00460 if ( modifierChar != QLatin1Char(':') ) { 00461 componentInteger = fromDateTime.time().hour(); 00462 minWidth = 1; 00463 if ( !escapePad ) { 00464 padChar = QChar(); 00465 } 00466 } 00467 break; 00468 case 'I': // Long 12 hour 00469 case 'l': // Short 12 hour 00470 if ( modifierChar != QLatin1Char(':') ) { 00471 if ( (timeOptions & KLocale::TimeDuration) == KLocale::TimeDuration ) { 00472 componentInteger = fromDateTime.time().hour(); 00473 } else { 00474 componentInteger = locale->d->dayPeriodForTime( fromDateTime.time() ).hourInPeriod( fromDateTime.time() ); 00475 } 00476 if ( thisChar == QLatin1Char('I') ) { 00477 minWidth = 2; 00478 } else { 00479 minWidth = 1; 00480 if ( !escapePad ) { 00481 padChar = QChar(); 00482 } 00483 } 00484 } 00485 break; 00486 case 'M': // Long minutes 00487 if ( modifierChar != QLatin1Char(':') ) { 00488 componentInteger = fromDateTime.time().minute(); 00489 minWidth = 2; 00490 } 00491 break; 00492 case 'S': // Long seconds 00493 invalidModifier = false; 00494 if ( (timeOptions & KLocale::TimeWithoutSeconds) == KLocale::TimeWithoutSeconds ) { 00495 //TODO strip the preceeding/following punctuation 00496 } else { 00497 componentInteger = fromDateTime.time().second(); 00498 if ( modifierChar == QLatin1Char(':') ) { // Only if not 00 seconds 00499 if ( componentInteger > 0 || fromDateTime.time().msec() > 0 ) { 00500 result.append( QLatin1Char(':') ); 00501 minWidth = 2; 00502 } 00503 } else { 00504 minWidth = 2; 00505 } 00506 } 00507 break; 00508 case 's': 00509 if ( modifierChar == QLatin1Char(':') ) { // Milliseconds 00510 invalidModifier = false; 00511 componentInteger = fromDateTime.time().msec(); 00512 minWidth = 3; 00513 } else { // Whole seconds since Unix Epoch 00514 KDateTime unixEpoch; 00515 unixEpoch.setTime_t( 0 ); 00516 componentInteger = unixEpoch.secsTo( fromDateTime ); 00517 } 00518 break; 00519 case 'p': // AM/PM symbol 00520 case 'P': // AM/PM symbol in lowercase 00521 if ( (timeOptions & KLocale::TimeWithoutAmPm) == KLocale::TimeWithoutAmPm ) { 00522 //TODO strip the preceeding/following punctuation 00523 } else { 00524 if ( modifierChar == QLatin1Char(':') ) { 00525 invalidModifier = false; 00526 initEnglish( calendar, locale ); 00527 componentString = m_englishLocale->d->dayPeriodForTime( fromDateTime.time() ).periodName( KLocale::ShortName ); 00528 } else { 00529 componentString = locale->d->dayPeriodForTime( fromDateTime.time() ).periodName( KLocale::ShortName ); 00530 } 00531 if ( thisChar == QLatin1Char('P') ) { 00532 componentString = componentString.toLower(); 00533 } 00534 } 00535 break; 00536 case 'z': // TZ UTC Offset 00537 invalidModifier = false; 00538 timeSpecType = fromDateTime.timeType(); 00539 if ( timeSpecType == KDateTime::UTC || timeSpecType == KDateTime::TimeZone || 00540 timeSpecType == KDateTime::OffsetFromUTC ) { 00541 if ( modifierChar == QLatin1Char(':') ) { // TZ UTC offset hours & minutes with colon 00542 int offsetInSeconds = fromDateTime.utcOffset(); 00543 if ( offsetInSeconds >= 0 ) { 00544 signChar = QLatin1Char('+'); 00545 } else { 00546 offsetInSeconds = -offsetInSeconds; 00547 signChar = QLatin1Char('-'); 00548 } 00549 int offsetHours = offsetInSeconds / 3600; 00550 int offsetMinutes = ( offsetInSeconds / 60 ) % 60; 00551 //int offsetSeconds = offsetInSeconds % 60; 00552 QString hourComponent = stringFromInteger( offsetHours, 2, QLatin1Char('0'), signChar, digitSet, locale ); 00553 QString minuteComponent = stringFromInteger( offsetMinutes, 2, QLatin1Char('0'), QChar(), digitSet, locale ); 00554 componentString = hourComponent + QLatin1Char(':') + minuteComponent; 00555 minWidth = 0; 00556 padChar = QChar(); 00557 padWidth = 0; 00558 } else { // TZ UTC offset hours & minutes 00559 componentInteger = fromDateTime.utcOffset() / 60; 00560 if ( componentInteger >= 0 ) { 00561 signChar = QLatin1Char('+'); 00562 } else { 00563 componentInteger = -componentInteger; 00564 signChar = QLatin1Char('-'); 00565 } 00566 minWidth = 4; 00567 } 00568 } 00569 break; 00570 case 'Z': // TZ Name 00571 invalidModifier = false; 00572 timeSpecType = fromDateTime.timeType(); 00573 if ( timeSpecType == KDateTime::UTC || timeSpecType == KDateTime::TimeZone ) { 00574 KTimeZone tz = fromDateTime.timeZone(); 00575 if ( tz.isValid() ) { 00576 if ( modifierChar == QLatin1Char(':') ) { // TZ full name 00577 componentString = QString::fromLatin1(tz.abbreviation(fromDateTime.toUtc().dateTime())); 00578 } else { // TZ abbreviated name 00579 componentString = tz.name(); 00580 } 00581 } 00582 } 00583 break; 00584 default: //No valid format code, treat as literal 00585 invalidComponent = true; 00586 break; 00587 } 00588 00589 if ( invalidComponent || invalidModifier ) { // If escape sequence invalid treat as literal 00590 componentString = toFormat.mid( escapeIndex, formatIndex ); 00591 } else if ( componentString.isEmpty() ) { //i.e. is a number component 00592 padWidth = qMax( minWidth, padWidth ); 00593 componentString = stringFromInteger( componentInteger, padWidth, padChar, signChar, digitSet, locale ); 00594 } else { //i.e. is a string component 00595 if ( padChar != QChar() && padWidth != 0 ) { 00596 componentString = componentString.rightJustified( padWidth, padChar ); 00597 } 00598 00599 if ( caseChar == QLatin1Char('^') ) { 00600 componentString = componentString.toUpper(); 00601 } else if ( caseChar == QLatin1Char('#') ) { 00602 componentString = componentString.toUpper(); // JPL ??? 00603 } 00604 } 00605 00606 result.append( componentString ); 00607 00608 escape = false; 00609 escapePad = false; 00610 padChar = QLatin1Char('0'); 00611 escapeMod = false; 00612 invalidModifier = false; 00613 invalidComponent = false; 00614 modifierChar = QChar(); 00615 caseChar = QChar(); 00616 escapeWidth = false; 00617 padWidth = 0; 00618 signChar = QChar(); 00619 } 00620 } 00621 //kDebug() << " return = " << result; 00622 //kDebug() << ""; 00623 return result; 00624 } 00625 00626 void KDateTimeFormatter::initEnglish( const KCalendarSystem *calendar, const KLocale *locale ) const 00627 { 00628 if ( !m_englishCalendar || m_englishCalendar->calendarType() != calendar->calendarType() ) { 00629 // Set up an English locale and calendar for use with ':' modifier which forces English names 00630 if ( !m_englishLocale ) { 00631 m_englishLocale = new KLocale( *locale ); 00632 m_englishLocale->setLanguage( QStringList() << QString::fromLatin1("en_US") ); 00633 } 00634 delete m_englishCalendar; 00635 m_englishCalendar = KCalendarSystem::create( calendar->calendarType(), m_englishLocale ); 00636 } 00637 } 00638 00639 // Reimplement if special string handling required 00640 // Format an input date to match a UNICODE date format string 00641 // Original QDate::fmtDateTime() code taken from Qt 4.7 under LGPL, now heavily modifed 00642 // Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). 00643 QString KDateTimeFormatter::formatDateTimeUnicode( const KDateTime &fromDateTime, 00644 const QString &toFormat, 00645 KLocale::TimeFormatOptions timeOptions, 00646 const KCalendarSystem *calendar, 00647 const KLocale *locale, 00648 KLocale::DigitSet digitSet ) const 00649 { 00650 const QLatin1Char quote('\''); 00651 00652 QString result; 00653 QString format; 00654 QChar status(QLatin1Char('0')); 00655 00656 for (int i = 0; i < toFormat.length(); ++i) { 00657 if (toFormat.at(i) == quote) { 00658 if (status == quote) { 00659 if (i > 0 && toFormat.at(i - 1) == quote) 00660 result += QLatin1Char('\''); 00661 status = QLatin1Char('0'); 00662 } else { 00663 if (!format.isEmpty()) { 00664 result += getUnicodeString( fromDateTime, format, timeOptions, calendar, locale, digitSet ); 00665 format.clear(); 00666 } 00667 status = quote; 00668 } 00669 } else if (status == quote) { 00670 result += toFormat.at(i); 00671 } else if (toFormat.at(i) == status) { 00672 if ( toFormat.at(i) == QLatin1Char('P') || 00673 toFormat.at(i) == QLatin1Char('p') ) { 00674 status = QLatin1Char('0'); 00675 } 00676 format += toFormat.at( i ); 00677 } else { 00678 result += getUnicodeString( fromDateTime, format, timeOptions, calendar, locale, digitSet ); 00679 format.clear(); 00680 if ( ( toFormat.at(i) == QLatin1Char('d') ) || 00681 ( toFormat.at(i) == QLatin1Char('M') ) || 00682 ( toFormat.at(i) == QLatin1Char('y') ) ) { 00683 status = toFormat.at( i ); 00684 format += toFormat.at( i ); 00685 } else { 00686 result += toFormat.at( i ); 00687 status = QLatin1Char('0'); 00688 } 00689 } 00690 } 00691 00692 result += getUnicodeString( fromDateTime, format, timeOptions, calendar, locale, digitSet ); 00693 00694 return result; 00695 } 00696 00697 // Original QDate::getFmtString() code taken from Qt 4.7 under LGPL, now heavily modifed 00698 // Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). 00699 // Replaces tokens by their value. See QDateTime::toString() for a list of valid tokens 00700 QString KDateTimeFormatter::getUnicodeString( const KDateTime &fromDateTime, 00701 const QString &toFormat, 00702 KLocale::TimeFormatOptions timeOptions, 00703 const KCalendarSystem *calendar, 00704 const KLocale *locale, 00705 KLocale::DigitSet digitSet ) const 00706 { 00707 if ( toFormat.isEmpty() ) { 00708 return QString(); 00709 } 00710 00711 QString result = toFormat; 00712 int removed = 0; 00713 00714 if ( toFormat.startsWith( QLatin1String( "dddd" ) ) ) { 00715 result = calendar->weekDayName( fromDateTime.date(), KCalendarSystem::LongDayName ); 00716 removed = 4; 00717 } else if ( toFormat.startsWith(QLatin1String( "ddd" ) ) ) { 00718 result = calendar->weekDayName( fromDateTime.date(), KCalendarSystem::ShortDayName ); 00719 removed = 3; 00720 } else if ( toFormat.startsWith( QLatin1String( "dd" ) ) ) { 00721 result = QString::number( calendar->day( fromDateTime.date() ) ).rightJustified( 2, QLatin1Char('0'), true ); 00722 removed = 2; 00723 } else if ( toFormat.at(0) == QLatin1Char('d') ) { 00724 result = QString::number( calendar->day( fromDateTime.date() ) ); 00725 removed = 1; 00726 } else if (toFormat.startsWith(QLatin1String("MMMM"))) { 00727 result = calendar->monthName( calendar->month( fromDateTime.date() ), calendar->year( fromDateTime.date() ), KCalendarSystem::LongName ); 00728 removed = 4; 00729 } else if (toFormat.startsWith(QLatin1String("MMM"))) { 00730 result = calendar->monthName( calendar->month( fromDateTime.date() ), calendar->year( fromDateTime.date() ), KCalendarSystem::ShortName ); 00731 removed = 3; 00732 } else if (toFormat.startsWith(QLatin1String("MM"))) { 00733 result = QString::number( calendar->month( fromDateTime.date() ) ).rightJustified( 2, QLatin1Char('0'), true ); 00734 removed = 2; 00735 } else if (toFormat.at(0) == QLatin1Char('M')) { 00736 result = QString::number( calendar->month( fromDateTime.date() ) ); 00737 removed = 1; 00738 } else if (toFormat.startsWith(QLatin1String("yyyy"))) { 00739 const int year = calendar->year( fromDateTime.date() ); 00740 result = QString::number( qAbs( year ) ).rightJustified( 4, QLatin1Char('0') ); 00741 if( year > 0 ) 00742 removed = 4; 00743 else 00744 { 00745 result.prepend( QLatin1Char('-') ); 00746 removed = 5; 00747 } 00748 } else if ( toFormat.startsWith( QLatin1String("yy") ) ) { 00749 result = QString::number( calendar->year(fromDateTime.date()) ).right( 2 ).rightJustified( 2, QLatin1Char('0') ); 00750 removed = 2; 00751 } 00752 00753 if ( removed == 0 || removed >= toFormat.size() ) { 00754 return result; 00755 } 00756 00757 return result + getUnicodeString( fromDateTime, toFormat.mid( removed ), timeOptions, calendar, locale, digitSet ); 00758 } 00759 00760 // Reimplement if special integer to string handling required, e.g. Hebrew. 00761 // Utility to convert an integer into the correct display string form 00762 QString KDateTimeFormatter::stringFromInteger( int number, int padWidth, QChar padChar, QChar signChar, 00763 KLocale::DigitSet digitSet, const KLocale *locale ) const 00764 { 00765 if ( padChar == QChar() && signChar == QChar() ) { 00766 //kDebug() << " stringFromInteger(" << number << padWidth << "null" << "null" << ")"; 00767 } else if ( padChar == QChar() ) { 00768 //kDebug() << " stringFromInteger(" << number << padWidth << "null" << signChar << ")"; 00769 } else if ( signChar == QChar() ) { 00770 //kDebug() << " stringFromInteger(" << number << padWidth << padChar << "null" << ")"; 00771 } else if ( signChar == QChar() ) { 00772 //kDebug() << " stringFromInteger(" << number << padWidth << padChar << signChar << ")"; 00773 } 00774 QString result; 00775 if ( padChar == QChar() || padWidth == 0 ) { // If null pad char or 0 width don't bother padding 00776 //kDebug() << " no pad"; 00777 if ( signChar == QChar() ) { 00778 result = locale->convertDigits( QString::number( number ), digitSet ); 00779 } else { 00780 result = locale->convertDigits( QString::number( number ).prepend( signChar ), digitSet ); 00781 } 00782 } else if ( signChar != QChar() ) { // If sign required 00783 if ( padChar == QLatin1Char('0') ) { // If zero-padded, zero considered part of the number, so pad the number then prepend the sign 00784 //kDebug() << " zero pad with sign"; 00785 result = locale->convertDigits( QString::number( number ).rightJustified( padWidth, padChar ).prepend( signChar ), digitSet ); 00786 } else { // If space-padded space not considered part of the number, so prepend the sign and then pad the number 00787 //kDebug() << " space pad with sign"; 00788 result = locale->convertDigits( QString::number( number ).prepend( signChar ).rightJustified( padWidth, padChar ), digitSet ); 00789 } 00790 } else { // No sign required so just pad 00791 //kDebug() << " pad no sign"; 00792 result = locale->convertDigits( QString::number( number ).rightJustified( padWidth, padChar ), digitSet ); 00793 } 00794 //kDebug() << " result = " << result; 00795 return result; 00796 }
KDE 4.6 API Reference