kdelibs/kdecore/date/kdatetimeformatter.cpp

816 lines
38 KiB
C++
Raw Normal View History

2014-11-13 01:04:59 +02:00
/*
Copyright 2009-2010 John Layt <john@layt.net>
Copyright 2005-2010 David Jarvie <djarvie@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "kdatetimeformatter_p.h"
#include <QtCore/qdatetime.h>
2014-11-13 01:04:59 +02:00
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QChar>
#include "kdatetime.h"
#include "ktimezone.h"
#include "kcalendarsystem.h"
#include "klocale_p.h"
#include "kdebug.h"
KDateTimeFormatter::KDateTimeFormatter()
: m_englishLocale(0),
m_englishCalendar(0)
{
}
KDateTimeFormatter::~KDateTimeFormatter()
{
delete m_englishCalendar;
delete m_englishLocale;
}
QString KDateTimeFormatter::formatDate(const QDate &fromDate,
const QString &toFormat,
const KCalendarSystem *calendar,
const KLocale *locale,
KLocale::DigitSet digitSet,
KLocale::DateTimeFormatStandard formatStandard) const
{
// If not valid input, don't waste our time
if (!calendar->isValid(fromDate) || toFormat.isEmpty()) {
return QString();
}
return formatDateTime(KDateTime(fromDate), toFormat, 0, calendar, locale, digitSet, formatStandard);
}
QString KDateTimeFormatter::formatTime(const QTime &fromTime,
const QString &toFormat,
KLocale::TimeFormatOptions timeOptions,
const KCalendarSystem *calendar,
const KLocale *locale,
KLocale::DigitSet digitSet,
KLocale::DateTimeFormatStandard formatStandard) const
{
// If not valid input, don't waste our time
if (fromTime.isValid() || toFormat.isEmpty()) {
return QString();
}
return formatDateTime(KDateTime(QDate::currentDate(), fromTime), toFormat, timeOptions, calendar, locale, digitSet, formatStandard);
}
// Format an input date to match a POSIX date format string
QString KDateTimeFormatter::formatDateTime(const KDateTime &fromDateTime,
const QString &toFormat,
KLocale::TimeFormatOptions timeOptions,
const KCalendarSystem *calendar,
const KLocale *locale,
KLocale::DigitSet digitSet,
KLocale::DateTimeFormatStandard formatStandard) const
{
// If not valid input, don't waste our time
if (!fromDateTime.isValid() || !calendar->isValid(fromDateTime.date()) || toFormat.isEmpty()) {
return QString();
}
if (formatStandard == KLocale::UnicodeFormat) {
return formatDateTimeUnicode(fromDateTime, toFormat, timeOptions, calendar, locale, digitSet);
} else {
return formatDateTimePosix(fromDateTime, toFormat, timeOptions, calendar, locale, digitSet, formatStandard);
}
}
// Format an input date to match a POSIX date format string
QString KDateTimeFormatter::formatDateTimePosix(const KDateTime &fromDateTime,
const QString &toFormat,
KLocale::TimeFormatOptions timeOptions,
const KCalendarSystem *calendar,
const KLocale *locale,
KLocale::DigitSet digitSet,
KLocale::DateTimeFormatStandard formatStandard) const
{
//kDebug() << "formatDateTimePosix(" << fromDateTime << toFormat << ")";
// If not valid input, don't waste our time
if (!fromDateTime.isValid() || toFormat.isEmpty()) {
return QString();
}
QChar thisChar; // Current toFormat char being processed
QString result; // Output string
int padWidth = 0; // The width to pad numbers to
QChar padChar = QLatin1Char('0'); // The char to use when padding numbers
QChar signChar; // The sign to use when formatting numbers
QChar caseChar; // The case modifier to use
bool escape = false; // Are we processing an escape char (%)
bool escapeWidth = false; // Are we processing an escape width
bool escapePad = false; // Are we processing an escape pad char
bool escapeMod = false; // Are we processing an escape modifier
int escapeIndex = 0; // Position in string of current escape char (%)
QChar modifierChar = QChar();
bool invalidModifier = false;
// Pre-fetch the core date components as they get used a lot
// and it is 1/3rd more efficient than 3 separatre calls
int year, month, day;
calendar->getDate(fromDateTime.date(), &year, &month, &day);
for (int formatIndex = 0; formatIndex < toFormat.length(); ++formatIndex) {
thisChar = toFormat.at(formatIndex);
if (!escape) {
if (thisChar == QLatin1Char('%')) {
escape = true;
escapeIndex = formatIndex;
} else {
result.append(toFormat.at(formatIndex));
}
} else if (!escapeMod && !escapeWidth && thisChar == QLatin1Char('-')) { // no padding
padChar = QChar();
escapePad = true;
} else if (!escapeMod && !escapeWidth && thisChar == QLatin1Char('_')) { // space padding
padChar = QLatin1Char(' ');
escapePad = true;
} else if (!escapeMod && !escapeWidth && thisChar == QLatin1Char('0')) { // 0 padding
padChar = QLatin1Char('0');
escapePad = true;
} else if (!escapeMod && !escapeWidth && (thisChar == QLatin1Char('^') || thisChar == QLatin1Char('#'))) { // Change case
caseChar = thisChar;
} else if (!escapeMod &&
((!escapeWidth && thisChar >= QLatin1Char('1') && thisChar <= QLatin1Char('9')) ||
(escapeWidth && thisChar >= QLatin1Char('0') && thisChar <= QLatin1Char('9')))) { // Change width
if (escapeWidth) {
padWidth = padWidth * 10;
}
padWidth = padWidth + QString(thisChar).toInt();
escapeWidth = true;
} else if (!escapeMod && (thisChar == QLatin1Char('E') || thisChar == QLatin1Char('O') || thisChar == QLatin1Char(':'))) { // Set modifier
escapeMod = true;
modifierChar = thisChar;
if (thisChar == QLatin1Char(':')) {
invalidModifier = true;
}
} else {
bool invalidComponent = false;
QString componentString;
int componentInteger = 0;
int minWidth = 0;
int isoWeekYear = year;
QDate yearDate;
//Default settings unless overridden by pad and case flags and width: are 0 pad to 0 width no sign
//Names will override 0 pad with no pad unless flagged
//Numbers will override with correct width unless flagged
QChar thisChar = toFormat.at(formatIndex).unicode();
switch (thisChar.unicode()) {
case '%': { //Literal %
if (modifierChar != QLatin1Char(':')) { // E and O mods are ignored if not used, but : is treated as literal
componentString = QLatin1Char('%');
if (!escapePad) {
padChar = QChar();
}
2014-11-13 01:04:59 +02:00
}
break;
2014-11-13 01:04:59 +02:00
}
case 't': { //Tab
if (modifierChar != QLatin1Char(':')) {
componentString = QString::fromLatin1("\t");
if (!escapePad) {
padChar = QChar();
}
2014-11-13 01:04:59 +02:00
}
break;
2014-11-13 01:04:59 +02:00
}
case 'Y': {
if (modifierChar == QLatin1Char('E')) { //Era Year, default no pad to 0 places no sign
if (!escapePad) {
padChar = QLatin1Char(' ');
}
componentString = calendar->eraYear(fromDateTime.date());
} else if (modifierChar != QLatin1Char(':')) { //Long year numeric, default 0 pad to 4 places with sign
componentInteger = qAbs(year);
minWidth = 4;
if (year < 0) {
signChar = QLatin1Char('-');
}
2014-11-13 01:04:59 +02:00
}
break;
2014-11-13 01:04:59 +02:00
}
case 'C': {
if (modifierChar == QLatin1Char('E')) { //Era name, default no pad to 0 places no sign
if (!escapePad) {
padChar = QLatin1Char(' ');
}
componentString = calendar->eraName(fromDateTime.date());
} else if (modifierChar != QLatin1Char(':')) { //Century numeric, default 0 pad to 2 places with sign
componentInteger = qAbs(year) / 100 ;
minWidth = 2;
if (year < 0) {
signChar = QLatin1Char('-');
}
2014-11-13 01:04:59 +02:00
}
break;
2014-11-13 01:04:59 +02:00
}
case 'y': {
if (modifierChar == QLatin1Char('E')) { //Year in Era number, default 0 pad to 1 places no sign
componentInteger = calendar->yearInEra(fromDateTime.date());
2014-11-13 01:04:59 +02:00
minWidth = 1;
} else if (modifierChar != QLatin1Char(':')) { //Short year numeric, default 0 pad to 2 places with sign
componentInteger = qAbs(year) % 100;
minWidth = 2;
if (year < 0) {
signChar = QLatin1Char('-');
2014-11-13 01:04:59 +02:00
}
}
break;
2014-11-13 01:04:59 +02:00
}
case 'm': { // Month numeric
componentInteger = month;
if (modifierChar == QLatin1Char(':')) { //Short month numeric, default no pad to 1 places no sign
2014-11-13 01:04:59 +02:00
minWidth = 1;
if (!escapePad) {
padChar = QChar();
}
invalidModifier = false;
} else { //Long month numeric, default 0 pad to 2 places no sign
componentInteger = month;
2014-11-13 01:04:59 +02:00
minWidth = 2;
}
break;
}
case 'n': {
//PosixFormat %n is newline
//KdeFormat %n is short month numeric
if (modifierChar != QLatin1Char(':')) {
if (formatStandard == KLocale::KdeFormat) {
//Copy what %e does, no padding by default
//Short month numeric, default no pad to 1 places no sign
componentInteger = month;
minWidth = 1;
if (!escapePad) {
padChar = QChar();
}
} else { // formatStandard == KLocale::PosixFormat
componentString = QLatin1Char('\n');
2014-11-13 01:04:59 +02:00
}
}
break;
2014-11-13 01:04:59 +02:00
}
case 'd': { //Long day numeric, default 0 pad to 2 places no sign
if (modifierChar != QLatin1Char(':')) {
componentInteger = day;
minWidth = 2;
}
break;
}
case 'e': { //Short day numeric, default no sign
//PosixFormat %e is space pad to 2 places
//KdeFormat %e is no pad to 1 place
if (modifierChar != QLatin1Char(':')) {
componentInteger = day;
if (formatStandard == KLocale::KdeFormat) {
minWidth = 1;
if (!escapePad) {
padChar = QChar();
}
} else { // formatStandard == KLocale::PosixFormat
minWidth = 2;
if (!escapePad) {
padChar = QLatin1Char(' ');
}
}
}
break;
}
case 'B': { //Long month name, default space pad to 0 places no sign
if (locale->dateMonthNamePossessive()) {
if (modifierChar == QLatin1Char(':')) {
invalidModifier = false;
initEnglish(calendar, locale);
componentString = m_englishCalendar->monthName(month, year, KCalendarSystem::LongNamePossessive);
} else {
componentString = calendar->monthName(month, year, KCalendarSystem::LongNamePossessive);
}
2014-11-13 01:04:59 +02:00
} else {
if (modifierChar == QLatin1Char(':')) {
invalidModifier = false;
initEnglish(calendar, locale);
componentString = m_englishCalendar->monthName(month, year, KCalendarSystem::LongName);
} else {
componentString = calendar->monthName(month, year, KCalendarSystem::LongName);
}
2014-11-13 01:04:59 +02:00
}
if (!escapePad) {
padChar = QLatin1Char(' ');
}
break;
}
case 'h': //Short month name, default space pad to 0 places no sign
case 'b': { //Short month name, default space pad to 0 places no sign
if (locale->dateMonthNamePossessive()) {
if (modifierChar == QLatin1Char(':')) {
invalidModifier = false;
initEnglish(calendar, locale);
componentString = m_englishCalendar->monthName(month, year, KCalendarSystem::ShortNamePossessive);
} else {
componentString = calendar->monthName(month, year, KCalendarSystem::ShortNamePossessive);
}
2014-11-13 01:04:59 +02:00
} else {
if (modifierChar == QLatin1Char(':')) {
invalidModifier = false;
initEnglish(calendar, locale);
componentString = m_englishCalendar->monthName(month, year, KCalendarSystem::ShortName);
} else {
componentString = calendar->monthName(month, year, KCalendarSystem::ShortName);
}
2014-11-13 01:04:59 +02:00
}
if (!escapePad) {
padChar = QLatin1Char(' ');
}
break;
2014-11-13 01:04:59 +02:00
}
case 'A': { //Long weekday name, default space pad to 0 places no sign
2014-11-13 01:04:59 +02:00
if (modifierChar == QLatin1Char(':')) {
invalidModifier = false;
initEnglish(calendar, locale);
componentString = m_englishCalendar->weekDayName(fromDateTime.date(), KCalendarSystem::LongDayName);
2014-11-13 01:04:59 +02:00
} else {
componentString = calendar->weekDayName(fromDateTime.date(), KCalendarSystem::LongDayName);
}
if (!escapePad) {
padChar = QLatin1Char(' ');
2014-11-13 01:04:59 +02:00
}
break;
}
case 'a': { //Short weekday name, default space pad to 0 places no sign
2014-11-13 01:04:59 +02:00
if (modifierChar == QLatin1Char(':')) {
invalidModifier = false;
initEnglish(calendar, locale);
componentString = m_englishCalendar->weekDayName(fromDateTime.date(), KCalendarSystem::ShortDayName);
2014-11-13 01:04:59 +02:00
} else {
componentString = calendar->weekDayName(fromDateTime.date(), KCalendarSystem::ShortDayName);
2014-11-13 01:04:59 +02:00
}
if (!escapePad) {
padChar = QLatin1Char(' ');
}
break;
2014-11-13 01:04:59 +02:00
}
case 'j': { //Long day of year numeric, default 0 pad to 3 places no sign
if (modifierChar != QLatin1Char(':')) {
componentInteger = calendar->dayOfYear(fromDateTime.date());
minWidth = 3;
}
break;
2014-11-13 01:04:59 +02:00
}
case 'V': { //Long ISO week of year numeric, default 0 pad to 2 places no sign
if (modifierChar != QLatin1Char(':')) {
componentInteger = calendar->week(fromDateTime.date(), KLocale::IsoWeekNumber);
minWidth = 2;
}
break;
2014-11-13 01:04:59 +02:00
}
case 'G': { //Long year of ISO week of year numeric, default 0 pad to 4 places with sign
if (modifierChar != QLatin1Char(':')) {
calendar->week(fromDateTime.date(), KLocale::IsoWeekNumber, &isoWeekYear);
calendar->setDate(yearDate, isoWeekYear, 1, 1);
componentInteger = qAbs(isoWeekYear);
minWidth = 4;
if (isoWeekYear < 0) {
signChar = QLatin1Char('-');
}
2014-11-13 01:04:59 +02:00
}
break;
2014-11-13 01:04:59 +02:00
}
case 'g': { //Short year of ISO week of year numeric, default 0 pad to 2 places with sign
if (modifierChar != QLatin1Char(':')) {
calendar->week(fromDateTime.date(), KLocale::IsoWeekNumber, &isoWeekYear);
calendar->setDate(yearDate, isoWeekYear, 1, 1);
componentInteger = qAbs(isoWeekYear) % 100;
minWidth = 2;
if (isoWeekYear < 0) {
signChar = QLatin1Char('-');
}
2014-11-13 01:04:59 +02:00
}
break;
2014-11-13 01:04:59 +02:00
}
case 'u': {
if (modifierChar == QLatin1Char(':')) { // TZ UTC offset hours
invalidModifier = false;
2014-11-13 01:04:59 +02:00
componentInteger = fromDateTime.utcOffset() / 3600;
if (componentInteger >= 0) {
signChar = QLatin1Char('+');
} else {
componentInteger = -componentInteger;
signChar = QLatin1Char('-');
}
minWidth = 2;
} else { // Short day of week numeric
componentInteger = calendar->dayOfWeek(fromDateTime.date());
minWidth = 1;
2014-11-13 01:04:59 +02:00
}
break;
2014-11-13 01:04:59 +02:00
}
case 'D': { // US short date format, ignore any overrides
if (modifierChar != QLatin1Char(':')) {
componentString = formatDateTimePosix(fromDateTime, QString::fromLatin1("%m/%d/%y"), timeOptions, calendar, locale, digitSet, formatStandard);
padWidth = 0;
padChar = QChar();
caseChar = QChar();
}
break;
2014-11-13 01:04:59 +02:00
}
case 'F': { // Full or ISO short date format, ignore any overrides
if (modifierChar != QLatin1Char(':')) {
componentString = formatDateTimePosix(fromDateTime, QString::fromLatin1("%Y-%m-%d"), timeOptions, calendar, locale, digitSet, formatStandard);
padWidth = 0;
padChar = QChar();
caseChar = QChar();
}
break;
2014-11-13 01:04:59 +02:00
}
case 'x': { // Locale short date format, ignore any overrides
if (modifierChar != QLatin1Char(':')) {
componentString = formatDateTimePosix(fromDateTime, locale->dateFormatShort(), timeOptions, calendar, locale, digitSet, formatStandard);
padWidth = 0;
2014-11-13 01:04:59 +02:00
padChar = QChar();
caseChar = QChar();
2014-11-13 01:04:59 +02:00
}
break;
2014-11-13 01:04:59 +02:00
}
case 'H': // Long 24 hour
case 'k': { // Short 24 hour
if (modifierChar != QLatin1Char(':')) {
2014-11-13 01:04:59 +02:00
componentInteger = fromDateTime.time().hour();
minWidth = 1;
if (!escapePad) {
padChar = QChar();
}
}
break;
2014-11-13 01:04:59 +02:00
}
case 'I': // Long 12 hour
case 'l': { // Short 12 hour
if (modifierChar != QLatin1Char(':')) {
if ((timeOptions & KLocale::TimeDuration) == KLocale::TimeDuration) {
componentInteger = fromDateTime.time().hour();
} else {
componentInteger = locale->d->dayPeriodForTime(fromDateTime.time()).hourInPeriod(fromDateTime.time());
}
if (thisChar == QLatin1Char('I')) {
2014-11-13 01:04:59 +02:00
minWidth = 2;
} else {
minWidth = 1;
if (!escapePad) {
padChar = QChar();
}
2014-11-13 01:04:59 +02:00
}
}
break;
}
case 'M': { // Long minutes
if (modifierChar != QLatin1Char(':')) {
componentInteger = fromDateTime.time().minute();
2014-11-13 01:04:59 +02:00
minWidth = 2;
}
break;
2014-11-13 01:04:59 +02:00
}
case 'S': { // Long seconds
2014-11-13 01:04:59 +02:00
invalidModifier = false;
if ((timeOptions & KLocale::TimeWithoutSeconds) == KLocale::TimeWithoutSeconds) {
//TODO strip the preceding/following punctuation
} else {
componentInteger = fromDateTime.time().second();
if (modifierChar == QLatin1Char(':')) { // Only if not 00 seconds
if (componentInteger > 0 || fromDateTime.time().msec() > 0) {
result.append(QLatin1Char(':'));
minWidth = 2;
}
} else {
minWidth = 2;
}
}
break;
2014-11-13 01:04:59 +02:00
}
case 's': {
if (modifierChar == QLatin1Char(':')) { // Milliseconds
2014-11-13 01:04:59 +02:00
invalidModifier = false;
componentInteger = fromDateTime.time().msec();
minWidth = 3;
} else { // Whole seconds since Unix Epoch
KDateTime unixEpoch;
unixEpoch.setTime_t(0);
componentInteger = unixEpoch.secsTo(fromDateTime);
2014-11-13 01:04:59 +02:00
}
break;
}
case 'p': // AM/PM symbol
case 'P': { // AM/PM symbol in lowercase
if ((timeOptions & KLocale::TimeWithoutAmPm) == KLocale::TimeWithoutAmPm) {
//TODO strip the preceding/following punctuation
} else {
if (modifierChar == QLatin1Char(':')) {
invalidModifier = false;
initEnglish(calendar, locale);
componentString = m_englishLocale->d->dayPeriodForTime(fromDateTime.time()).periodName(KLocale::ShortName);
} else {
componentString = locale->d->dayPeriodForTime(fromDateTime.time()).periodName(KLocale::ShortName);
}
if (thisChar == QLatin1Char('P')) {
componentString = componentString.toLower();
}
2014-11-13 01:04:59 +02:00
}
break;
2014-11-13 01:04:59 +02:00
}
case 'z': { // TZ UTC Offset
invalidModifier = false;
2014-11-13 01:04:59 +02:00
if (modifierChar == QLatin1Char(':')) { // TZ UTC offset hours & minutes with colon
int offsetInSeconds = fromDateTime.utcOffset();
if (offsetInSeconds >= 0) {
signChar = QLatin1Char('+');
} else {
offsetInSeconds = -offsetInSeconds;
signChar = QLatin1Char('-');
}
int offsetHours = offsetInSeconds / 3600;
int offsetMinutes = (offsetInSeconds / 60) % 60;
//int offsetSeconds = offsetInSeconds % 60;
QString hourComponent = stringFromInteger(offsetHours, 2, QLatin1Char('0'), signChar, digitSet, locale);
QString minuteComponent = stringFromInteger(offsetMinutes, 2, QLatin1Char('0'), QChar(), digitSet, locale);
componentString = hourComponent + QLatin1Char(':') + minuteComponent;
minWidth = 0;
padChar = QChar();
padWidth = 0;
} else { // TZ UTC offset hours & minutes
componentInteger = fromDateTime.utcOffset() / 60;
if (componentInteger >= 0) {
signChar = QLatin1Char('+');
} else {
componentInteger = -componentInteger;
signChar = QLatin1Char('-');
}
minWidth = 4;
}
break;
2014-11-13 01:04:59 +02:00
}
case 'Z': { // TZ Name
invalidModifier = false;
Qt::TimeSpec timeSpecType = fromDateTime.timeSpec();
if (timeSpecType == Qt::UTC || timeSpecType == Qt::LocalTime) {
KTimeZone tz = fromDateTime.timeZone();
if (tz.isValid()) {
if (modifierChar == QLatin1Char(':')) { // TZ full name
componentString = QString::fromLatin1(tz.abbreviation(fromDateTime.toUTC()));
} else { // TZ abbreviated name
componentString = tz.name();
}
2014-11-13 01:04:59 +02:00
}
}
break;
}
default: { //No valid format code, treat as literal
invalidComponent = true;
break;
2014-11-13 01:04:59 +02:00
}
}
if (invalidComponent || invalidModifier) { // If escape sequence invalid treat as literal
componentString = toFormat.mid(escapeIndex, formatIndex);
} else if (componentString.isEmpty()) { //i.e. is a number component
padWidth = qMax(minWidth, padWidth);
componentString = stringFromInteger(componentInteger, padWidth, padChar, signChar, digitSet, locale);
} else { //i.e. is a string component
if (padChar != QChar() && padWidth != 0) {
componentString = componentString.rightJustified(padWidth, padChar);
}
if (caseChar == QLatin1Char('^')) {
componentString = componentString.toUpper();
} else if (caseChar == QLatin1Char('#')) {
componentString = componentString.toUpper(); // JPL ???
}
}
result.append(componentString);
escape = false;
escapePad = false;
padChar = QLatin1Char('0');
escapeMod = false;
invalidModifier = false;
invalidComponent = false;
modifierChar = QChar();
caseChar = QChar();
escapeWidth = false;
padWidth = 0;
signChar = QChar();
}
}
//kDebug() << " return = " << result;
//kDebug() << "";
return result;
}
void KDateTimeFormatter::initEnglish(const KCalendarSystem *calendar, const KLocale *locale) const
{
if (!m_englishCalendar || m_englishCalendar->calendarSystem() != calendar->calendarSystem()) {
// Set up an English locale and calendar for use with ':' modifier which forces English names
if (!m_englishLocale) {
m_englishLocale = new KLocale(*locale);
m_englishLocale->setLanguage(QStringList() << QString::fromLatin1("en_US"));
}
delete m_englishCalendar;
m_englishCalendar = KCalendarSystem::create(calendar->calendarSystem(), m_englishLocale);
}
}
// Reimplement if special string handling required
// Format an input date to match a UNICODE date format string
// Original QDate::fmtDateTime() code taken from Qt 4.7 under LGPL, now heavily modifed
// Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
QString KDateTimeFormatter::formatDateTimeUnicode(const KDateTime &fromDateTime,
const QString &toFormat,
KLocale::TimeFormatOptions timeOptions,
const KCalendarSystem *calendar,
const KLocale *locale,
KLocale::DigitSet digitSet) const
{
const QLatin1Char quote('\'');
QString result;
QString format;
QChar status(QLatin1Char('0'));
for (int i = 0; i < toFormat.length(); ++i) {
if (toFormat.at(i) == quote) {
if (status == quote) {
if (i > 0 && toFormat.at(i - 1) == quote)
result += QLatin1Char('\'');
status = QLatin1Char('0');
} else {
if (!format.isEmpty()) {
result += getUnicodeString(fromDateTime, format, timeOptions, calendar, locale, digitSet);
format.clear();
}
status = quote;
}
} else if (status == quote) {
result += toFormat.at(i);
} else if (toFormat.at(i) == status) {
if (toFormat.at(i) == QLatin1Char('P') ||
toFormat.at(i) == QLatin1Char('p')) {
status = QLatin1Char('0');
}
format += toFormat.at(i);
} else {
result += getUnicodeString(fromDateTime, format, timeOptions, calendar, locale, digitSet);
format.clear();
if ((toFormat.at(i) == QLatin1Char('d')) ||
(toFormat.at(i) == QLatin1Char('M')) ||
(toFormat.at(i) == QLatin1Char('y'))) {
status = toFormat.at(i);
format += toFormat.at(i);
} else {
result += toFormat.at(i);
status = QLatin1Char('0');
}
}
}
result += getUnicodeString(fromDateTime, format, timeOptions, calendar, locale, digitSet);
return result;
}
// Original QDate::getFmtString() code taken from Qt 4.7 under LGPL, now heavily modifed
// Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
// Replaces tokens by their value. See QDateTime::toString() for a list of valid tokens
QString KDateTimeFormatter::getUnicodeString(const KDateTime &fromDateTime,
const QString &toFormat,
KLocale::TimeFormatOptions timeOptions,
const KCalendarSystem *calendar,
const KLocale *locale,
KLocale::DigitSet digitSet) const
{
if (toFormat.isEmpty()) {
return QString();
}
QString result = toFormat;
int removed = 0;
if (toFormat.startsWith(QLatin1String("dddd"))) {
result = calendar->weekDayName(fromDateTime.date(), KCalendarSystem::LongDayName);
removed = 4;
} else if (toFormat.startsWith(QLatin1String("ddd"))) {
result = calendar->weekDayName(fromDateTime.date(), KCalendarSystem::ShortDayName);
removed = 3;
} else if (toFormat.startsWith(QLatin1String("dd"))) {
result = QString::number(calendar->day(fromDateTime.date())).rightJustified(2, QLatin1Char('0'), true);
removed = 2;
} else if (toFormat.at(0) == QLatin1Char('d')) {
result = QString::number(calendar->day(fromDateTime.date()));
removed = 1;
} else if (toFormat.startsWith(QLatin1String("MMMM"))) {
result = calendar->monthName(calendar->month(fromDateTime.date()), calendar->year(fromDateTime.date()), KCalendarSystem::LongName);
removed = 4;
} else if (toFormat.startsWith(QLatin1String("MMM"))) {
result = calendar->monthName(calendar->month(fromDateTime.date()), calendar->year(fromDateTime.date()), KCalendarSystem::ShortName);
removed = 3;
} else if (toFormat.startsWith(QLatin1String("MM"))) {
result = QString::number(calendar->month(fromDateTime.date())).rightJustified(2, QLatin1Char('0'), true);
removed = 2;
} else if (toFormat.at(0) == QLatin1Char('M')) {
result = QString::number(calendar->month(fromDateTime.date()));
removed = 1;
} else if (toFormat.startsWith(QLatin1String("yyyy"))) {
const int year = calendar->year(fromDateTime.date());
result = QString::number(qAbs(year)).rightJustified(4, QLatin1Char('0'));
if (year > 0)
removed = 4;
else {
result.prepend(QLatin1Char('-'));
removed = 5;
}
} else if (toFormat.startsWith(QLatin1String("yy"))) {
result = QString::number(calendar->year(fromDateTime.date())).right(2).rightJustified(2, QLatin1Char('0'));
removed = 2;
}
if (removed == 0 || removed >= toFormat.size()) {
return result;
}
return result + getUnicodeString(fromDateTime, toFormat.mid(removed), timeOptions, calendar, locale, digitSet);
}
// Reimplement if special integer to string handling required, e.g. Hebrew.
// Utility to convert an integer into the correct display string form
QString KDateTimeFormatter::stringFromInteger(int number, int padWidth, QChar padChar, QChar signChar,
KLocale::DigitSet digitSet, const KLocale *locale) const
{
if (padChar == QChar() && signChar == QChar()) {
//kDebug() << " stringFromInteger(" << number << padWidth << "null" << "null" << ")";
} else if (padChar == QChar()) {
//kDebug() << " stringFromInteger(" << number << padWidth << "null" << signChar << ")";
} else if (signChar == QChar()) {
//kDebug() << " stringFromInteger(" << number << padWidth << padChar << "null" << ")";
} else if (signChar == QChar()) {
//kDebug() << " stringFromInteger(" << number << padWidth << padChar << signChar << ")";
}
QString result;
if (padChar == QChar() || padWidth == 0) { // If null pad char or 0 width don't bother padding
//kDebug() << " no pad";
if (signChar == QChar()) {
result = locale->convertDigits(QString::number(number), digitSet);
} else {
result = locale->convertDigits(QString::number(number).prepend(signChar), digitSet);
}
} else if (signChar != QChar()) { // If sign required
if (padChar == QLatin1Char('0')) { // If zero-padded, zero considered part of the number, so pad the number then prepend the sign
//kDebug() << " zero pad with sign";
result = locale->convertDigits(QString::number(number).rightJustified(padWidth, padChar).prepend(signChar), digitSet);
} else { // If space-padded space not considered part of the number, so prepend the sign and then pad the number
//kDebug() << " space pad with sign";
result = locale->convertDigits(QString::number(number).prepend(signChar).rightJustified(padWidth, padChar), digitSet);
}
} else { // No sign required so just pad
//kDebug() << " pad no sign";
result = locale->convertDigits(QString::number(number).rightJustified(padWidth, padChar), digitSet);
}
//kDebug() << " result = " << result;
return result;
}