24 #include <config-date.h>
26 #ifdef HAVE_SYS_TIME_H
36 #include <QtCore/QDateTime>
37 #include <QtCore/QRegExp>
38 #include <QtCore/QStringList>
39 #include <QtCore/QSharedData>
58 "Monday",
"Tuesday",
"Wednesday",
59 "Thursday",
"Friday",
"Saturday",
63 "Jan",
"Feb",
"Mar",
"Apr",
64 "May",
"Jun",
"Jul",
"Aug",
65 "Sep",
"Oct",
"Nov",
"Dec"
68 "January",
"February",
"March",
69 "April",
"May",
"June",
70 "July",
"August",
"September",
71 "October",
"November",
"December"
83 QString& zoneName, QByteArray& zoneAbbrev,
bool& dateOnly,
Status&);
88 static bool getNumber(
const QString &
string,
int &offset,
int mindigits,
int maxdigits,
int minval,
int maxval,
int &result);
90 template<
int disp>
static inline
98 #ifdef COMPILING_TESTS
99 KDECORE_EXPORT
int KDateTime_utcCacheHit = 0;
100 KDECORE_EXPORT
int KDateTime_zoneCacheHit = 0;
105 class KDateTimeSpecPrivate
108 KDateTimeSpecPrivate() : utcOffset(0) {}
117 : d(new KDateTimeSpecPrivate)
123 : d(new KDateTimeSpecPrivate())
129 : d(new KDateTimeSpecPrivate())
135 : d(new KDateTimeSpecPrivate())
149 d->type = spec.d->type;
153 d->utcOffset = spec.d->utcOffset;
223 if (d->type != other.d->type
232 if (d->type == other.d->type)
255 s << static_cast<quint8>(
'u');
258 s << static_cast<quint8>(
'o') << spec.
utcOffset();
264 s << static_cast<quint8>(
'c');
268 s << static_cast<quint8>(
' ');
280 switch (static_cast<char>(t))
323 convertedCached(false),
324 m2ndOccurrence(false),
335 convertedCached(false),
336 m2ndOccurrence(false),
356 KDateTimePrivate(
const KDateTimePrivate &rhs)
359 specZone(rhs.specZone),
360 specUtcOffset(rhs.specUtcOffset),
362 converted(rhs.converted),
363 specType(rhs.specType),
365 utcCached(rhs.utcCached),
366 convertedCached(rhs.convertedCached),
367 m2ndOccurrence(rhs.m2ndOccurrence),
368 mDateOnly(rhs.mDateOnly),
369 converted2ndOccur(rhs.converted2ndOccur)
372 ~KDateTimePrivate() {}
373 const QDateTime& dt()
const {
return mDt; }
374 const QDate
date()
const {
return mDt.date(); }
377 bool dateOnly()
const {
return mDateOnly; }
378 bool secondOccurrence()
const {
return m2ndOccurrence; }
379 void setDt(
const QDateTime &dt) { mDt = dt; utcCached = convertedCached = m2ndOccurrence =
false; }
380 void setDtFromUtc(
const QDateTime &utcdt);
381 void setDate(
const QDate &d) { mDt.setDate(d); utcCached = convertedCached = m2ndOccurrence =
false; }
382 void setTime(
const QTime &t) { mDt.setTime(t); utcCached = convertedCached = mDateOnly = m2ndOccurrence =
false; }
383 void setDtTimeSpec(Qt::TimeSpec s) { mDt.setTimeSpec(s); utcCached = convertedCached = m2ndOccurrence =
false; }
386 int timeZoneOffset()
const;
390 bool equalSpec(
const KDateTimePrivate&)
const;
391 void clearCache() { utcCached = convertedCached =
false; }
395 ut.date = utcDt.date();
396 ut.time = utcDt.time();
398 convertedCached =
false;
399 m2ndOccurrence =
false;
406 convertedCached =
false;
418 converted.date = dt.date();
419 converted.time = dt.time();
421 convertedCached =
true;
422 converted2ndOccur =
false;
429 return *s_fromStringDefault;
435 static qint64 currentDateTimeOffset;
453 mutable struct converted {
461 mutable bool utcCached : 1;
462 mutable bool convertedCached : 1;
463 mutable bool m2ndOccurrence : 1;
466 mutable bool converted2ndOccur : 1;
470 QTime KDateTimePrivate::sod(0,0,0);
472 qint64 KDateTimePrivate::currentDateTimeOffset = 0;
485 if (specType == other.
type())
500 if (specUtcOffset == offset)
502 specUtcOffset = offset;
512 specType = other.
type();
530 convertedCached =
false;
531 setDtTimeSpec((specType ==
KDateTime::UTC) ? Qt::UTC : Qt::LocalTime);
534 bool KDateTimePrivate::equalSpec(
const KDateTimePrivate &other)
const
536 if (specType != other.specType
543 void KDateTimePrivate::setDateOnly(
bool dateOnly)
545 if (dateOnly != mDateOnly)
547 mDateOnly = dateOnly;
548 if (dateOnly && mDt.time() != sod)
552 convertedCached =
false;
554 m2ndOccurrence =
false;
559 void KDateTimePrivate::setDtFromUtc(
const QDateTime &utcdt)
568 QDateTime local = utcdt.addSecs(specUtcOffset);
569 local.setTimeSpec(Qt::LocalTime);
576 setDt(specZone.toZoneTime(utcdt, &second), utcdt);
577 m2ndOccurrence = second;
582 setDt(specZone.toZoneTime(utcdt), utcdt);
592 int KDateTimePrivate::timeZoneOffset()
const
599 dt.setTimeSpec(Qt::UTC);
600 return utc().secsTo(dt);
603 if (!specZone.isValid()) {
606 int offset = specZone.offsetAtZoneTime(mDt, &secondOffset);
609 m2ndOccurrence = (secondOffset != offset);
610 offset = secondOffset;
616 convertedCached =
false;
622 utcdt.setTimeSpec(Qt::UTC);
623 setUtc(utcdt.addSecs(-offset));
648 #ifdef COMPILING_TESTS
649 ++KDateTime_utcCacheHit;
657 #ifdef COMPILING_TESTS
658 ++KDateTime_utcCacheHit;
684 const_cast<KDateTimePrivate*
>(
this)->specZone = loc;
703 convertedCached =
false;
714 if (convertedCached && converted.tz == zone)
717 #ifdef COMPILING_TESTS
719 ++KDateTime_zoneCacheHit;
721 return QDateTime(converted.date, converted.time, Qt::LocalTime);
728 converted.date = result.date();
729 converted.time = result.time();
731 convertedCached =
true;
732 converted2ndOccur = second;
741 void KDateTimePrivate::newToZone(KDateTimePrivate *newd,
const KTimeZone &zone,
const KTimeZone &local)
const
743 newd->mDt =
toZone(zone, local);
744 newd->specZone = zone;
746 newd->utcCached = utcCached;
747 newd->mDateOnly = mDateOnly;
748 newd->m2ndOccurrence = converted2ndOccur;
752 newd->ut.date = mDt.date();
753 newd->ut.time = mDt.time();
757 newd->converted.date = mDt.date();
758 newd->converted.time = mDt.time();
759 newd->converted.tz = specZone;
760 newd->convertedCached =
true;
761 newd->converted2ndOccur = m2ndOccurrence;
768 newd->convertedCached =
false;
776 : d(*emptyDateTimePrivate)
781 : d(new KDateTimePrivate(
QDateTime(date, KDateTimePrivate::sod, Qt::LocalTime), spec, true))
784 d->setDtTimeSpec(Qt::UTC);
788 : d(new KDateTimePrivate(
QDateTime(date, time, Qt::LocalTime), spec))
791 d->setDtTimeSpec(Qt::UTC);
795 : d(new KDateTimePrivate(dt, spec))
800 if (dt.timeSpec() == Qt::LocalTime)
803 else if (dt.timeSpec() == Qt::UTC)
808 : d(new KDateTimePrivate(dt, (dt.timeSpec() == Qt::LocalTime ?
Spec(LocalZone) :
Spec(UTC))))
863 return d->timeZoneOffset();
865 return d->specUtcOffset;
875 if (d->specType ==
UTC)
899 qdt.setTimeSpec(Qt::LocalTime);
903 offset = d->timeZoneOffset();
920 if (d->specType ==
OffsetFromUTC && d->specUtcOffset == utcOffset)
932 if (d->specType ==
TimeZone && d->specZone == local)
943 d->newToZone(result.d, local, local);
970 if (d->specType ==
TimeZone && d->specZone == zone)
975 d->newToZone(result.d, zone);
986 if (spec == d->spec())
995 d->newToZone(result.d, spec.
timeZone());
1006 return qdt.toTime_t();
1012 int days =
static_cast<int>(seconds / 86400);
1013 int secs =
static_cast<int>(seconds % 86400);
1015 dt.setTimeSpec(Qt::UTC);
1017 d->setDt(dt.addDays(days).addSecs(secs));
1022 d->setDateOnly(dateOnly);
1038 d->setDateOnly(
false);
1039 if (dt.timeSpec() == Qt::LocalTime)
1041 if (d->specType ==
UTC)
1047 d->setDtFromUtc(dt);
1059 d->m2ndOccurrence = second;
1065 d->timeZoneOffset();
1079 result.d->setDate(d->date().addDays(static_cast<int>(msecs / 86400000)));
1082 qint64 secs = msecs / 1000;
1083 int oldms = d->dt().time().msec();
1084 int ms = oldms +
static_cast<int>(msecs % 1000);
1102 QTime t = result.
time();
1103 result.d->setTime(QTime(t.hour(), t.minute(), t.second(), ms));
1113 int days =
static_cast<int>(secs / 86400);
1114 int seconds =
static_cast<int>(secs % 86400);
1118 result.d->setDate(d->date().addDays(days));
1124 qdt.setTimeSpec(Qt::UTC);
1125 qdt = qdt.addDays(days).addSecs(seconds);
1126 qdt.setTimeSpec(Qt::LocalTime);
1129 return KDateTime(d->toUtc().addDays(days).addSecs(seconds), d->spec());
1137 result.d->setDate(d->date().addDays(days));
1146 result.d->setDate(d->date().addMonths(months));
1155 result.d->setDate(d->date().addYears(years));
1170 QDate dat = t2.d->dateOnly() ? t2.d->date() : t2.
toTimeSpec(d->spec()).d->
date();
1171 return static_cast<qint64>(d->date().daysTo(dat)) * 86400;
1173 if (t2.d->dateOnly())
1174 return static_cast<qint64>(
toTimeSpec(t2.d->spec()).d->
date().daysTo(t2.d->date())) * 86400;
1181 dt1.setTimeSpec(Qt::UTC);
1183 dt2.setTimeSpec(Qt::UTC);
1184 return dt1.secsTo(dt2);
1189 dt2 = t2.d->toUtc();
1191 return static_cast<qint64>(dt1.date().daysTo(dt2.date())) * 86400
1192 + dt1.time().secsTo(dt2.time());
1201 QDate dat = t2.d->dateOnly() ? t2.d->date() : t2.
toTimeSpec(d->spec()).d->
date();
1202 return d->date().daysTo(dat);
1204 if (t2.d->dateOnly())
1208 switch (d->specType)
1211 dat = t2.d->toUtc().date();
1214 dat = t2.d->toUtc().addSecs(d->specUtcOffset).date();
1217 dat = t2.d->toZone(d->specZone).date();
1222 dat = t2.d->toZone(local, local).date();
1228 return d->date().daysTo(dat);
1245 memset(&st, 0,
sizeof(SYSTEMTIME));
1247 result =
KDateTime(QDate(st.wYear, st.wMonth, st.wDay),
1248 QTime(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds),
1253 result.
setTime_t(static_cast<qint64>(t));
1256 return result.
addSecs(KDateTimePrivate::currentDateTimeOffset);
1264 switch (spec.
type())
1293 const bool conv = (!d->equalSpec(*other.d) || d->secondOccurrence() != other.d->secondOccurrence());
1298 start1 = d->toUtc();
1299 start2 = other.d->toUtc();
1305 start2 = other.d->dt();
1307 if (d->dateOnly() || other.d->dateOnly())
1317 kdt.
setTime(QTime(23,59,59,999));
1318 end1 = kdt.d->toUtc();
1322 if (other.d->dateOnly())
1325 kdt.
setTime(QTime(23,59,59,999));
1326 end2 = kdt.d->toUtc();
1334 end1 =
QDateTime(d->date(), QTime(23,59,59,999), Qt::LocalTime);
1337 if (other.d->dateOnly())
1338 end2 =
QDateTime(other.d->date(), QTime(23,59,59,999), Qt::LocalTime);
1340 end2 = other.d->dt();
1342 if (start1 == start2)
1343 return !d->dateOnly() ?
AtStart : (end1 == end2) ?
Equal
1346 if (start1 < start2)
1347 return (end1 < start2) ?
Before
1349 : (end1 == start2) ? static_cast<Comparison>(
Before|
AtStart)
1352 return (start1 > end2) ?
After
1353 : (start1 == end2) ? (end1 == end2 ?
AtEnd : static_cast<Comparison>(
AtEnd|
After))
1364 if (d->dateOnly() != other.d->dateOnly())
1366 if (d->equalSpec(*other.d))
1370 return d->date() == other.d->date();
1372 return d->secondOccurrence() == other.d->secondOccurrence()
1373 && d->dt() == other.d->dt();
1376 if (qAbs(d->date().daysTo(other.d->date())) > 2)
1381 if (d->toUtc() != other.d->toUtc())
1384 end1.
setTime(QTime(23,59,59,999));
1386 end2.
setTime(QTime(23,59,59,999));
1387 return end1.d->toUtc() == end2.d->toUtc();
1389 return d->toUtc() == other.d->toUtc();
1396 if (d->equalSpec(*other.d))
1399 if (d->dateOnly() || other.d->dateOnly())
1400 return d->date() < other.d->date();
1401 if (d->secondOccurrence() == other.d->secondOccurrence())
1402 return d->dt() < other.d->dt();
1406 const int dayDiff = d->date().daysTo(other.d->date());
1415 const int dayDiff = d->date().daysTo(other.d->date());
1428 kdt.
setTime(QTime(23,59,59,999));
1429 return kdt.d->toUtc() < other.d->toUtc();
1431 return d->toUtc() < other.d->toUtc();
1438 enum { TZNone, UTCOffsetShort, UTCOffset, UTCOffsetColon, TZAbbrev, TZName };
1443 int num, numLength, zone;
1444 bool escape =
false;
1446 for (
int i = 0, end = format.length(); i < end; ++i)
1451 ushort ch = format[i].unicode();
1457 result += format[i];
1465 result += QLatin1Char(
'%');
1471 num = d->date().year();
1475 num = d->date().year() % 100;
1480 num = d->date().month();
1492 num = d->date().day();
1504 num = d->dt().time().hour();
1510 num = (d->dt().time().hour() + 11) % 12 + 1;
1513 num = d->dt().time().minute();
1517 num = d->dt().time().second();
1522 bool am = (d->dt().time().hour() < 12);
1525 result += am ? QLatin1String(
"am") : QLatin1String(
"pm");
1532 bool am = (d->dt().time().hour() < 12);
1535 result += am ? QLatin1String(
"AM") : QLatin1String(
"PM");
1547 result += QLatin1Char(
'%');
1548 result += format[i];
1552 else if (flag ==
':')
1558 result += QLatin1String(
longDay[d->date().dayOfWeek() - 1]);
1561 result += QLatin1String(
shortDay[d->date().dayOfWeek() - 1]);
1564 result += QLatin1String(
longMonth[d->date().month() - 1]);
1567 result += QLatin1String(
shortMonth[d->date().month() - 1]);
1570 num = d->date().month();
1573 result += (d->dt().time().hour() < 12) ? QLatin1String(
"am") : QLatin1String(
"pm");
1576 result += (d->dt().time().hour() < 12) ? QLatin1String(
"AM") : QLatin1String(
"PM");
1580 int sec = d->dt().time().second();
1581 if (sec || d->dt().time().msec())
1583 result += QLatin1Char(
':');
1590 result += s.sprintf(
"%03d", d->dt().time().msec());
1593 zone = UTCOffsetShort;
1596 zone = UTCOffsetColon;
1602 result += QLatin1String(
"%:");
1603 result += format[i];
1615 result += QString::number(num);
1616 else if (numLength == 2 || numLength == 4)
1621 result += QLatin1Char(
'-');
1623 result += s.sprintf((numLength == 2 ?
"%02d" :
"%04d"), num);
1626 else if (zone != TZNone)
1630 switch (d->specType)
1637 offset = (d->specType ==
TimeZone) ? d->timeZoneOffset()
1642 case UTCOffsetShort:
1644 case UTCOffsetColon:
1647 result += QLatin1Char(
'+');
1650 result += QLatin1Char(
'-');
1654 result += s.sprintf(((zone == UTCOffsetColon) ?
"%02d:" :
"%02d"), offset/60);
1655 if (ch !=
'u' || offset % 60)
1656 result += s.sprintf(
"%02d", offset % 60);
1661 result += QString::fromLatin1(tz.
abbreviation(d->toUtc()));
1665 result += tz.
name();
1686 const char *tzcolon =
"";
1691 result += QString::fromLatin1(
shortDay[d->date().dayOfWeek() - 1]);
1692 result += QLatin1String(
", ");
1696 char seconds[8] = { 0 };
1697 if (d->dt().time().second())
1698 sprintf(seconds,
":%02d", d->dt().time().second());
1699 result += s.sprintf(
"%02d %s ", d->date().day(),
shortMonth[d->date().month() - 1]);
1700 int year = d->date().year();
1703 result += QLatin1Char(
'-');
1706 result += s.sprintf(
"%04d %02d:%02d%s ",
1707 year, d->dt().time().hour(), d->dt().time().minute(), seconds);
1715 result += s.sprintf(
"%04d-%02d-%02dT%02d:%02d:%02d",
1716 d->date().year(), d->date().month(), d->date().day(),
1717 d->dt().time().hour(), d->dt().time().minute(), d->dt().time().second());
1718 int msec = d->dt().time().msec();
1723 msec /= 10, --digits;
1725 msec /= 10, --digits;
1726 result += s.sprintf(
".%0*d", digits, d->dt().time().msec());
1728 if (d->specType ==
UTC)
1729 return result + QLatin1Char(
'Z');
1738 int year = d->date().year();
1741 result += QLatin1Char(
'-');
1745 result += s.sprintf(
"%04d-%02d-%02d",
1746 year, d->date().month(), d->date().day());
1747 if (!d->dateOnly() || d->specType !=
ClockTime)
1749 result += s.sprintf(
"T%02d:%02d:%02d",
1750 d->dt().time().hour(), d->dt().time().minute(), d->dt().time().second());
1751 if (d->dt().time().msec())
1756 result += (locale && locale->
decimalSymbol() == QLatin1String(
".")) ? QLatin1Char(
'.') : QLatin1Char(
',');
1757 result += s.sprintf(
"%03d", d->dt().time().msec());
1760 if (d->specType ==
UTC)
1761 return result + QLatin1Char(
'Z');
1770 Qt::DateFormat qtfmt = (format ==
QtTextDate) ? Qt::TextDate : Qt::LocalDate;
1772 result = d->date().toString(qtfmt);
1774 result = d->dt().toString(qtfmt);
1775 if (result.isEmpty() || d->specType ==
ClockTime)
1777 result += QLatin1Char(
' ');
1788 offset = d->timeZoneOffset();
1798 return result + s.sprintf(
"%c%02d%s%02d", tzsign, offset/60, tzcolon, offset%60);
1805 QString str =
string.trimmed();
1822 QRegExp rx(QString::fromLatin1(
"^(?:([A-Z][a-z]+),\\s*)?(\\d{1,2})(\\s+|-)([^-\\s]+)(\\s+|-)(\\d{2,4})\\s+(\\d\\d):(\\d\\d)(?::(\\d\\d))?\\s+(\\S+)$"));
1824 if (!str.indexOf(rx))
1827 parts = rx.capturedTexts();
1828 bool h1 = (parts[3] == QLatin1String(
"-"));
1829 bool h2 = (parts[5] == QLatin1String(
"-"));
1836 rx = QRegExp(QString::fromLatin1(
"^([A-Z][a-z]+)\\s+(\\S+)\\s+(\\d\\d)\\s+(\\d\\d):(\\d\\d):(\\d\\d)\\s+(\\d\\d\\d\\d)$"));
1837 if (str.indexOf(rx))
1846 parts = rx.capturedTexts();
1849 int day = parts[nday].toInt(&ok[0]);
1850 int year = parts[nyear].toInt(&ok[1]);
1851 int hour = parts[nhour].toInt(&ok[2]);
1852 int minute = parts[nmin].toInt(&ok[3]);
1853 if (!ok[0] || !ok[1] || !ok[2] || !ok[3])
1856 if (!parts[nsec].isEmpty())
1858 second = parts[nsec].toInt(&ok[0]);
1862 bool leapSecond = (second == 60);
1866 for ( ; month < 12 && parts[nmonth] != QLatin1String(
shortMonth[month]); ++month) ;
1868 if (!parts[nwday].isEmpty())
1871 while (++dayOfWeek < 7 && QLatin1String(
shortDay[dayOfWeek]) != parts[nwday]) ;
1873 for (dayOfWeek = 0; dayOfWeek < 7 && QLatin1String(
longDay[dayOfWeek]) != parts[nwday]; ++dayOfWeek) ;
1875 if (month >= 12 || dayOfWeek >= 7
1878 int i = parts[nyear].size();
1882 year += (i == 2 && year < 50) ? 2000 : 1900;
1887 bool negOffset =
false;
1888 if (parts.count() > 10)
1890 rx = QRegExp(QString::fromLatin1(
"^([+-])(\\d\\d)(\\d\\d)$"));
1894 parts = rx.capturedTexts();
1895 offset = parts[2].toInt(&ok[0]) * 3600;
1896 int offsetMin = parts[3].toInt(&ok[1]);
1897 if (!ok[0] || !ok[1] || offsetMin > 59)
1899 offset += offsetMin * 60;
1900 negOffset = (parts[1] == QLatin1String(
"-"));
1907 QByteArray zone = parts[10].toLatin1();
1908 if (zone.length() == 1 &&
isalpha(zone[0]) && toupper(zone[0]) !=
'J')
1910 else if (zone !=
"UT" && zone !=
"GMT")
1912 offset = (zone ==
"EDT") ? -4*3600
1913 : (zone ==
"EST" || zone ==
"CDT") ? -5*3600
1914 : (zone ==
"CST" || zone ==
"MDT") ? -6*3600
1915 : (zone ==
"MST" || zone ==
"PDT") ? -7*3600
1916 : (zone ==
"PST") ? -8*3600
1921 bool nonalpha =
false;
1922 for (
int i = 0, end = zone.size(); i < end && !nonalpha; ++i)
1933 QDate qdate =
checkDate(year, month+1, day, invalid);
1934 if (!qdate.isValid())
1938 || (dayOfWeek >= 0 && result.
date().dayOfWeek() != dayOfWeek+1))
1942 if (negOffset && negZero)
1950 if ((hour*3600 + minute*60 + 60 - offset + 86400*5) % 86400)
1956 dt.d->status = invalid;
1963 QRegExp rx(QString::fromLatin1(
"^(\\d{4})-(\\d\\d)-(\\d\\d)[Tt](\\d\\d):(\\d\\d):(\\d\\d)(?:\\.(\\d+))?([Zz]|([+-])(\\d\\d):(\\d\\d))$"));
1964 if (str.indexOf(rx))
1969 bool leapSecond =
false;
1970 int year = parts[1].toInt(&ok);
1971 int month = parts[2].toInt(&ok1);
1972 int day = parts[3].toInt(&ok2);
1973 if (!ok || !ok1 || !ok2)
1975 QDate d(year, month, day);
1978 int hour = parts[4].toInt(&ok);
1979 int minute = parts[5].toInt(&ok1);
1980 int second = parts[6].toInt(&ok2);
1981 if (!ok || !ok1 || !ok2)
1983 leapSecond = (second == 60);
1986 if (!parts[7].isEmpty())
1988 QString ms = parts[7] + QLatin1String(
"00");
1990 msecs = ms.toInt(&ok);
1993 if (msecs && leapSecond)
1996 QTime t(hour, minute, second, msecs);
2003 offset = parts[10].toInt(&ok) * 3600;
2004 offset += parts[11].toInt(&ok1) * 60;
2007 if (parts[9] == QLatin1String(
"-"))
2009 if (!offset && leapSecond)
2012 if (!offset && negZero)
2020 if ((hour*3600 + minute*60 + 60 - offset + 86400*5) % 86400)
2044 bool dateOnly =
false;
2046 QRegExp rx(QString::fromLatin1(
"^([+-])?(\\d{4,})-(\\d\\d\\d|\\d\\d-\\d\\d)[T ](\\d\\d)(?::(\\d\\d)(?::(\\d\\d)(?:(?:\\.|,)(\\d+))?)?)?(Z|([+-])(\\d\\d)(?::(\\d\\d))?)?$"));
2047 if (str.indexOf(rx))
2050 rx = QRegExp(QString::fromLatin1(
"^([+-])?(\\d{4,})(\\d{4})[T ](\\d\\d)(?:(\\d\\d)(?:(\\d\\d)(?:(?:\\.|,)(\\d+))?)?)?(Z|([+-])(\\d\\d)(\\d\\d)?)?$"));
2051 if (str.indexOf(rx))
2053 rx = QRegExp(QString::fromLatin1(
"^([+-])?(\\d{4})(\\d{3})[T ](\\d\\d)(?:(\\d\\d)(?:(\\d\\d)(?:(?:\\.|,)(\\d+))?)?)?(Z|([+-])(\\d\\d)(\\d\\d)?)?$"));
2054 if (str.indexOf(rx))
2058 rx = QRegExp(QString::fromLatin1(
"^([+-])?(\\d{4,})-(\\d\\d\\d|\\d\\d-\\d\\d)$"));
2059 if (str.indexOf(rx))
2062 rx = QRegExp(QString::fromLatin1(
"^([+-])?(\\d{4,})(\\d{4})$"));
2063 if (str.indexOf(rx))
2065 rx = QRegExp(QString::fromLatin1(
"^([+-])?(\\d{4})(\\d{3})$"));
2066 if (str.indexOf(rx))
2080 bool leapSecond =
false;
2081 int year = parts[2].toInt(&ok);
2084 if (parts[1] == QLatin1String(
"-"))
2088 hour = parts[4].toInt(&ok);
2091 if (!parts[5].isEmpty())
2093 minute = parts[5].toInt(&ok);
2097 if (!parts[6].isEmpty())
2099 second = parts[6].toInt(&ok);
2103 leapSecond = (second == 60);
2106 if (!parts[7].isEmpty())
2108 QString ms = parts[7] + QLatin1String(
"00");
2110 msecs = ms.toInt(&ok);
2117 if (parts[3].length() == 3)
2120 day = parts[3].toInt(&ok);
2121 if (!ok || day < 1 || day > 366)
2123 d =
checkDate(year, 1, 1, invalid).addDays(day - 1);
2124 if (!d.isValid() || (!invalid && d.year() != year))
2132 month = parts[3].left(2).toInt(&ok);
2133 day = parts[3].right(2).toInt(&ok1);
2136 d =
checkDate(year, month, day, invalid);
2145 dt.d->status = invalid;
2150 if (hour == 24 && !minute && !second && !msecs)
2157 QTime t(hour, minute, second, msecs);
2160 if (parts[8].isEmpty())
2166 dt.d->status = invalid;
2169 return KDateTime(d, t, KDateTimePrivate::fromStringDefault());
2175 offset = parts[10].toInt(&ok) * 3600;
2178 if (!parts[11].isEmpty())
2180 offset += parts[11].toInt(&ok) * 60;
2184 if (parts[9] == QLatin1String(
"-"))
2187 if (!offset && negZero)
2195 if ((hour*3600 + minute*60 + 60 - offset + 86400*5) % 86400)
2201 dt.d->status = invalid;
2209 QRegExp rx(QString::fromLatin1(
"^(\\S+\\s+\\S+\\s+\\d\\d\\s+(\\d\\d:\\d\\d:\\d\\d\\s+)?\\d\\d\\d\\d)\\s*(.*)$"));
2210 if (str.indexOf(rx) < 0)
2215 bool dateOnly = parts[2].isEmpty();
2218 qd = QDate::fromString(parts[1], Qt::TextDate);
2224 qdt = QDateTime::fromString(parts[1], Qt::TextDate);
2228 if (parts[3].isEmpty())
2232 return KDateTime(qd, KDateTimePrivate::fromStringDefault());
2236 return KDateTime(qdt.date(), qdt.time(), KDateTimePrivate::fromStringDefault());
2239 rx = QRegExp(QString::fromLatin1(
"([+-])([\\d][\\d])(?::?([\\d][\\d]))?$"));
2245 parts = rx.capturedTexts();
2246 offset = parts[2].toInt(&ok) * 3600;
2249 if (parts.count() > 3)
2251 offset += parts[3].toInt(&ok) * 60;
2255 if (parts[1] == QLatin1String(
"-"))
2258 if (!offset && negZero)
2263 qdt.setTimeSpec(offset ? Qt::LocalTime : Qt::UTC);
2274 const KTimeZones *zones,
bool offsetIfAmbiguous)
2277 bool dateOnly =
false;
2280 QByteArray zoneAbbrev;
2281 QDateTime qdt =
fromStr(
string, format, utcOffset, zoneName, zoneAbbrev, dateOnly, invalid);
2289 if (!zoneName.isEmpty())
2293 zone = zones->
zone(zoneName);
2298 if (!zoneAbbrev.isEmpty())
2303 bool useUtcOffset =
false;
2305 for (KTimeZones::ZoneMap::ConstIterator it = z.constBegin(); it != z.constEnd(); ++it)
2307 if (it.value().abbreviations().contains(zoneAbbrev))
2310 int offset = it.value().offsetAtZoneTime(qdt, &offset2);
2312 ut.setTimeSpec(Qt::UTC);
2313 ut.addSecs(-offset);
2314 if (it.value().abbreviation(ut) != zoneAbbrev)
2316 if (offset == offset2)
2318 ut.addSecs(offset - offset2);
2319 if (it.value().abbreviation(ut) != zoneAbbrev)
2327 if (!offsetIfAmbiguous || offset != utcOffset)
2329 useUtcOffset =
true;
2342 qdt.setTimeSpec(Qt::UTC);
2347 else if (utcOffset || qdt.timeSpec() == Qt::UTC)
2353 dtUTC.setTimeSpec(Qt::UTC);
2354 dtUTC.addSecs(-utcOffset);
2356 for (KTimeZones::ZoneMap::ConstIterator it = z.constBegin(); it != z.constEnd(); ++it)
2358 QList<int> offsets = it.value().utcOffsets();
2359 if ((offsets.isEmpty() || offsets.contains(utcOffset))
2360 && it.value().offsetAtUtc(dtUTC) ==
utcOffset)
2366 if (!offsetIfAmbiguous)
2371 dt.d->status = invalid;
2376 qdt.setTimeSpec(Qt::LocalTime);
2386 if (zone.
isValid() && !invalid)
2398 dt.d->status = invalid;
2404 qdt.setTimeSpec(Qt::LocalTime);
2407 else if (qdt.timeSpec() == Qt::UTC)
2412 result.
setTimeSpec(KDateTimePrivate::fromStringDefault());
2421 KDateTimePrivate::fromStringDefault() = spec;
2435 KDateTimePrivate::currentDateTimeOffset = 0;
2462 s >> d >> t >> spec >> flags;
2478 QString& zoneName, QByteArray& zoneAbbrev,
bool& dateOnly,
Status &status)
2481 QString str =
string.simplified();
2495 enum { TZNone, UTCOffset, UTCOffsetColon, TZAbbrev, TZName };
2500 int send = str.length();
2501 bool escape =
false;
2503 for (
int f = 0, fend = format.length(); f < fend && s < send; ++f)
2506 ushort ch = format[f].unicode();
2511 else if (format[f].isSpace())
2513 if (str[s].isSpace())
2516 else if (format[f] == str[s])
2527 if (str[s++] != QLatin1Char(
'%'))
2538 if (!
getNumber(str, s, 2, 2, 0, 99, year))
2540 year += (year <= 50) ? 2000 : 1999;
2543 if (!
getNumber(str, s, 2, 2, 1, 12, month))
2550 if (m <= 0 || (month !=
NO_NUMBER && month != m))
2556 if (!
getNumber(str, s, 2, 2, 1, 31, day))
2560 if (!
getNumber(str, s, 1, 2, 1, 31, day))
2566 int dow =
matchDay(str, s, &calendar);
2567 if (dow <= 0 || (dayOfWeek !=
NO_NUMBER && dayOfWeek != dow))
2573 if (!
getNumber(str, s, 2, 2, 0, 23, hour))
2577 if (!
getNumber(str, s, 1, 2, 0, 23, hour))
2581 if (!
getNumber(str, s, 2, 2, 1, 12, hour))
2585 if (!
getNumber(str, s, 1, 2, 1, 12, hour))
2589 if (!
getNumber(str, s, 2, 2, 0, 59, minute))
2593 if (!
getNumber(str, s, 2, 2, 0, 59, second))
2597 if (!
getNumber(str, s, 1, 2, 0, 59, second))
2603 int ap =
getAmPm(str, s, locale);
2604 if (!ap || (ampm !=
NO_NUMBER && ampm != ap))
2616 if (str[s++] != QLatin1Char(
' '))
2621 || str[s++] != QLatin1Char(
'%')
2622 || str[s++] != format[f])
2627 else if (flag ==
':')
2640 if (dow <= 0 || (dayOfWeek !=
NO_NUMBER && dayOfWeek != dow))
2649 if (m <= 0 || (month !=
NO_NUMBER && month != m))
2655 if (!
getNumber(str, s, 1, 2, 1, 12, month))
2662 if (!ap || (ampm !=
NO_NUMBER && ampm != ap))
2668 if (!
getNumber(str, s, 1, 2, 0, 59, minute))
2672 if (str[s] != QLatin1Char(
':'))
2678 if (!
getNumber(str, s, 1, 2, 0, 59, second))
2683 if (str[s] != QLatin1Char(
'.'))
2687 if (!str.mid(s).startsWith(dpt))
2689 s += dpt.length() - 1;
2696 for (
int end = val.length(); i < end && val[i].isDigit(); ++i) ;
2700 val += QLatin1String(
"00");
2702 int ms = val.toInt();
2703 if (millisec !=
NO_NUMBER && millisec != ms)
2713 zone = UTCOffsetColon;
2720 || str[s++] != QLatin1Char(
'%')
2721 || str[s++] != QLatin1Char(
':')
2722 || str[s++] != format[f])
2737 case UTCOffsetColon:
2738 if (!zoneAbbrev.isEmpty() || !zoneName.isEmpty())
2740 if (!
getUTCOffset(str, s, (zone == UTCOffsetColon), tzoffset))
2745 if (tzoffset !=
NO_NUMBER || !zoneName.isEmpty())
2748 while (s < send && str[s].isLetterOrNumber())
2752 QString z = str.mid(start, s - start);
2753 if (!zoneAbbrev.isEmpty() && z.toLatin1() != zoneAbbrev)
2755 zoneAbbrev = z.toLatin1();
2760 if (tzoffset !=
NO_NUMBER || !zoneAbbrev.isEmpty())
2771 QChar endchar = format[f + 1];
2772 if (endchar == QLatin1Char(
'%') && f + 2 < fend)
2774 QChar endchar2 = format[f + 2];
2775 if (endchar2 == QLatin1Char(
'n') || endchar2 == QLatin1Char(
't'))
2776 endchar = QLatin1Char(
' ');
2780 for ( ; s < send && str[s] != endchar; ++s) ;
2783 z = str.mid(start, s - start);
2785 if (!zoneName.isEmpty() && z != zoneName)
2800 QDate d =
checkDate(year, month, (day > 0 ? day : 1), status);
2807 day = 1 + dayOfWeek - QDate(year, month, 1).dayOfWeek();
2813 if (QDate(year, month, day).dayOfWeek() != dayOfWeek)
2830 if (!hour || hour > 12)
2832 if (ampm == 1 && hour == 12)
2834 else if (ampm == 2 && hour < 12)
2838 QDateTime dt(d, QTime(hour, minute, second, millisec), (tzoffset == 0 ? Qt::UTC : Qt::LocalTime));
2840 utcOffset = (tzoffset ==
NO_NUMBER) ? 0 : tzoffset*60;
2854 QString part =
string.mid(offset);
2860 for (dayOfWeek = 1; dayOfWeek <= 7; ++dayOfWeek)
2863 if (part.startsWith(name, Qt::CaseInsensitive))
2865 offset += name.length();
2869 for (dayOfWeek = 1; dayOfWeek <= 7; ++dayOfWeek)
2872 if (part.startsWith(name, Qt::CaseInsensitive))
2874 offset += name.length();
2884 return dayOfWeek + 1;
2895 QString part =
string.mid(offset);
2901 for (month = 1; month <= 12; ++month)
2904 if (part.startsWith(name, Qt::CaseInsensitive))
2906 offset += name.length();
2910 for (month = 1; month <= 12; ++month)
2913 if (part.startsWith(name, Qt::CaseInsensitive))
2915 offset += name.length();
2933 int len =
string.length();
2936 switch (
string[offset++].unicode())
2949 if (!
getNumber(
string, offset, 2, 2, 0, 99, tzhour))
2953 if (offset >= len ||
string[offset++] != QLatin1Char(
':'))
2956 if (offset >= len || !
string[offset].isDigit())
2960 if (!
getNumber(
string, offset, 2, 2, 0, 59, tzmin))
2963 tzmin += tzhour * 60;
2964 if (result !=
NO_NUMBER && result != tzmin)
2966 result = sign * tzmin;
2977 QString part =
string.mid(offset);
2984 if (part.startsWith(aps, Qt::CaseInsensitive))
2992 if (part.startsWith(aps, Qt::CaseInsensitive))
3001 if (part.startsWith(QLatin1String(
"am"), Qt::CaseInsensitive))
3003 else if (part.startsWith(QLatin1String(
"pm"), Qt::CaseInsensitive))
3015 bool getNumber(
const QString&
string,
int& offset,
int mindigits,
int maxdigits,
int minval,
int maxval,
int& result)
3017 int end =
string.size();
3019 if (minval ==
NO_NUMBER && offset < end &&
string[offset] == QLatin1Char(
'-'))
3024 if (offset + maxdigits > end)
3025 maxdigits = end - offset;
3027 for (ndigits = 0; ndigits < maxdigits &&
string[offset + ndigits].isDigit(); ++ndigits) ;
3028 if (ndigits < mindigits)
3031 int n =
string.mid(offset, ndigits).toInt(&ok);
3034 if (!ok || (result !=
NO_NUMBER && n != result) || (minval !=
NO_NUMBER && n < minval) || (n > maxval && maxval >= 0))
3043 for (
int i = 0; i < count; ++i)
3045 if (
string.startsWith(QLatin1String(array + i * disp), Qt::CaseInsensitive))
3047 offset += qstrlen(array + i * disp);
3063 QDate qdate(year, month, day);
3064 if (qdate.isValid())
3070 bool leap = (year % 4 == 0) && (year % 100 || year % 400 == 0);
3071 qdate.setYMD((leap ? 2000 : 2001), month, day);
3072 if (qdate.isValid())