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->week(fromDateTime.date(), KLocale::IsoWeekNumber); 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->week(fromDateTime.date(), KLocale::IsoWeekNumber, &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->week(fromDateTime.date(), KLocale::IsoWeekNumber, &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 preceding/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 preceding/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->calendarSystem() != calendar->calendarSystem()) { 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->calendarSystem(), 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 result.prepend(QLatin1Char('-')); 00745 removed = 5; 00746 } 00747 } else if (toFormat.startsWith(QLatin1String("yy"))) { 00748 result = QString::number(calendar->year(fromDateTime.date())).right(2).rightJustified(2, QLatin1Char('0')); 00749 removed = 2; 00750 } 00751 00752 if (removed == 0 || removed >= toFormat.size()) { 00753 return result; 00754 } 00755 00756 return result + getUnicodeString(fromDateTime, toFormat.mid(removed), timeOptions, calendar, locale, digitSet); 00757 } 00758 00759 // Reimplement if special integer to string handling required, e.g. Hebrew. 00760 // Utility to convert an integer into the correct display string form 00761 QString KDateTimeFormatter::stringFromInteger(int number, int padWidth, QChar padChar, QChar signChar, 00762 KLocale::DigitSet digitSet, const KLocale *locale) const 00763 { 00764 if (padChar == QChar() && signChar == QChar()) { 00765 //kDebug() << " stringFromInteger(" << number << padWidth << "null" << "null" << ")"; 00766 } else if (padChar == QChar()) { 00767 //kDebug() << " stringFromInteger(" << number << padWidth << "null" << signChar << ")"; 00768 } else if (signChar == QChar()) { 00769 //kDebug() << " stringFromInteger(" << number << padWidth << padChar << "null" << ")"; 00770 } else if (signChar == QChar()) { 00771 //kDebug() << " stringFromInteger(" << number << padWidth << padChar << signChar << ")"; 00772 } 00773 QString result; 00774 if (padChar == QChar() || padWidth == 0) { // If null pad char or 0 width don't bother padding 00775 //kDebug() << " no pad"; 00776 if (signChar == QChar()) { 00777 result = locale->convertDigits(QString::number(number), digitSet); 00778 } else { 00779 result = locale->convertDigits(QString::number(number).prepend(signChar), digitSet); 00780 } 00781 } else if (signChar != QChar()) { // If sign required 00782 if (padChar == QLatin1Char('0')) { // If zero-padded, zero considered part of the number, so pad the number then prepend the sign 00783 //kDebug() << " zero pad with sign"; 00784 result = locale->convertDigits(QString::number(number).rightJustified(padWidth, padChar).prepend(signChar), digitSet); 00785 } else { // If space-padded space not considered part of the number, so prepend the sign and then pad the number 00786 //kDebug() << " space pad with sign"; 00787 result = locale->convertDigits(QString::number(number).prepend(signChar).rightJustified(padWidth, padChar), digitSet); 00788 } 00789 } else { // No sign required so just pad 00790 //kDebug() << " pad no sign"; 00791 result = locale->convertDigits(QString::number(number).rightJustified(padWidth, padChar), digitSet); 00792 } 00793 //kDebug() << " result = " << result; 00794 return result; 00795 }
KDE 4.7 API Reference