10#include "alkdateformat.h"
12#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
13#include <KCalendarSystem>
18#include <QRegularExpression>
19#include <QRegularExpressionMatch>
22class AlkDateFormat::Private
26 AlkDateFormat::ErrorCode m_errorCode;
27 QString m_errorMessage;
29 QDate setError(AlkDateFormat::ErrorCode errorCode,
const QString& arg1 = QString(),
const QString& arg2 = QString())
31 m_errorCode = errorCode;
33 case AlkDateFormat::NoError:
34 m_errorMessage.clear();
36 case AlkDateFormat::InvalidFormatString:
37 m_errorMessage = QString(
"Invalid format string '%1'").arg(arg1);
39 case AlkDateFormat::InvalidFormatCharacter:
40 m_errorMessage = QString(
"Invalid format character '%1'").arg(arg1);
42 case AlkDateFormat::InvalidDate:
43 m_errorMessage = QString(
"Invalid date '%1'").arg(arg1);
45 case AlkDateFormat::InvalidDay:
46 m_errorMessage = QString(
"Invalid day entry: %1").arg(arg1);
48 case AlkDateFormat::InvalidMonth:
49 m_errorMessage = QString(
"Invalid month entry: %1").arg(arg1);
51 case AlkDateFormat::InvalidYear:
52 m_errorMessage = QString(
"Invalid year entry: %1").arg(arg1);
54 case AlkDateFormat::InvalidYearLength:
55 m_errorMessage = QString(
"Length of year (%1) does not match expected length (%2).").arg(arg1, arg2);
61 QDate convertStringSkrooge(
const QString &_in)
64 if (m_format ==
"UNIX") {
66 const quint64 unixTime = _in.
toUInt(&ok);
72 const QString skroogeFormat = m_format;
74 m_format = m_format.toLower();
76#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
78 if (formatrex.indexIn(m_format) == -1) {
79 return setError(AlkDateFormat::InvalidFormatString, m_format);
81 m_format = QLatin1String(
"%");
82 m_format.append(formatrex.cap(1));
83 m_format.append(formatrex.cap(2));
84 m_format.append(QLatin1String(
"%"));
85 m_format.append(formatrex.cap(3));
86 m_format.append(formatrex.cap(4));
87 m_format.append(QLatin1String(
"%"));
88 m_format.append(formatrex.cap(5));
91 auto match = formatrex.match(m_format);
92 if (!
match.hasMatch()) {
93 return setError(AlkDateFormat::InvalidFormatString, m_format);
96 m_format = QLatin1String(
"%");
97 m_format +=
match.captured(1);
98 m_format +=
match.captured(2);
99 m_format.append(QLatin1String(
"%"));
100 m_format +=
match.captured(3);
101 m_format +=
match.captured(4);
102 m_format.append(QLatin1String(
"%"));
103 m_format +=
match.captured(5);
105 date = convertStringKMyMoney(_in,
true, 2000);
106 m_format = skroogeFormat;
109 return setError(AlkDateFormat::InvalidDate, _in);
111 if (!m_format.contains(QStringLiteral(
"yyyy")) && date.
year() < 2000)
116 QDate convertStringUnix(
const QString& _in)
119 quint64 unixTime = _in.
toUInt(&ok);
121 return setError(AlkDateFormat::InvalidDate, _in);
123 if (m_format.startsWith(QLatin1String(
"%ud"))) {
129#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
131 QDate convertStringKMyMoney(
const QString &_in,
bool _strict,
unsigned _centurymidpoint)
133 if (m_format.startsWith(QLatin1String(
"%u"))) {
134 return convertStringUnix(_in);
142 if (formatrex.indexIn(m_format) == -1) {
143 return setError(AlkDateFormat::InvalidFormatString, m_format);
146 QStringList formatParts;
147 formatParts += formatrex.cap(1);
148 formatParts += formatrex.cap(3);
149 formatParts += formatrex.cap(5);
151 QStringList formatDelimiters;
152 formatDelimiters += formatrex.cap(2);
153 formatDelimiters += formatrex.cap(4);
156 QStringList::iterator it;
157 QRegExp specialChars(
"^[\\.\\\\\\?]$");
158 for(it = formatDelimiters.
begin(); it != formatDelimiters.
end(); ++it) {
159 if (specialChars.indexIn(*it) != -1)
174 inputrex.setPattern(QString(
"(\\w+)\\.?%1(\\w+)\\.?%2(\\w+)\\.?").arg(formatDelimiters[0],
175 formatDelimiters[1]));
177 inputrex.setPattern(
"(\\w+)\\W+(\\w+)\\W+(\\w+)");
180 if (inputrex.indexIn(_in) == -1) {
181 return setError(AlkDateFormat::InvalidDate, _in);
184 QStringList scannedParts;
185 scannedParts += inputrex.cap(1).toLower();
186 scannedParts += inputrex.cap(2).toLower();
187 scannedParts += inputrex.cap(3).toLower();
192 unsigned day = 0, month = 0, year = 0;
194 QRegExp digitrex(
"(\\d+)");
195 QStringList::const_iterator it_scanned = scannedParts.
constBegin();
196 QStringList::const_iterator it_format = formatParts.
constBegin();
197 while (it_scanned != scannedParts.
constEnd()) {
199 switch ((*it_format).at(0).cell()) {
203 if (digitrex.indexIn(*it_scanned) != -1) {
204 day = digitrex.cap(1).toUInt(&ok);
206 if (!ok || day > 31) {
207 return setError(AlkDateFormat::InvalidDay, *it_scanned);
211 month = (*it_scanned).toUInt(&ok);
216 if (KGlobal::locale()->calendar()->monthName(i, 2000).toLower() == *it_scanned
217 || KGlobal::locale()->calendar()->monthName(i, 2000,
218 KCalendarSystem::ShortName).
219 toLower() == *it_scanned) {
226 if (month < 1 || month > 12) {
227 return setError(AlkDateFormat::InvalidMonth, *it_scanned);
232 if (_strict && (*it_scanned).length() != (*it_format).length()) {
233 return setError(AlkDateFormat::InvalidYearLength, *it_scanned, *it_format);
236 year = (*it_scanned).toUInt(&ok);
239 return setError(AlkDateFormat::InvalidYear, *it_scanned);
249 unsigned centuryend = _centurymidpoint + 50;
250 unsigned centurybegin = _centurymidpoint - 50;
252 if (year < centuryend % 100) {
255 year += centurybegin - centurybegin % 100;
264 return setError(AlkDateFormat::InvalidFormatCharacter, QString((*it_format).at(0).cell()));
270 QDate result(year, month, day);
271 if (!result.isValid()) {
272 return setError(AlkDateFormat::InvalidDate, QString(
"yr:%1 mo:%2 dy:%3)").arg(year).arg(month).arg(day));
280 QDate convertStringKMyMoney(
const QString& _in,
bool _strict,
unsigned _centurymidpoint)
282 if (m_format.startsWith(QLatin1String(
"%u"))) {
283 return convertStringUnix(_in);
291 QRegularExpressionMatch
match = formatrex.match(m_format);
292 if (!
match.hasMatch()) {
293 return setError(AlkDateFormat::InvalidFormatString, m_format);
296 QStringList formatParts;
297 formatParts +=
match.captured(1);
298 formatParts +=
match.captured(3);
299 formatParts +=
match.captured(5);
301 QStringList formatDelimiters;
302 formatDelimiters +=
match.captured(2);
303 formatDelimiters +=
match.captured(4);
306 QStringList::iterator it;
307 QRegularExpression specialChars(
"^[\\.\\\\\\?]$");
308 for(it = formatDelimiters.
begin(); it != formatDelimiters.
end(); ++it) {
309 QRegularExpressionMatch
special = specialChars.match(*it);
319 QRegularExpression inputrex;
325 inputrex.
setPattern(QString(
"(\\w+)\\.?%1(\\w+)\\.?%2(\\w+)\\.?").arg(formatDelimiters[0], formatDelimiters[1]));
327 inputrex.
setPattern(
"(\\w+)\\W+(\\w+)\\W+(\\w+)");
330 if (!
match.hasMatch()) {
331 return setError(AlkDateFormat::InvalidDate, _in);
334 QStringList scannedParts;
335 scannedParts +=
match.captured(1).toLower();
336 scannedParts +=
match.captured(2).toLower();
337 scannedParts +=
match.captured(3).toLower();
342 unsigned day = 0, month = 0, year = 0;
344 QRegularExpression digitrex(
"(\\d+)");
345 QStringList::const_iterator it_scanned = scannedParts.
constBegin();
346 QStringList::const_iterator it_format = formatParts.
constBegin();
347 while (it_scanned != scannedParts.
constEnd()) {
349 switch ((*it_format).at(0).cell()) {
353 match = digitrex.match(*it_scanned);
354 if (
match.hasMatch())
355 day =
match.captured(1).toUInt(&ok);
357 return setError(AlkDateFormat::InvalidDay, *it_scanned);
360 month = (*it_scanned).toUInt(&ok);
379 if( !(locale == localeC)) {
382 if (localeC.standaloneMonthName(i).toLower() == *it_scanned
393 if (month < 1 || month > 12)
394 return setError(AlkDateFormat::InvalidMonth, *it_scanned);
398 if (_strict && (*it_scanned).length() != (*it_format).length())
399 return setError(AlkDateFormat::InvalidYearLength, *it_scanned, *it_format);
401 year = (*it_scanned).toUInt(&ok);
404 return setError(AlkDateFormat::InvalidYear, *it_scanned);
413 unsigned centuryend = _centurymidpoint + 50;
414 unsigned centurybegin = _centurymidpoint - 50;
416 if (year < centuryend % 100)
418 year += centurybegin - centurybegin % 100;
426 return setError(AlkDateFormat::InvalidFormatCharacter, QString(QChar((*it_format).at(0).cell())));
432 QDate result(year, month, day);
433 if (! result.isValid())
434 return setError(AlkDateFormat::InvalidDate, QString(
"yr:%1 mo:%2 dy:%3)").arg(year).arg(month).arg(day));
442AlkDateFormat::AlkDateFormat(
const QString &format)
445 d->m_format = format;
452 d->m_format =
right.d->m_format;
456AlkDateFormat::~AlkDateFormat()
463 d->m_format =
right.d->m_format;
468const QString & AlkDateFormat::format()
const
473AlkDateFormat::ErrorCode AlkDateFormat::lastError()
const
475 return d->m_errorCode;
478QString AlkDateFormat::lastErrorMessage()
const
480 return d->m_errorMessage;
483QDate AlkDateFormat::convertString(
const QString& date,
bool strict,
unsigned int centuryMidPoint)
486 d->m_errorCode = NoError;
487 d->m_errorMessage.clear();
489 if (d->m_format.contains(
"%"))
490 return d->convertStringKMyMoney(date, strict, centuryMidPoint);
492 return d->convertStringSkrooge(date);
500 d->m_errorCode = NoError;
501 d->m_errorMessage.clear();
KCOREADDONS_EXPORT Result match(QStringView pattern, QStringView str)
KIOCORE_EXPORT SimpleJob * special(const QUrl &url, const QByteArray &data, JobFlags flags=DefaultFlags)
QDate addYears(int nyears) const const
bool isValid(int year, int month, int day)
QDateTime fromMSecsSinceEpoch(qint64 msecs)
const_iterator constBegin() const const
const_iterator constEnd() const const
QString standaloneMonthName(int month, FormatType type) const const
QRegularExpressionMatch match(QStringView subjectView, qsizetype offset, MatchType matchType, MatchOptions matchOptions) const const
void setPattern(const QString &pattern)
void setPatternOptions(PatternOptions options)
QString number(double n, char format, int precision)
QString toLower() const const
uint toUInt(bool *ok, int base) const const
QTextStream & right(QTextStream &stream)