• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.38 API Reference
  • KDE Home
  • Contact Us
 

KDECore

  • kdecore
  • date
kdatetime.cpp
Go to the documentation of this file.
1/*
2 This file is part of the KDE libraries
3 Copyright (c) 2005-2011 David Jarvie <djarvie@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21#include "kdatetime.h"
22
23#include <config.h>
24#include <config-date.h>
25
26#ifdef HAVE_SYS_TIME_H
27#include <sys/time.h>
28#endif
29#ifdef HAVE_TIME_H
30#include <time.h>
31#endif
32#include <stdlib.h>
33#include <stdio.h>
34#include <ctype.h>
35
36#include <QtCore/QDateTime>
37#include <QtCore/QRegExp>
38#include <QtCore/QStringList>
39#include <QtCore/QSharedData>
40
41#include <kglobal.h>
42#include <klocale.h>
43#include "kcalendarsystemqdate_p.h"
44#include <ksystemtimezone.h>
45#include <kdebug.h>
46
47#ifdef Q_OS_WIN
48#include <windows.h> // SYSTEMTIME
49#endif
50
51
52static const char shortDay[][4] = {
53 "Mon", "Tue", "Wed",
54 "Thu", "Fri", "Sat",
55 "Sun"
56};
57static const char longDay[][10] = {
58 "Monday", "Tuesday", "Wednesday",
59 "Thursday", "Friday", "Saturday",
60 "Sunday"
61};
62static const char shortMonth[][4] = {
63 "Jan", "Feb", "Mar", "Apr",
64 "May", "Jun", "Jul", "Aug",
65 "Sep", "Oct", "Nov", "Dec"
66};
67static const char longMonth[][10] = {
68 "January", "February", "March",
69 "April", "May", "June",
70 "July", "August", "September",
71 "October", "November", "December"
72};
73
74
75// The reason for the KDateTime being invalid, returned from KDateTime::fromString()
76enum Status {
77 stValid = 0, // either valid, or really invalid
78 stTooEarly // invalid (valid date before QDate range)
79};
80
81
82static QDateTime fromStr(const QString& string, const QString& format, int& utcOffset,
83 QString& zoneName, QByteArray& zoneAbbrev, bool& dateOnly, Status&);
84static int matchDay(const QString &string, int &offset, KCalendarSystem*);
85static int matchMonth(const QString &string, int &offset, KCalendarSystem*);
86static bool getUTCOffset(const QString &string, int &offset, bool colon, int &result);
87static int getAmPm(const QString &string, int &offset, KLocale*);
88static bool getNumber(const QString &string, int &offset, int mindigits, int maxdigits, int minval, int maxval, int &result);
89static int findString_internal(const QString &string, const char *ptr, int count, int &offset, int disp);
90template<int disp> static inline
91int findString(const QString &string, const char array[][disp], int count, int &offset)
92{ return findString_internal(string, array[0], count, offset, disp); }
93static QDate checkDate(int year, int month, int day, Status&);
94
95static const int MIN_YEAR = -4712; // minimum year which QDate allows
96static const int NO_NUMBER = 0x8000000; // indicates that no number is present in string conversion functions
97
98#ifdef COMPILING_TESTS
99KDECORE_EXPORT int KDateTime_utcCacheHit = 0;
100KDECORE_EXPORT int KDateTime_zoneCacheHit = 0;
101#endif
102
103/*----------------------------------------------------------------------------*/
104
105class KDateTimeSpecPrivate
106{
107 public:
108 KDateTimeSpecPrivate() : utcOffset(0) {}
109 // *** NOTE: This structure is replicated in KDateTimePrivate. Any changes must be copied there.
110 KTimeZone tz; // if type == TimeZone, the instance's time zone.
111 int utcOffset; // if type == OffsetFromUTC, the offset from UTC
112 KDateTime::SpecType type; // time spec type
113};
114
115
116KDateTime::Spec::Spec()
117 : d(new KDateTimeSpecPrivate)
118{
119 d->type = KDateTime::Invalid;
120}
121
122KDateTime::Spec::Spec(const KTimeZone &tz)
123 : d(new KDateTimeSpecPrivate())
124{
125 setType(tz);
126}
127
128KDateTime::Spec::Spec(SpecType type, int utcOffset)
129 : d(new KDateTimeSpecPrivate())
130{
131 setType(type, utcOffset);
132}
133
134KDateTime::Spec::Spec(const Spec& spec)
135 : d(new KDateTimeSpecPrivate())
136{
137 operator=(spec);
138}
139
140KDateTime::Spec::~Spec()
141{
142 delete d;
143}
144
145KDateTime::Spec &KDateTime::Spec::operator=(const Spec& spec)
146{
147 if (&spec != this)
148 {
149 d->type = spec.d->type;
150 if (d->type == KDateTime::TimeZone)
151 d->tz = spec.d->tz;
152 else if (d->type == KDateTime::OffsetFromUTC)
153 d->utcOffset = spec.d->utcOffset;
154 }
155 return *this;
156}
157
158void KDateTime::Spec::setType(SpecType type, int utcOffset)
159{
160 switch (type)
161 {
162 case KDateTime::OffsetFromUTC:
163 d->utcOffset = utcOffset;
164 // fall through to UTC
165 case KDateTime::UTC:
166 case KDateTime::ClockTime:
167 d->type = type;
168 break;
169 case KDateTime::LocalZone:
170 d->tz = KSystemTimeZones::local();
171 d->type = KDateTime::TimeZone;
172 break;
173 case KDateTime::TimeZone:
174 default:
175 d->type = KDateTime::Invalid;
176 break;
177 }
178}
179
180void KDateTime::Spec::setType(const KTimeZone &tz)
181{
182 if (tz == KTimeZone::utc())
183 d->type = KDateTime::UTC;
184 else if (tz.isValid())
185 {
186 d->type = KDateTime::TimeZone;
187 d->tz = tz;
188 }
189 else
190 d->type = KDateTime::Invalid;
191}
192
193KTimeZone KDateTime::Spec::timeZone() const
194{
195 if (d->type == KDateTime::TimeZone)
196 return d->tz;
197 if (d->type == KDateTime::UTC)
198 return KTimeZone::utc();
199 return KTimeZone();
200}
201
202bool KDateTime::Spec::isUtc() const
203{
204 if (d->type == KDateTime::UTC
205 || (d->type == KDateTime::OffsetFromUTC && d->utcOffset == 0))
206 return true;
207 return false;
208}
209
210KDateTime::Spec KDateTime::Spec::UTC() { return Spec(KDateTime::UTC); }
211KDateTime::Spec KDateTime::Spec::ClockTime() { return Spec(KDateTime::ClockTime); }
212KDateTime::Spec KDateTime::Spec::LocalZone() { return Spec(KDateTime::LocalZone); }
213KDateTime::Spec KDateTime::Spec::OffsetFromUTC(int utcOffset) { return Spec(KDateTime::OffsetFromUTC, utcOffset); }
214KDateTime::SpecType KDateTime::Spec::type() const { return d->type; }
215bool KDateTime::Spec::isValid() const { return d->type != KDateTime::Invalid; }
216bool KDateTime::Spec::isLocalZone() const { return d->type == KDateTime::TimeZone && d->tz == KSystemTimeZones::local(); }
217bool KDateTime::Spec::isClockTime() const { return d->type == KDateTime::ClockTime; }
218bool KDateTime::Spec::isOffsetFromUtc() const { return d->type == KDateTime::OffsetFromUTC; }
219int KDateTime::Spec::utcOffset() const { return d->type == KDateTime::OffsetFromUTC ? d->utcOffset : 0; }
220
221bool KDateTime::Spec::operator==(const Spec &other) const
222{
223 if (d->type != other.d->type
224 || (d->type == KDateTime::TimeZone && d->tz != other.d->tz)
225 || (d->type == KDateTime::OffsetFromUTC && d->utcOffset != other.d->utcOffset))
226 return false;
227 return true;
228}
229
230bool KDateTime::Spec::equivalentTo(const Spec &other) const
231{
232 if (d->type == other.d->type)
233 {
234 if ((d->type == KDateTime::TimeZone && d->tz != other.d->tz)
235 || (d->type == KDateTime::OffsetFromUTC && d->utcOffset != other.d->utcOffset))
236 return false;
237 return true;
238 }
239 else
240 {
241 if ((d->type == KDateTime::UTC && other.d->type == KDateTime::OffsetFromUTC && other.d->utcOffset == 0)
242 || (other.d->type == KDateTime::UTC && d->type == KDateTime::OffsetFromUTC && d->utcOffset == 0))
243 return true;
244 return false;
245 }
246}
247
248QDataStream & operator<<(QDataStream &s, const KDateTime::Spec &spec)
249{
250 // The specification type is encoded in order to insulate from changes
251 // to the SpecType enum.
252 switch (spec.type())
253 {
254 case KDateTime::UTC:
255 s << static_cast<quint8>('u');
256 break;
257 case KDateTime::OffsetFromUTC:
258 s << static_cast<quint8>('o') << spec.utcOffset();
259 break;
260 case KDateTime::TimeZone:
261 s << static_cast<quint8>('z') << (spec.timeZone().isValid() ? spec.timeZone().name() : QString());
262 break;
263 case KDateTime::ClockTime:
264 s << static_cast<quint8>('c');
265 break;
266 case KDateTime::Invalid:
267 default:
268 s << static_cast<quint8>(' ');
269 break;
270 }
271 return s;
272}
273
274QDataStream & operator>>(QDataStream &s, KDateTime::Spec &spec)
275{
276 // The specification type is encoded in order to insulate from changes
277 // to the SpecType enum.
278 quint8 t;
279 s >> t;
280 switch (static_cast<char>(t))
281 {
282 case 'u':
283 spec.setType(KDateTime::UTC);
284 break;
285 case 'o':
286 {
287 int utcOffset;
288 s >> utcOffset;
289 spec.setType(KDateTime::OffsetFromUTC, utcOffset);
290 break;
291 }
292 case 'z':
293 {
294 QString zone;
295 s >> zone;
296 KTimeZone tz = KSystemTimeZones::zone(zone);
297 spec.setType(tz);
298 break;
299 }
300 case 'c':
301 spec.setType(KDateTime::ClockTime);
302 break;
303 default:
304 spec.setType(KDateTime::Invalid);
305 break;
306 }
307 return s;
308}
309
310
311/*----------------------------------------------------------------------------*/
312
313K_GLOBAL_STATIC_WITH_ARGS(KDateTime::Spec, s_fromStringDefault, (KDateTime::ClockTime))
314
315class KDateTimePrivate : public QSharedData
316{
317 public:
318 KDateTimePrivate()
319 : QSharedData(),
320 specType(KDateTime::Invalid),
321 status(stValid),
322 utcCached(true),
323 convertedCached(false),
324 m2ndOccurrence(false),
325 mDateOnly(false)
326 {
327 }
328
329 KDateTimePrivate(const QDateTime &d, const KDateTime::Spec &s, bool donly = false)
330 : QSharedData(),
331 mDt(d),
332 specType(s.type()),
333 status(stValid),
334 utcCached(false),
335 convertedCached(false),
336 m2ndOccurrence(false),
337 mDateOnly(donly)
338 {
339 switch (specType)
340 {
341 case KDateTime::TimeZone:
342 specZone = s.timeZone();
343 break;
344 case KDateTime::OffsetFromUTC:
345 specUtcOffset= s.utcOffset();
346 break;
347 case KDateTime::Invalid:
348 utcCached = true;
349 // fall through to UTC
350 case KDateTime::UTC:
351 default:
352 break;
353 }
354 }
355
356 KDateTimePrivate(const KDateTimePrivate &rhs)
357 : QSharedData(rhs),
358 mDt(rhs.mDt),
359 specZone(rhs.specZone),
360 specUtcOffset(rhs.specUtcOffset),
361 ut(rhs.ut),
362 converted(rhs.converted),
363 specType(rhs.specType),
364 status(rhs.status),
365 utcCached(rhs.utcCached),
366 convertedCached(rhs.convertedCached),
367 m2ndOccurrence(rhs.m2ndOccurrence),
368 mDateOnly(rhs.mDateOnly),
369 converted2ndOccur(rhs.converted2ndOccur)
370 {}
371
372 ~KDateTimePrivate() {}
373 const QDateTime& dt() const { return mDt; }
374 const QDate date() const { return mDt.date(); }
375 KDateTime::Spec spec() const;
376 QDateTime utc() const { return QDateTime(ut.date, ut.time, Qt::UTC); }
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; }
384 void setSpec(const KDateTime::Spec&);
385 void setDateOnly(bool d);
386 int timeZoneOffset() const;
387 QDateTime toUtc(const KTimeZone &local = KTimeZone()) const;
388 QDateTime toZone(const KTimeZone &zone, const KTimeZone &local = KTimeZone()) const;
389 void newToZone(KDateTimePrivate *newd, const KTimeZone &zone, const KTimeZone &local = KTimeZone()) const;
390 bool equalSpec(const KDateTimePrivate&) const;
391 void clearCache() { utcCached = convertedCached = false; }
392 void setDt(const QDateTime &dt, const QDateTime &utcDt)
393 {
394 mDt = dt;
395 ut.date = utcDt.date();
396 ut.time = utcDt.time();
397 utcCached = true;
398 convertedCached = false;
399 m2ndOccurrence = false;
400 }
401 void setUtc(const QDateTime &dt) const
402 {
403 ut.date = dt.date();
404 ut.time = dt.time();
405 utcCached = true;
406 convertedCached = false;
407 }
408
409 /* Initialise the date/time for specType = UTC, from a time zone time,
410 * and cache the time zone time.
411 */
412 void setUtcFromTz(const QDateTime &dt, const KTimeZone &tz)
413 {
414 if (specType == KDateTime::UTC)
415 {
416 mDt = tz.toUtc(dt);
417 utcCached = false;
418 converted.date = dt.date();
419 converted.time = dt.time();
420 converted.tz = tz;
421 convertedCached = true;
422 converted2ndOccur = false; // KTimeZone::toUtc() returns the first occurrence
423 }
424 }
425
426 // Default time spec used by fromString()
427 static KDateTime::Spec& fromStringDefault()
428 {
429 return *s_fromStringDefault;
430 }
431
432
433 static QTime sod; // start of day (00:00:00)
434#ifndef NDEBUG
435 static qint64 currentDateTimeOffset; // offset to apply to current system time
436#endif
437
438 /* Because some applications create thousands of instances of KDateTime, this
439 * data structure is designed to minimize memory usage. Ensure that all small
440 * members are kept together at the end!
441 */
442private:
443 QDateTime mDt;
444public:
445 KTimeZone specZone; // if specType == TimeZone, the instance's time zone
446 // if specType == ClockTime, the local time zone used to calculate the cached UTC time (mutable)
447 int specUtcOffset; // if specType == OffsetFromUTC, the offset from UTC
448 mutable struct ut { // cached UTC equivalent of 'mDt'. Saves space compared to storing QDateTime.
449 QDate date;
450 QTime time;
451 } ut;
452private:
453 mutable struct converted { // cached conversion to another time zone (if 'tz' is valid)
454 QDate date;
455 QTime time;
456 KTimeZone tz;
457 } converted;
458public:
459 KDateTime::SpecType specType : 4; // time spec type (N.B. need 3 bits + sign bit, since enums are signed on some platforms)
460 Status status : 2; // reason for invalid status
461 mutable bool utcCached : 1; // true if 'ut' is valid
462 mutable bool convertedCached : 1; // true if 'converted' is valid
463 mutable bool m2ndOccurrence : 1; // this is the second occurrence of a time zone time
464private:
465 bool mDateOnly : 1; // true to ignore the time part
466 mutable bool converted2ndOccur : 1; // this is the second occurrence of 'converted' time
467};
468
469
470QTime KDateTimePrivate::sod(0,0,0);
471#ifndef NDEBUG
472qint64 KDateTimePrivate::currentDateTimeOffset = 0;
473#endif
474
475KDateTime::Spec KDateTimePrivate::spec() const
476{
477 if (specType == KDateTime::TimeZone)
478 return KDateTime::Spec(specZone);
479 else
480 return KDateTime::Spec(specType, specUtcOffset);
481}
482
483void KDateTimePrivate::setSpec(const KDateTime::Spec &other)
484{
485 if (specType == other.type())
486 {
487 switch (specType)
488 {
489 case KDateTime::TimeZone:
490 {
491 KTimeZone tz = other.timeZone();
492 if (specZone == tz)
493 return;
494 specZone = tz;
495 break;
496 }
497 case KDateTime::OffsetFromUTC:
498 {
499 int offset = other.utcOffset();
500 if (specUtcOffset == offset)
501 return;
502 specUtcOffset = offset;
503 break;
504 }
505 default:
506 return;
507 }
508 utcCached = false;
509 }
510 else
511 {
512 specType = other.type();
513 switch (specType)
514 {
515 case KDateTime::TimeZone:
516 specZone = other.timeZone();
517 break;
518 case KDateTime::OffsetFromUTC:
519 specUtcOffset = other.utcOffset();
520 break;
521 case KDateTime::Invalid:
522 ut.date = QDate(); // cache an invalid UTC value
523 utcCached = true;
524 // fall through to UTC
525 case KDateTime::UTC:
526 default:
527 break;
528 }
529 }
530 convertedCached = false;
531 setDtTimeSpec((specType == KDateTime::UTC) ? Qt::UTC : Qt::LocalTime); // this clears cached UTC value
532}
533
534bool KDateTimePrivate::equalSpec(const KDateTimePrivate &other) const
535{
536 if (specType != other.specType
537 || (specType == KDateTime::TimeZone && specZone != other.specZone)
538 || (specType == KDateTime::OffsetFromUTC && specUtcOffset != other.specUtcOffset))
539 return false;
540 return true;
541}
542
543void KDateTimePrivate::setDateOnly(bool dateOnly)
544{
545 if (dateOnly != mDateOnly)
546 {
547 mDateOnly = dateOnly;
548 if (dateOnly && mDt.time() != sod)
549 {
550 mDt.setTime(sod);
551 utcCached = false;
552 convertedCached = false;
553 }
554 m2ndOccurrence = false;
555 }
556}
557
558/* Sets the date/time to a given UTC date/time. The time spec is not changed. */
559void KDateTimePrivate::setDtFromUtc(const QDateTime &utcdt)
560{
561 switch (specType)
562 {
563 case KDateTime::UTC:
564 setDt(utcdt);
565 break;
566 case KDateTime::OffsetFromUTC:
567 {
568 QDateTime local = utcdt.addSecs(specUtcOffset);
569 local.setTimeSpec(Qt::LocalTime);
570 setDt(local, utcdt);
571 break;
572 }
573 case KDateTime::TimeZone:
574 {
575 bool second;
576 setDt(specZone.toZoneTime(utcdt, &second), utcdt);
577 m2ndOccurrence = second;
578 break;
579 }
580 case KDateTime::ClockTime:
581 specZone = KSystemTimeZones::local();
582 setDt(specZone.toZoneTime(utcdt), utcdt);
583 break;
584 default: // invalid
585 break;
586 }
587}
588
589/*
590 * Returns the UTC offset for the date/time, provided that it is a time zone type.
591 */
592int KDateTimePrivate::timeZoneOffset() const
593{
594 if (specType != KDateTime::TimeZone)
595 return KTimeZone::InvalidOffset;
596 if (utcCached)
597 {
598 QDateTime dt = mDt;
599 dt.setTimeSpec(Qt::UTC);
600 return utc().secsTo(dt);
601 }
602 int secondOffset;
603 if (!specZone.isValid()) {
604 return KTimeZone::InvalidOffset;
605 }
606 int offset = specZone.offsetAtZoneTime(mDt, &secondOffset);
607 if (m2ndOccurrence)
608 {
609 m2ndOccurrence = (secondOffset != offset); // cancel "second occurrence" flag if not applicable
610 offset = secondOffset;
611 }
612 if (offset == KTimeZone::InvalidOffset)
613 {
614 ut.date = QDate();
615 utcCached = true;
616 convertedCached = false;
617 }
618 else
619 {
620 // Calculate the UTC time from the offset and cache it
621 QDateTime utcdt = mDt;
622 utcdt.setTimeSpec(Qt::UTC);
623 setUtc(utcdt.addSecs(-offset));
624 }
625 return offset;
626}
627
628/*
629 * Returns the date/time converted to UTC.
630 * Depending on which KTimeZone class is involved, conversion to UTC may require
631 * significant calculation, so the calculated UTC value is cached.
632 */
633QDateTime KDateTimePrivate::toUtc(const KTimeZone &local) const
634{
635 KTimeZone loc(local);
636 if (utcCached)
637 {
638 // Return cached UTC value
639 if (specType == KDateTime::ClockTime)
640 {
641 // ClockTime uses the dynamic current local system time zone.
642 // Check for a time zone change before using the cached UTC value.
643 if (!local.isValid())
644 loc = KSystemTimeZones::local();
645 if (specZone == loc)
646 {
647// kDebug() << "toUtc(): cached -> " << utc() << endl,
648#ifdef COMPILING_TESTS
649 ++KDateTime_utcCacheHit;
650#endif
651 return utc();
652 }
653 }
654 else
655 {
656// kDebug() << "toUtc(): cached -> " << utc() << endl,
657#ifdef COMPILING_TESTS
658 ++KDateTime_utcCacheHit;
659#endif
660 return utc();
661 }
662 }
663
664 // No cached UTC value, so calculate it
665 switch (specType)
666 {
667 case KDateTime::UTC:
668 return mDt;
669 case KDateTime::OffsetFromUTC:
670 {
671 if (!mDt.isValid())
672 break;
673 QDateTime dt = QDateTime(mDt.date(), mDt.time(), Qt::UTC).addSecs(-specUtcOffset);
674 setUtc(dt);
675// kDebug() << "toUtc(): calculated -> " << dt << endl,
676 return dt;
677 }
678 case KDateTime::ClockTime:
679 {
680 if (!mDt.isValid())
681 break;
682 if (!loc.isValid())
683 loc = KSystemTimeZones::local();
684 const_cast<KDateTimePrivate*>(this)->specZone = loc;
685 QDateTime dt(specZone.toUtc(mDt));
686 setUtc(dt);
687// kDebug() << "toUtc(): calculated -> " << dt << endl,
688 return dt;
689 }
690 case KDateTime::TimeZone:
691 if (!mDt.isValid())
692 break;
693 timeZoneOffset(); // calculate offset and cache UTC value
694// kDebug() << "toUtc(): calculated -> " << utc() << endl,
695 return utc();
696 default:
697 break;
698 }
699
700 // Invalid - mark it cached to avoid having to process it again
701 ut.date = QDate(); // (invalid)
702 utcCached = true;
703 convertedCached = false;
704// kDebug() << "toUtc(): invalid";
705 return mDt;
706}
707
708/* Convert this value to another time zone.
709 * The value is cached to save having to repeatedly calculate it.
710 * The caller should check for an invalid date/time.
711 */
712QDateTime KDateTimePrivate::toZone(const KTimeZone &zone, const KTimeZone &local) const
713{
714 if (convertedCached && converted.tz == zone)
715 {
716 // Converted value is already cached
717#ifdef COMPILING_TESTS
718// kDebug() << "KDateTimePrivate::toZone(" << zone->name() << "): " << mDt << " cached";
719 ++KDateTime_zoneCacheHit;
720#endif
721 return QDateTime(converted.date, converted.time, Qt::LocalTime);
722 }
723 else
724 {
725 // Need to convert the value
726 bool second;
727 QDateTime result = zone.toZoneTime(toUtc(local), &second);
728 converted.date = result.date();
729 converted.time = result.time();
730 converted.tz = zone;
731 convertedCached = true;
732 converted2ndOccur = second;
733 return result;
734 }
735}
736
737/* Convert this value to another time zone, and write it into the specified instance.
738 * The value is cached to save having to repeatedly calculate it.
739 * The caller should check for an invalid date/time.
740 */
741void KDateTimePrivate::newToZone(KDateTimePrivate *newd, const KTimeZone &zone, const KTimeZone &local) const
742{
743 newd->mDt = toZone(zone, local);
744 newd->specZone = zone;
745 newd->specType = KDateTime::TimeZone;
746 newd->utcCached = utcCached;
747 newd->mDateOnly = mDateOnly;
748 newd->m2ndOccurrence = converted2ndOccur;
749 switch (specType)
750 {
751 case KDateTime::UTC:
752 newd->ut.date = mDt.date(); // cache the UTC value
753 newd->ut.time = mDt.time();
754 break;
755 case KDateTime::TimeZone:
756 // This instance is also type time zone, so cache its value in the new instance
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;
762 newd->ut = ut;
763 return;
764 default:
765 newd->ut = ut;
766 break;
767 }
768 newd->convertedCached = false;
769}
770
771
772/*----------------------------------------------------------------------------*/
773K_GLOBAL_STATIC_WITH_ARGS(QSharedDataPointer<KDateTimePrivate>, emptyDateTimePrivate, (new KDateTimePrivate))
774
775KDateTime::KDateTime()
776 : d(*emptyDateTimePrivate)
777{
778}
779
780KDateTime::KDateTime(const QDate &date, const Spec &spec)
781: d(new KDateTimePrivate(QDateTime(date, KDateTimePrivate::sod, Qt::LocalTime), spec, true))
782{
783 if (spec.type() == UTC)
784 d->setDtTimeSpec(Qt::UTC);
785}
786
787KDateTime::KDateTime(const QDate &date, const QTime &time, const Spec &spec)
788 : d(new KDateTimePrivate(QDateTime(date, time, Qt::LocalTime), spec))
789{
790 if (spec.type() == UTC)
791 d->setDtTimeSpec(Qt::UTC);
792}
793
794KDateTime::KDateTime(const QDateTime &dt, const Spec &spec)
795 : d(new KDateTimePrivate(dt, spec))
796{
797 // If the supplied date/time is UTC and we need local time, or vice versa, convert it.
798 if (spec.type() == UTC)
799 {
800 if (dt.timeSpec() == Qt::LocalTime)
801 d->setUtcFromTz(dt, KSystemTimeZones::local()); // set time & cache local time
802 }
803 else if (dt.timeSpec() == Qt::UTC)
804 d->setDtFromUtc(dt);
805}
806
807KDateTime::KDateTime(const QDateTime &dt)
808 : d(new KDateTimePrivate(dt, (dt.timeSpec() == Qt::LocalTime ? Spec(LocalZone) : Spec(UTC))))
809{
810}
811
812KDateTime::KDateTime(const KDateTime &other)
813 : d(other.d)
814{
815}
816
817KDateTime::~KDateTime()
818{
819}
820
821KDateTime &KDateTime::operator=(const KDateTime &other)
822{
823 if (&other != this)
824 d = other.d;
825 return *this;
826}
827
828void KDateTime::detach() { d.detach(); }
829bool KDateTime::isNull() const { return d->dt().isNull(); }
830bool KDateTime::isValid() const { return d->specType != Invalid && d->dt().isValid(); }
831bool KDateTime::outOfRange() const { return d->status == stTooEarly; }
832bool KDateTime::isDateOnly() const { return d->dateOnly(); }
833bool KDateTime::isLocalZone() const { return d->specType == TimeZone && d->specZone == KSystemTimeZones::local(); }
834bool KDateTime::isClockTime() const { return d->specType == ClockTime; }
835bool KDateTime::isUtc() const { return d->specType == UTC || (d->specType == OffsetFromUTC && d->specUtcOffset == 0); }
836bool KDateTime::isOffsetFromUtc() const { return d->specType == OffsetFromUTC; }
837bool KDateTime::isSecondOccurrence() const { return d->specType == TimeZone && d->secondOccurrence(); }
838QDate KDateTime::date() const { return d->date(); }
839QTime KDateTime::time() const { return d->dt().time(); }
840QDateTime KDateTime::dateTime() const { return d->dt(); }
841
842KDateTime::Spec KDateTime::timeSpec() const { return d->spec(); }
843KDateTime::SpecType KDateTime::timeType() const { return d->specType; }
844
845KTimeZone KDateTime::timeZone() const
846{
847 switch (d->specType)
848 {
849 case TimeZone:
850 return d->specZone;
851 case UTC:
852 return KTimeZone::utc();
853 default:
854 return KTimeZone();
855 }
856}
857
858int KDateTime::utcOffset() const
859{
860 switch (d->specType)
861 {
862 case TimeZone:
863 return d->timeZoneOffset(); // calculate offset and cache UTC value
864 case OffsetFromUTC:
865 return d->specUtcOffset;
866 default:
867 return 0;
868 }
869}
870
871KDateTime KDateTime::toUtc() const
872{
873 if (!isValid())
874 return KDateTime();
875 if (d->specType == UTC)
876 return *this;
877 if (d->dateOnly())
878 return KDateTime(d->date(), UTC);
879 QDateTime udt = d->toUtc();
880 if (!udt.isValid())
881 return KDateTime();
882 return KDateTime(udt, UTC);
883}
884
885KDateTime KDateTime::toOffsetFromUtc() const
886{
887 if (!isValid())
888 return KDateTime();
889 int offset = 0;
890 switch (d->specType)
891 {
892 case OffsetFromUTC:
893 return *this;
894 case UTC:
895 {
896 if (d->dateOnly())
897 return KDateTime(d->date(), Spec(OffsetFromUTC, 0));
898 QDateTime qdt = d->dt();
899 qdt.setTimeSpec(Qt::LocalTime);
900 return KDateTime(qdt, Spec(OffsetFromUTC, 0));
901 }
902 case TimeZone:
903 offset = d->timeZoneOffset(); // calculate offset and cache UTC value
904 break;
905 case ClockTime:
906 offset = KSystemTimeZones::local().offsetAtZoneTime(d->dt());
907 break;
908 default:
909 return KDateTime();
910 }
911 if (d->dateOnly())
912 return KDateTime(d->date(), Spec(OffsetFromUTC, offset));
913 return KDateTime(d->dt(), Spec(OffsetFromUTC, offset));
914}
915
916KDateTime KDateTime::toOffsetFromUtc(int utcOffset) const
917{
918 if (!isValid())
919 return KDateTime();
920 if (d->specType == OffsetFromUTC && d->specUtcOffset == utcOffset)
921 return *this;
922 if (d->dateOnly())
923 return KDateTime(d->date(), Spec(OffsetFromUTC, utcOffset));
924 return KDateTime(d->toUtc(), Spec(OffsetFromUTC, utcOffset));
925}
926
927KDateTime KDateTime::toLocalZone() const
928{
929 if (!isValid())
930 return KDateTime();
931 KTimeZone local = KSystemTimeZones::local();
932 if (d->specType == TimeZone && d->specZone == local)
933 return *this; // it's already local zone. Preserve UTC cache, if any
934 if (d->dateOnly())
935 return KDateTime(d->date(), Spec(local));
936 switch (d->specType)
937 {
938 case TimeZone:
939 case OffsetFromUTC:
940 case UTC:
941 {
942 KDateTime result;
943 d->newToZone(result.d, local, local); // cache the time zone conversion
944 return result;
945 }
946 case ClockTime:
947 return KDateTime(d->dt(), Spec(local));
948 default:
949 return KDateTime();
950 }
951}
952
953KDateTime KDateTime::toClockTime() const
954{
955 if (!isValid())
956 return KDateTime();
957 if (d->specType == ClockTime)
958 return *this;
959 if (d->dateOnly())
960 return KDateTime(d->date(), Spec(ClockTime));
961 KDateTime result = toLocalZone();
962 result.d->specType = ClockTime; // cached value (if any) is unaffected
963 return result;
964}
965
966KDateTime KDateTime::toZone(const KTimeZone &zone) const
967{
968 if (!zone.isValid() || !isValid())
969 return KDateTime();
970 if (d->specType == TimeZone && d->specZone == zone)
971 return *this; // preserve UTC cache, if any
972 if (d->dateOnly())
973 return KDateTime(d->date(), Spec(zone));
974 KDateTime result;
975 d->newToZone(result.d, zone); // cache the time zone conversion
976 return result;
977}
978
979KDateTime KDateTime::toTimeSpec(const KDateTime &dt) const
980{
981 return toTimeSpec(dt.timeSpec());
982}
983
984KDateTime KDateTime::toTimeSpec(const Spec &spec) const
985{
986 if (spec == d->spec())
987 return *this;
988 if (!isValid())
989 return KDateTime();
990 if (d->dateOnly())
991 return KDateTime(d->date(), spec);
992 if (spec.type() == TimeZone)
993 {
994 KDateTime result;
995 d->newToZone(result.d, spec.timeZone()); // cache the time zone conversion
996 return result;
997 }
998 return KDateTime(d->toUtc(), spec);
999}
1000
1001uint KDateTime::toTime_t() const
1002{
1003 QDateTime qdt = d->toUtc();
1004 if (!qdt.isValid())
1005 return uint(-1);
1006 return qdt.toTime_t();
1007}
1008
1009void KDateTime::setTime_t(qint64 seconds)
1010{
1011 d->setSpec(UTC);
1012 int days = static_cast<int>(seconds / 86400);
1013 int secs = static_cast<int>(seconds % 86400);
1014 QDateTime dt;
1015 dt.setTimeSpec(Qt::UTC); // prevent QDateTime::setTime_t() converting to local time
1016 dt.setTime_t(0);
1017 d->setDt(dt.addDays(days).addSecs(secs));
1018}
1019
1020void KDateTime::setDateOnly(bool dateOnly)
1021{
1022 d->setDateOnly(dateOnly);
1023}
1024
1025void KDateTime::setDate(const QDate &date)
1026{
1027 d->setDate(date);
1028}
1029
1030void KDateTime::setTime(const QTime &time)
1031{
1032 d->setTime(time);
1033}
1034
1035void KDateTime::setDateTime(const QDateTime &dt)
1036{
1037 d->clearCache();
1038 d->setDateOnly(false);
1039 if (dt.timeSpec() == Qt::LocalTime)
1040 {
1041 if (d->specType == UTC)
1042 d->setUtcFromTz(dt, KSystemTimeZones::local()); // set time & cache local time
1043 else
1044 d->setDt(dt);
1045 }
1046 else
1047 d->setDtFromUtc(dt); // a UTC time has been supplied
1048}
1049
1050void KDateTime::setTimeSpec(const Spec &other)
1051{
1052 d->setSpec(other);
1053}
1054
1055void KDateTime::setSecondOccurrence(bool second)
1056{
1057 if (d->specType == KDateTime::TimeZone && second != d->m2ndOccurrence)
1058 {
1059 d->m2ndOccurrence = second;
1060 d->clearCache();
1061 if (second)
1062 {
1063 // Check whether a second occurrence is actually possible, and
1064 // if not, reset m2ndOccurrence.
1065 d->timeZoneOffset(); // check, and cache UTC value
1066 }
1067 }
1068}
1069
1070KDateTime KDateTime::addMSecs(qint64 msecs) const
1071{
1072 if (!msecs)
1073 return *this; // retain cache - don't create another instance
1074 if (!isValid())
1075 return KDateTime();
1076 if (d->dateOnly())
1077 {
1078 KDateTime result(*this);
1079 result.d->setDate(d->date().addDays(static_cast<int>(msecs / 86400000)));
1080 return result;
1081 }
1082 qint64 secs = msecs / 1000;
1083 int oldms = d->dt().time().msec();
1084 int ms = oldms + static_cast<int>(msecs % 1000);
1085 if (msecs >= 0)
1086 {
1087 if (ms >= 1000)
1088 {
1089 ++secs;
1090 ms -= 1000;
1091 }
1092 }
1093 else
1094 {
1095 if (ms < 0)
1096 {
1097 --secs;
1098 ms += 1000;
1099 }
1100 }
1101 KDateTime result = addSecs(secs);
1102 QTime t = result.time();
1103 result.d->setTime(QTime(t.hour(), t.minute(), t.second(), ms));
1104 return result;
1105}
1106
1107KDateTime KDateTime::addSecs(qint64 secs) const
1108{
1109 if (!secs)
1110 return *this; // retain cache - don't create another instance
1111 if (!isValid())
1112 return KDateTime();
1113 int days = static_cast<int>(secs / 86400);
1114 int seconds = static_cast<int>(secs % 86400);
1115 if (d->dateOnly())
1116 {
1117 KDateTime result(*this);
1118 result.d->setDate(d->date().addDays(days));
1119 return result;
1120 }
1121 if (d->specType == ClockTime)
1122 {
1123 QDateTime qdt = d->dt();
1124 qdt.setTimeSpec(Qt::UTC); // set time as UTC to avoid daylight savings adjustments in addSecs()
1125 qdt = qdt.addDays(days).addSecs(seconds);
1126 qdt.setTimeSpec(Qt::LocalTime);
1127 return KDateTime(qdt, Spec(ClockTime));
1128 }
1129 return KDateTime(d->toUtc().addDays(days).addSecs(seconds), d->spec());
1130}
1131
1132KDateTime KDateTime::addDays(int days) const
1133{
1134 if (!days)
1135 return *this; // retain cache - don't create another instance
1136 KDateTime result(*this);
1137 result.d->setDate(d->date().addDays(days));
1138 return result;
1139}
1140
1141KDateTime KDateTime::addMonths(int months) const
1142{
1143 if (!months)
1144 return *this; // retain cache - don't create another instance
1145 KDateTime result(*this);
1146 result.d->setDate(d->date().addMonths(months));
1147 return result;
1148}
1149
1150KDateTime KDateTime::addYears(int years) const
1151{
1152 if (!years)
1153 return *this; // retain cache - don't create another instance
1154 KDateTime result(*this);
1155 result.d->setDate(d->date().addYears(years));
1156 return result;
1157}
1158
1159int KDateTime::secsTo(const KDateTime &t2) const
1160{
1161 return static_cast<int>(secsTo_long(t2));
1162}
1163
1164qint64 KDateTime::secsTo_long(const KDateTime &t2) const
1165{
1166 if (!isValid() || !t2.isValid())
1167 return 0;
1168 if (d->dateOnly())
1169 {
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;
1172 }
1173 if (t2.d->dateOnly())
1174 return static_cast<qint64>(toTimeSpec(t2.d->spec()).d->date().daysTo(t2.d->date())) * 86400;
1175
1176 QDateTime dt1, dt2;
1177 if (d->specType == ClockTime && t2.d->specType == ClockTime)
1178 {
1179 // Set both times as UTC to avoid daylight savings adjustments in secsTo()
1180 dt1 = d->dt();
1181 dt1.setTimeSpec(Qt::UTC);
1182 dt2 = t2.d->dt();
1183 dt2.setTimeSpec(Qt::UTC);
1184 return dt1.secsTo(dt2);
1185 }
1186 else
1187 {
1188 dt1 = d->toUtc();
1189 dt2 = t2.d->toUtc();
1190 }
1191 return static_cast<qint64>(dt1.date().daysTo(dt2.date())) * 86400
1192 + dt1.time().secsTo(dt2.time());
1193}
1194
1195int KDateTime::daysTo(const KDateTime &t2) const
1196{
1197 if (!isValid() || !t2.isValid())
1198 return 0;
1199 if (d->dateOnly())
1200 {
1201 QDate dat = t2.d->dateOnly() ? t2.d->date() : t2.toTimeSpec(d->spec()).d->date();
1202 return d->date().daysTo(dat);
1203 }
1204 if (t2.d->dateOnly())
1205 return toTimeSpec(t2.d->spec()).d->date().daysTo(t2.d->date());
1206
1207 QDate dat;
1208 switch (d->specType)
1209 {
1210 case UTC:
1211 dat = t2.d->toUtc().date();
1212 break;
1213 case OffsetFromUTC:
1214 dat = t2.d->toUtc().addSecs(d->specUtcOffset).date();
1215 break;
1216 case TimeZone:
1217 dat = t2.d->toZone(d->specZone).date(); // this caches the converted time in t2
1218 break;
1219 case ClockTime:
1220 {
1221 KTimeZone local = KSystemTimeZones::local();
1222 dat = t2.d->toZone(local, local).date(); // this caches the converted time in t2
1223 break;
1224 }
1225 default: // invalid
1226 return 0;
1227 }
1228 return d->date().daysTo(dat);
1229}
1230
1231KDateTime KDateTime::currentLocalDateTime()
1232{
1233#ifndef NDEBUG
1234 if (KSystemTimeZones::isSimulated())
1235 return currentUtcDateTime().toZone(KSystemTimeZones::local());
1236#endif
1237 return KDateTime(QDateTime::currentDateTime(), Spec(KSystemTimeZones::local()));
1238}
1239
1240KDateTime KDateTime::currentUtcDateTime()
1241{
1242 KDateTime result;
1243#ifdef Q_OS_WIN
1244 SYSTEMTIME st;
1245 memset(&st, 0, sizeof(SYSTEMTIME));
1246 GetSystemTime(&st);
1247 result = KDateTime(QDate(st.wYear, st.wMonth, st.wDay),
1248 QTime(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds),
1249 UTC);
1250#else
1251 time_t t;
1252 ::time(&t);
1253 result.setTime_t(static_cast<qint64>(t));
1254#endif
1255#ifndef NDEBUG
1256 return result.addSecs(KDateTimePrivate::currentDateTimeOffset);
1257#else
1258 return result;
1259#endif
1260}
1261
1262KDateTime KDateTime::currentDateTime(const Spec &spec)
1263{
1264 switch (spec.type())
1265 {
1266 case UTC:
1267 return currentUtcDateTime();
1268 case TimeZone:
1269 if (spec.timeZone() != KSystemTimeZones::local())
1270 break;
1271 // fall through to LocalZone
1272 case LocalZone:
1273 return currentLocalDateTime();
1274 default:
1275 break;
1276 }
1277 return currentUtcDateTime().toTimeSpec(spec);
1278}
1279
1280QDate KDateTime::currentLocalDate()
1281{
1282 return currentLocalDateTime().date();
1283}
1284
1285QTime KDateTime::currentLocalTime()
1286{
1287 return currentLocalDateTime().time();
1288}
1289
1290KDateTime::Comparison KDateTime::compare(const KDateTime &other) const
1291{
1292 QDateTime start1, start2;
1293 const bool conv = (!d->equalSpec(*other.d) || d->secondOccurrence() != other.d->secondOccurrence());
1294 if (conv)
1295 {
1296 // Different time specs or one is a time which occurs twice,
1297 // so convert to UTC before comparing
1298 start1 = d->toUtc();
1299 start2 = other.d->toUtc();
1300 }
1301 else
1302 {
1303 // Same time specs, so no need to convert to UTC
1304 start1 = d->dt();
1305 start2 = other.d->dt();
1306 }
1307 if (d->dateOnly() || other.d->dateOnly())
1308 {
1309 // At least one of the instances is date-only, so we need to compare
1310 // time periods rather than just times.
1311 QDateTime end1, end2;
1312 if (conv)
1313 {
1314 if (d->dateOnly())
1315 {
1316 KDateTime kdt(*this);
1317 kdt.setTime(QTime(23,59,59,999));
1318 end1 = kdt.d->toUtc();
1319 }
1320 else
1321 end1 = start1;
1322 if (other.d->dateOnly())
1323 {
1324 KDateTime kdt(other);
1325 kdt.setTime(QTime(23,59,59,999));
1326 end2 = kdt.d->toUtc();
1327 }
1328 else
1329 end2 = start2;
1330 }
1331 else
1332 {
1333 if (d->dateOnly())
1334 end1 = QDateTime(d->date(), QTime(23,59,59,999), Qt::LocalTime);
1335 else
1336 end1 = d->dt();
1337 if (other.d->dateOnly())
1338 end2 = QDateTime(other.d->date(), QTime(23,59,59,999), Qt::LocalTime);
1339 else
1340 end2 = other.d->dt();
1341 }
1342 if (start1 == start2)
1343 return !d->dateOnly() ? AtStart : (end1 == end2) ? Equal
1344 : (end1 < end2) ? static_cast<Comparison>(AtStart|Inside)
1345 : static_cast<Comparison>(AtStart|Inside|AtEnd|After);
1346 if (start1 < start2)
1347 return (end1 < start2) ? Before
1348 : (end1 == end2) ? static_cast<Comparison>(Before|AtStart|Inside|AtEnd)
1349 : (end1 == start2) ? static_cast<Comparison>(Before|AtStart)
1350 : (end1 < end2) ? static_cast<Comparison>(Before|AtStart|Inside) : Outside;
1351 else
1352 return (start1 > end2) ? After
1353 : (start1 == end2) ? (end1 == end2 ? AtEnd : static_cast<Comparison>(AtEnd|After))
1354 : (end1 == end2) ? static_cast<Comparison>(Inside|AtEnd)
1355 : (end1 < end2) ? Inside : static_cast<Comparison>(Inside|AtEnd|After);
1356 }
1357 return (start1 == start2) ? Equal : (start1 < start2) ? Before : After;
1358}
1359
1360bool KDateTime::operator==(const KDateTime &other) const
1361{
1362 if (d == other.d)
1363 return true; // the two instances share the same data
1364 if (d->dateOnly() != other.d->dateOnly())
1365 return false;
1366 if (d->equalSpec(*other.d))
1367 {
1368 // Both instances are in the same time zone, so compare directly
1369 if (d->dateOnly())
1370 return d->date() == other.d->date();
1371 else
1372 return d->secondOccurrence() == other.d->secondOccurrence()
1373 && d->dt() == other.d->dt();
1374 }
1375 // Don't waste time converting to UTC if the dates aren't close enough.
1376 if (qAbs(d->date().daysTo(other.d->date())) > 2)
1377 return false;
1378 if (d->dateOnly())
1379 {
1380 // Date-only values are equal if both the start and end of day times are equal.
1381 if (d->toUtc() != other.d->toUtc())
1382 return false; // start-of-day times differ
1383 KDateTime end1(*this);
1384 end1.setTime(QTime(23,59,59,999));
1385 KDateTime end2(other);
1386 end2.setTime(QTime(23,59,59,999));
1387 return end1.d->toUtc() == end2.d->toUtc();
1388 }
1389 return d->toUtc() == other.d->toUtc();
1390}
1391
1392bool KDateTime::operator<(const KDateTime &other) const
1393{
1394 if (d == other.d)
1395 return false; // the two instances share the same data
1396 if (d->equalSpec(*other.d))
1397 {
1398 // Both instances are in the same time zone, so compare directly
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();
1403 // One is the second occurrence of a date/time, during a change from
1404 // daylight saving to standard time, so only do a direct comparison
1405 // if the dates are more than 1 day apart.
1406 const int dayDiff = d->date().daysTo(other.d->date());
1407 if (dayDiff > 1)
1408 return true;
1409 if (dayDiff < -1)
1410 return false;
1411 }
1412 else
1413 {
1414 // Don't waste time converting to UTC if the dates aren't close enough.
1415 const int dayDiff = d->date().daysTo(other.d->date());
1416 if (dayDiff > 2)
1417 return true;
1418 if (dayDiff < -2)
1419 return false;
1420 }
1421 if (d->dateOnly())
1422 {
1423 // This instance is date-only, so we need to compare the end of its
1424 // day with the other value. Note that if the other value is date-only,
1425 // we want to compare with the start of its day, which will happen
1426 // automatically.
1427 KDateTime kdt(*this);
1428 kdt.setTime(QTime(23,59,59,999));
1429 return kdt.d->toUtc() < other.d->toUtc();
1430 }
1431 return d->toUtc() < other.d->toUtc();
1432}
1433
1434QString KDateTime::toString(const QString &format) const
1435{
1436 if (!isValid())
1437 return QString();
1438 enum { TZNone, UTCOffsetShort, UTCOffset, UTCOffsetColon, TZAbbrev, TZName };
1439 KLocale *locale = KGlobal::locale();
1440 KCalendarSystemQDate calendar(locale);
1441 QString result;
1442 QString s;
1443 int num, numLength, zone;
1444 bool escape = false;
1445 ushort flag = 0;
1446 for (int i = 0, end = format.length(); i < end; ++i)
1447 {
1448 zone = TZNone;
1449 num = NO_NUMBER;
1450 numLength = 0; // no leading zeroes
1451 ushort ch = format[i].unicode();
1452 if (!escape)
1453 {
1454 if (ch == '%')
1455 escape = true;
1456 else
1457 result += format[i];
1458 continue;
1459 }
1460 if (!flag)
1461 {
1462 switch (ch)
1463 {
1464 case '%':
1465 result += QLatin1Char('%');
1466 break;
1467 case ':':
1468 flag = ch;
1469 break;
1470 case 'Y': // year
1471 num = d->date().year();
1472 numLength = 4;
1473 break;
1474 case 'y': // year, 2 digits
1475 num = d->date().year() % 100;
1476 numLength = 2;
1477 break;
1478 case 'm': // month, 01 - 12
1479 numLength = 2;
1480 num = d->date().month();
1481 break;
1482 case 'B': // month name, translated
1483 result += calendar.monthName(d->date().month(), 2000, KCalendarSystem::LongName);
1484 break;
1485 case 'b': // month name, translated, short
1486 result += calendar.monthName(d->date().month(), 2000, KCalendarSystem::ShortName);
1487 break;
1488 case 'd': // day of month, 01 - 31
1489 numLength = 2;
1490 // fall through to 'e'
1491 case 'e': // day of month, 1 - 31
1492 num = d->date().day();
1493 break;
1494 case 'A': // week day name, translated
1495 result += calendar.weekDayName(d->date().dayOfWeek(), KCalendarSystem::LongDayName);
1496 break;
1497 case 'a': // week day name, translated, short
1498 result += calendar.weekDayName(d->date().dayOfWeek(), KCalendarSystem::ShortDayName);
1499 break;
1500 case 'H': // hour, 00 - 23
1501 numLength = 2;
1502 // fall through to 'k'
1503 case 'k': // hour, 0 - 23
1504 num = d->dt().time().hour();
1505 break;
1506 case 'I': // hour, 01 - 12
1507 numLength = 2;
1508 // fall through to 'l'
1509 case 'l': // hour, 1 - 12
1510 num = (d->dt().time().hour() + 11) % 12 + 1;
1511 break;
1512 case 'M': // minutes, 00 - 59
1513 num = d->dt().time().minute();
1514 numLength = 2;
1515 break;
1516 case 'S': // seconds, 00 - 59
1517 num = d->dt().time().second();
1518 numLength = 2;
1519 break;
1520 case 'P': // am/pm
1521 {
1522 bool am = (d->dt().time().hour() < 12);
1523 QString ap = ki18n(am ? "am" : "pm").toString(locale);
1524 if (ap.isEmpty())
1525 result += am ? QLatin1String("am") : QLatin1String("pm");
1526 else
1527 result += ap;
1528 break;
1529 }
1530 case 'p': // AM/PM
1531 {
1532 bool am = (d->dt().time().hour() < 12);
1533 QString ap = ki18n(am ? "am" : "pm").toString(locale).toUpper();
1534 if (ap.isEmpty())
1535 result += am ? QLatin1String("AM") : QLatin1String("PM");
1536 else
1537 result += ap;
1538 break;
1539 }
1540 case 'z': // UTC offset in hours and minutes
1541 zone = UTCOffset;
1542 break;
1543 case 'Z': // time zone abbreviation
1544 zone = TZAbbrev;
1545 break;
1546 default:
1547 result += QLatin1Char('%');
1548 result += format[i];
1549 break;
1550 }
1551 }
1552 else if (flag == ':')
1553 {
1554 // It's a "%:" sequence
1555 switch (ch)
1556 {
1557 case 'A': // week day name in English
1558 result += QLatin1String(longDay[d->date().dayOfWeek() - 1]);
1559 break;
1560 case 'a': // week day name in English, short
1561 result += QLatin1String(shortDay[d->date().dayOfWeek() - 1]);
1562 break;
1563 case 'B': // month name in English
1564 result += QLatin1String(longMonth[d->date().month() - 1]);
1565 break;
1566 case 'b': // month name in English, short
1567 result += QLatin1String(shortMonth[d->date().month() - 1]);
1568 break;
1569 case 'm': // month, 1 - 12
1570 num = d->date().month();
1571 break;
1572 case 'P': // am/pm
1573 result += (d->dt().time().hour() < 12) ? QLatin1String("am") : QLatin1String("pm");
1574 break;
1575 case 'p': // AM/PM
1576 result += (d->dt().time().hour() < 12) ? QLatin1String("AM") : QLatin1String("PM");
1577 break;
1578 case 'S': // seconds with ':' prefix, only if non-zero
1579 {
1580 int sec = d->dt().time().second();
1581 if (sec || d->dt().time().msec())
1582 {
1583 result += QLatin1Char(':');
1584 num = sec;
1585 numLength = 2;
1586 }
1587 break;
1588 }
1589 case 's': // milliseconds
1590 result += s.sprintf("%03d", d->dt().time().msec());
1591 break;
1592 case 'u': // UTC offset in hours
1593 zone = UTCOffsetShort;
1594 break;
1595 case 'z': // UTC offset in hours and minutes, with colon
1596 zone = UTCOffsetColon;
1597 break;
1598 case 'Z': // time zone name
1599 zone = TZName;
1600 break;
1601 default:
1602 result += QLatin1String("%:");
1603 result += format[i];
1604 break;
1605 }
1606 flag = 0;
1607 }
1608 if (!flag)
1609 escape = false;
1610
1611 // Append any required number or time zone information
1612 if (num != NO_NUMBER)
1613 {
1614 if (!numLength)
1615 result += QString::number(num);
1616 else if (numLength == 2 || numLength == 4)
1617 {
1618 if (num < 0)
1619 {
1620 num = -num;
1621 result += QLatin1Char('-');
1622 }
1623 result += s.sprintf((numLength == 2 ? "%02d" : "%04d"), num);
1624 }
1625 }
1626 else if (zone != TZNone)
1627 {
1628 KTimeZone tz;
1629 int offset;
1630 switch (d->specType)
1631 {
1632 case UTC:
1633 case TimeZone:
1634 tz = (d->specType == TimeZone) ? d->specZone : KTimeZone::utc();
1635 // fall through to OffsetFromUTC
1636 case OffsetFromUTC:
1637 offset = (d->specType == TimeZone) ? d->timeZoneOffset()
1638 : (d->specType == OffsetFromUTC) ? d->specUtcOffset : 0;
1639 offset /= 60;
1640 switch (zone)
1641 {
1642 case UTCOffsetShort: // UTC offset in hours
1643 case UTCOffset: // UTC offset in hours and minutes
1644 case UTCOffsetColon: // UTC offset in hours and minutes, with colon
1645 {
1646 if (offset >= 0)
1647 result += QLatin1Char('+');
1648 else
1649 {
1650 result += QLatin1Char('-');
1651 offset = -offset;
1652 }
1653 QString s;
1654 result += s.sprintf(((zone == UTCOffsetColon) ? "%02d:" : "%02d"), offset/60);
1655 if (ch != 'u' || offset % 60)
1656 result += s.sprintf("%02d", offset % 60);
1657 break;
1658 }
1659 case TZAbbrev: // time zone abbreviation
1660 if (tz.isValid() && d->specType != OffsetFromUTC)
1661 result += QString::fromLatin1(tz.abbreviation(d->toUtc()));
1662 break;
1663 case TZName: // time zone name
1664 if (tz.isValid() && d->specType != OffsetFromUTC)
1665 result += tz.name();
1666 break;
1667 }
1668 break;
1669 default:
1670 break;
1671 }
1672 }
1673 }
1674 return result;
1675}
1676
1677QString KDateTime::toString(TimeFormat format) const
1678{
1679 QString result;
1680 if (!isValid())
1681 return result;
1682
1683 QString s;
1684 char tzsign = '+';
1685 int offset = 0;
1686 const char *tzcolon = "";
1687 KTimeZone tz;
1688 switch (format)
1689 {
1690 case RFCDateDay:
1691 result += QString::fromLatin1(shortDay[d->date().dayOfWeek() - 1]);
1692 result += QLatin1String(", ");
1693 // fall through to RFCDate
1694 case RFCDate:
1695 {
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();
1701 if (year < 0)
1702 {
1703 result += QLatin1Char('-');
1704 year = -year;
1705 }
1706 result += s.sprintf("%04d %02d:%02d%s ",
1707 year, d->dt().time().hour(), d->dt().time().minute(), seconds);
1708 if (d->specType == ClockTime)
1709 tz = KSystemTimeZones::local();
1710 break;
1711 }
1712 case RFC3339Date:
1713 {
1714 QString s;
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();
1719 if (msec)
1720 {
1721 int digits = 3;
1722 if (!(msec % 10))
1723 msec /= 10, --digits;
1724 if (!(msec % 10))
1725 msec /= 10, --digits;
1726 result += s.sprintf(".%0*d", digits, d->dt().time().msec());
1727 }
1728 if (d->specType == UTC)
1729 return result + QLatin1Char('Z');
1730 if (d->specType == ClockTime)
1731 tz = KSystemTimeZones::local();
1732 tzcolon = ":"; // krazy:exclude=doublequote_chars
1733 break;
1734 }
1735 case ISODate:
1736 {
1737 // QDateTime::toString(Qt::ISODate) doesn't output fractions of a second
1738 int year = d->date().year();
1739 if (year < 0)
1740 {
1741 result += QLatin1Char('-');
1742 year = -year;
1743 }
1744 QString s;
1745 result += s.sprintf("%04d-%02d-%02d",
1746 year, d->date().month(), d->date().day());
1747 if (!d->dateOnly() || d->specType != ClockTime)
1748 {
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())
1752 {
1753 // Comma is preferred by ISO8601 as the decimal point symbol,
1754 // so use it unless '.' is the symbol used in this locale or we don't have a locale.
1755 KLocale *locale = KGlobal::locale();
1756 result += (locale && locale->decimalSymbol() == QLatin1String(".")) ? QLatin1Char('.') : QLatin1Char(',');
1757 result += s.sprintf("%03d", d->dt().time().msec());
1758 }
1759 }
1760 if (d->specType == UTC)
1761 return result + QLatin1Char('Z');
1762 if (d->specType == ClockTime)
1763 return result;
1764 tzcolon = ":"; // krazy:exclude=doublequote_chars
1765 break;
1766 }
1767 case QtTextDate:
1768 case LocalDate:
1769 {
1770 Qt::DateFormat qtfmt = (format == QtTextDate) ? Qt::TextDate : Qt::LocalDate;
1771 if (d->dateOnly())
1772 result = d->date().toString(qtfmt);
1773 else
1774 result = d->dt().toString(qtfmt);
1775 if (result.isEmpty() || d->specType == ClockTime)
1776 return result;
1777 result += QLatin1Char(' ');
1778 break;
1779 }
1780 default:
1781 return result;
1782 }
1783
1784 // Return the string with UTC offset ±hhmm appended
1785 if (d->specType == OffsetFromUTC || d->specType == TimeZone || tz.isValid())
1786 {
1787 if (d->specType == TimeZone)
1788 offset = d->timeZoneOffset(); // calculate offset and cache UTC value
1789 else
1790 offset = tz.isValid() ? tz.offsetAtZoneTime(d->dt()) : d->specUtcOffset;
1791 if (offset < 0)
1792 {
1793 offset = -offset;
1794 tzsign = '-';
1795 }
1796 }
1797 offset /= 60;
1798 return result + s.sprintf("%c%02d%s%02d", tzsign, offset/60, tzcolon, offset%60);
1799}
1800
1801KDateTime KDateTime::fromString(const QString &string, TimeFormat format, bool *negZero)
1802{
1803 if (negZero)
1804 *negZero = false;
1805 QString str = string.trimmed();
1806 if (str.isEmpty())
1807 return KDateTime();
1808
1809 switch (format)
1810 {
1811 case RFCDateDay: // format is Wdy, DD Mon YYYY hh:mm:ss ±hhmm
1812 case RFCDate: // format is [Wdy,] DD Mon YYYY hh:mm[:ss] ±hhmm
1813 {
1814 int nyear = 6; // indexes within string to values
1815 int nmonth = 4;
1816 int nday = 2;
1817 int nwday = 1;
1818 int nhour = 7;
1819 int nmin = 8;
1820 int nsec = 9;
1821 // Also accept obsolete form "Weekday, DD-Mon-YY HH:MM:SS ±hhmm"
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+)$"));
1823 QStringList parts;
1824 if (!str.indexOf(rx))
1825 {
1826 // Check that if date has '-' separators, both separators are '-'.
1827 parts = rx.capturedTexts();
1828 bool h1 = (parts[3] == QLatin1String("-"));
1829 bool h2 = (parts[5] == QLatin1String("-"));
1830 if (h1 != h2)
1831 break;
1832 }
1833 else
1834 {
1835 // Check for the obsolete form "Wdy Mon DD HH:MM:SS YYYY"
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))
1838 break;
1839 nyear = 7;
1840 nmonth = 2;
1841 nday = 3;
1842 nwday = 1;
1843 nhour = 4;
1844 nmin = 5;
1845 nsec = 6;
1846 parts = rx.capturedTexts();
1847 }
1848 bool ok[4];
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])
1854 break;
1855 int second = 0;
1856 if (!parts[nsec].isEmpty())
1857 {
1858 second = parts[nsec].toInt(&ok[0]);
1859 if (!ok[0])
1860 break;
1861 }
1862 bool leapSecond = (second == 60);
1863 if (leapSecond)
1864 second = 59; // apparently a leap second - validate below, once time zone is known
1865 int month = 0;
1866 for ( ; month < 12 && parts[nmonth] != QLatin1String(shortMonth[month]); ++month) ;
1867 int dayOfWeek = -1;
1868 if (!parts[nwday].isEmpty())
1869 {
1870 // Look up the weekday name
1871 while (++dayOfWeek < 7 && QLatin1String(shortDay[dayOfWeek]) != parts[nwday]) ;
1872 if (dayOfWeek >= 7)
1873 for (dayOfWeek = 0; dayOfWeek < 7 && QLatin1String(longDay[dayOfWeek]) != parts[nwday]; ++dayOfWeek) ;
1874 }
1875 if (month >= 12 || dayOfWeek >= 7
1876 || (dayOfWeek < 0 && format == RFCDateDay))
1877 break;
1878 int i = parts[nyear].size();
1879 if (i < 4)
1880 {
1881 // It's an obsolete year specification with less than 4 digits
1882 year += (i == 2 && year < 50) ? 2000 : 1900;
1883 }
1884
1885 // Parse the UTC offset part
1886 int offset = 0; // set default to '-0000'
1887 bool negOffset = false;
1888 if (parts.count() > 10)
1889 {
1890 rx = QRegExp(QString::fromLatin1("^([+-])(\\d\\d)(\\d\\d)$"));
1891 if (!parts[10].indexOf(rx))
1892 {
1893 // It's a UTC offset ±hhmm
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)
1898 break;
1899 offset += offsetMin * 60;
1900 negOffset = (parts[1] == QLatin1String("-"));
1901 if (negOffset)
1902 offset = -offset;
1903 }
1904 else
1905 {
1906 // Check for an obsolete time zone name
1907 QByteArray zone = parts[10].toLatin1();
1908 if (zone.length() == 1 && isalpha(zone[0]) && toupper(zone[0]) != 'J')
1909 negOffset = true; // military zone: RFC 2822 treats as '-0000'
1910 else if (zone != "UT" && zone != "GMT") // treated as '+0000'
1911 {
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
1917 : 0;
1918 if (!offset)
1919 {
1920 // Check for any other alphabetic time zone
1921 bool nonalpha = false;
1922 for (int i = 0, end = zone.size(); i < end && !nonalpha; ++i)
1923 nonalpha = !isalpha(zone[i]);
1924 if (nonalpha)
1925 break;
1926 // TODO: Attempt to recognize the time zone abbreviation?
1927 negOffset = true; // unknown time zone: RFC 2822 treats as '-0000'
1928 }
1929 }
1930 }
1931 }
1932 Status invalid = stValid;
1933 QDate qdate = checkDate(year, month+1, day, invalid); // convert date, and check for out-of-range
1934 if (!qdate.isValid())
1935 break;
1936 KDateTime result(qdate, QTime(hour, minute, second), Spec(OffsetFromUTC, offset));
1937 if (!result.isValid()
1938 || (dayOfWeek >= 0 && result.date().dayOfWeek() != dayOfWeek+1))
1939 break; // invalid date/time, or weekday doesn't correspond with date
1940 if (!offset)
1941 {
1942 if (negOffset && negZero)
1943 *negZero = true; // UTC offset given as "-0000"
1944 result.setTimeSpec(UTC);
1945 }
1946 if (leapSecond)
1947 {
1948 // Validate a leap second time. Leap seconds are inserted after 23:59:59 UTC.
1949 // Convert the time to UTC and check that it is 00:00:00.
1950 if ((hour*3600 + minute*60 + 60 - offset + 86400*5) % 86400) // (max abs(offset) is 100 hours)
1951 break; // the time isn't the last second of the day
1952 }
1953 if (invalid)
1954 {
1955 KDateTime dt; // date out of range - return invalid KDateTime ...
1956 dt.d->status = invalid; // ... with reason for error
1957 return dt;
1958 }
1959 return result;
1960 }
1961 case RFC3339Date: // format is YYYY-MM-DDThh:mm:ss[.s]TZ
1962 {
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))
1965 break;
1966 const QStringList parts = rx.capturedTexts();
1967 bool ok, ok1, ok2;
1968 int msecs = 0;
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)
1974 break;
1975 QDate d(year, month, day);
1976 if (!d.isValid())
1977 break;
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)
1982 break;
1983 leapSecond = (second == 60);
1984 if (leapSecond)
1985 second = 59; // apparently a leap second - validate below, once time zone is known
1986 if (!parts[7].isEmpty())
1987 {
1988 QString ms = parts[7] + QLatin1String("00");
1989 ms.truncate(3);
1990 msecs = ms.toInt(&ok);
1991 if (!ok)
1992 break;
1993 if (msecs && leapSecond)
1994 break; // leap second only valid if 23:59:60.000
1995 }
1996 QTime t(hour, minute, second, msecs);
1997 if (!t.isValid())
1998 break;
1999 int offset = 0;
2000 SpecType spec = (parts[8].toUpper() == QLatin1String("Z")) ? UTC : OffsetFromUTC;
2001 if (spec == OffsetFromUTC)
2002 {
2003 offset = parts[10].toInt(&ok) * 3600;
2004 offset += parts[11].toInt(&ok1) * 60;
2005 if (!ok || !ok1)
2006 break;
2007 if (parts[9] == QLatin1String("-"))
2008 {
2009 if (!offset && leapSecond)
2010 break; // leap second only valid if known time zone
2011 offset = -offset;
2012 if (!offset && negZero)
2013 *negZero = true;
2014 }
2015 }
2016 if (leapSecond)
2017 {
2018 // Validate a leap second time. Leap seconds are inserted after 23:59:59 UTC.
2019 // Convert the time to UTC and check that it is 00:00:00.
2020 if ((hour*3600 + minute*60 + 60 - offset + 86400*5) % 86400) // (max abs(offset) is 100 hours)
2021 break; // the time isn't the last second of the day
2022 }
2023 return KDateTime(d, t, Spec(spec, offset));
2024 }
2025 case ISODate:
2026 {
2027 /*
2028 * Extended format: [±]YYYY-MM-DD[Thh[:mm[:ss.s]][TZ]]
2029 * Basic format: [±]YYYYMMDD[Thh[mm[ss.s]][TZ]]
2030 * Extended format: [±]YYYY-DDD[Thh[:mm[:ss.s]][TZ]]
2031 * Basic format: [±]YYYYDDD[Thh[mm[ss.s]][TZ]]
2032 * In the first three formats, the year may be expanded to more than 4 digits.
2033 *
2034 * QDateTime::fromString(Qt::ISODate) is a rather limited implementation
2035 * of parsing ISO 8601 format date/time strings, so it isn't used here.
2036 * This implementation isn't complete either, but it's better.
2037 *
2038 * ISO 8601 allows truncation, but for a combined date & time, the date part cannot
2039 * be truncated from the right, and the time part cannot be truncated from the left.
2040 * In other words, only the outer parts of the string can be omitted.
2041 * The standard does not actually define how to interpret omitted parts - it is up
2042 * to those interchanging the data to agree on a scheme.
2043 */
2044 bool dateOnly = false;
2045 // Check first for the extended format of ISO 8601
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))
2048 {
2049 // It's not the extended format - check for the basic format
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))
2052 {
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))
2055 {
2056 // Check for date-only formats
2057 dateOnly = true;
2058 rx = QRegExp(QString::fromLatin1("^([+-])?(\\d{4,})-(\\d\\d\\d|\\d\\d-\\d\\d)$"));
2059 if (str.indexOf(rx))
2060 {
2061 // It's not the extended format - check for the basic format
2062 rx = QRegExp(QString::fromLatin1("^([+-])?(\\d{4,})(\\d{4})$"));
2063 if (str.indexOf(rx))
2064 {
2065 rx = QRegExp(QString::fromLatin1("^([+-])?(\\d{4})(\\d{3})$"));
2066 if (str.indexOf(rx))
2067 break;
2068 }
2069 }
2070 }
2071 }
2072 }
2073 const QStringList parts = rx.capturedTexts();
2074 bool ok, ok1;
2075 QDate d;
2076 int hour = 0;
2077 int minute = 0;
2078 int second = 0;
2079 int msecs = 0;
2080 bool leapSecond = false;
2081 int year = parts[2].toInt(&ok);
2082 if (!ok)
2083 break;
2084 if (parts[1] == QLatin1String("-"))
2085 year = -year;
2086 if (!dateOnly)
2087 {
2088 hour = parts[4].toInt(&ok);
2089 if (!ok)
2090 break;
2091 if (!parts[5].isEmpty())
2092 {
2093 minute = parts[5].toInt(&ok);
2094 if (!ok)
2095 break;
2096 }
2097 if (!parts[6].isEmpty())
2098 {
2099 second = parts[6].toInt(&ok);
2100 if (!ok)
2101 break;
2102 }
2103 leapSecond = (second == 60);
2104 if (leapSecond)
2105 second = 59; // apparently a leap second - validate below, once time zone is known
2106 if (!parts[7].isEmpty())
2107 {
2108 QString ms = parts[7] + QLatin1String("00");
2109 ms.truncate(3);
2110 msecs = ms.toInt(&ok);
2111 if (!ok)
2112 break;
2113 }
2114 }
2115 int month, day;
2116 Status invalid = stValid;
2117 if (parts[3].length() == 3)
2118 {
2119 // A day of the year is specified
2120 day = parts[3].toInt(&ok);
2121 if (!ok || day < 1 || day > 366)
2122 break;
2123 d = checkDate(year, 1, 1, invalid).addDays(day - 1); // convert date, and check for out-of-range
2124 if (!d.isValid() || (!invalid && d.year() != year))
2125 break;
2126 day = d.day();
2127 month = d.month();
2128 }
2129 else
2130 {
2131 // A month and day are specified
2132 month = parts[3].left(2).toInt(&ok);
2133 day = parts[3].right(2).toInt(&ok1);
2134 if (!ok || !ok1)
2135 break;
2136 d = checkDate(year, month, day, invalid); // convert date, and check for out-of-range
2137 if (!d.isValid())
2138 break;
2139 }
2140 if (dateOnly)
2141 {
2142 if (invalid)
2143 {
2144 KDateTime dt; // date out of range - return invalid KDateTime ...
2145 dt.d->status = invalid; // ... with reason for error
2146 return dt;
2147 }
2148 return KDateTime(d, Spec(ClockTime));
2149 }
2150 if (hour == 24 && !minute && !second && !msecs)
2151 {
2152 // A time of 24:00:00 is allowed by ISO 8601, and means midnight at the end of the day
2153 d = d.addDays(1);
2154 hour = 0;
2155 }
2156
2157 QTime t(hour, minute, second, msecs);
2158 if (!t.isValid())
2159 break;
2160 if (parts[8].isEmpty())
2161 {
2162 // No UTC offset is specified. Don't try to validate leap seconds.
2163 if (invalid)
2164 {
2165 KDateTime dt; // date out of range - return invalid KDateTime ...
2166 dt.d->status = invalid; // ... with reason for error
2167 return dt;
2168 }
2169 return KDateTime(d, t, KDateTimePrivate::fromStringDefault());
2170 }
2171 int offset = 0;
2172 SpecType spec = (parts[8] == QLatin1String("Z")) ? UTC : OffsetFromUTC;
2173 if (spec == OffsetFromUTC)
2174 {
2175 offset = parts[10].toInt(&ok) * 3600;
2176 if (!ok)
2177 break;
2178 if (!parts[11].isEmpty())
2179 {
2180 offset += parts[11].toInt(&ok) * 60;
2181 if (!ok)
2182 break;
2183 }
2184 if (parts[9] == QLatin1String("-"))
2185 {
2186 offset = -offset;
2187 if (!offset && negZero)
2188 *negZero = true;
2189 }
2190 }
2191 if (leapSecond)
2192 {
2193 // Validate a leap second time. Leap seconds are inserted after 23:59:59 UTC.
2194 // Convert the time to UTC and check that it is 00:00:00.
2195 if ((hour*3600 + minute*60 + 60 - offset + 86400*5) % 86400) // (max abs(offset) is 100 hours)
2196 break; // the time isn't the last second of the day
2197 }
2198 if (invalid)
2199 {
2200 KDateTime dt; // date out of range - return invalid KDateTime ...
2201 dt.d->status = invalid; // ... with reason for error
2202 return dt;
2203 }
2204 return KDateTime(d, t, Spec(spec, offset));
2205 }
2206 case QtTextDate: // format is Wdy Mth DD [hh:mm:ss] YYYY [±hhmm]
2207 {
2208 int offset = 0;
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)
2211 break;
2212 QStringList parts = rx.capturedTexts();
2213 QDate qd;
2214 QDateTime qdt;
2215 bool dateOnly = parts[2].isEmpty();
2216 if (dateOnly)
2217 {
2218 qd = QDate::fromString(parts[1], Qt::TextDate);
2219 if (!qd.isValid())
2220 break;
2221 }
2222 else
2223 {
2224 qdt = QDateTime::fromString(parts[1], Qt::TextDate);
2225 if (!qdt.isValid())
2226 break;
2227 }
2228 if (parts[3].isEmpty())
2229 {
2230 // No time zone offset specified, so return a local clock time
2231 if (dateOnly)
2232 return KDateTime(qd, KDateTimePrivate::fromStringDefault());
2233 else
2234 {
2235 // Do it this way to prevent UTC conversions changing the time
2236 return KDateTime(qdt.date(), qdt.time(), KDateTimePrivate::fromStringDefault());
2237 }
2238 }
2239 rx = QRegExp(QString::fromLatin1("([+-])([\\d][\\d])(?::?([\\d][\\d]))?$"));
2240 if (parts[3].indexOf(rx) < 0)
2241 break;
2242
2243 // Extract the UTC offset at the end of the string
2244 bool ok;
2245 parts = rx.capturedTexts();
2246 offset = parts[2].toInt(&ok) * 3600;
2247 if (!ok)
2248 break;
2249 if (parts.count() > 3)
2250 {
2251 offset += parts[3].toInt(&ok) * 60;
2252 if (!ok)
2253 break;
2254 }
2255 if (parts[1] == QLatin1String("-"))
2256 {
2257 offset = -offset;
2258 if (!offset && negZero)
2259 *negZero = true;
2260 }
2261 if (dateOnly)
2262 return KDateTime(qd, Spec((offset ? OffsetFromUTC : UTC), offset));
2263 qdt.setTimeSpec(offset ? Qt::LocalTime : Qt::UTC);
2264 return KDateTime(qdt, Spec((offset ? OffsetFromUTC : UTC), offset));
2265 }
2266 case LocalDate:
2267 default:
2268 break;
2269 }
2270 return KDateTime();
2271}
2272
2273KDateTime KDateTime::fromString(const QString &string, const QString &format,
2274 const KTimeZones *zones, bool offsetIfAmbiguous)
2275{
2276 int utcOffset = 0; // UTC offset in seconds
2277 bool dateOnly = false;
2278 Status invalid = stValid;
2279 QString zoneName;
2280 QByteArray zoneAbbrev;
2281 QDateTime qdt = fromStr(string, format, utcOffset, zoneName, zoneAbbrev, dateOnly, invalid);
2282 if (!qdt.isValid())
2283 return KDateTime();
2284 if (zones)
2285 {
2286 // Try to find a time zone match
2287 bool zname = false;
2288 KTimeZone zone;
2289 if (!zoneName.isEmpty())
2290 {
2291 // A time zone name has been found.
2292 // Use the time zone with that name.
2293 zone = zones->zone(zoneName);
2294 zname = true;
2295 }
2296 else if (!invalid)
2297 {
2298 if (!zoneAbbrev.isEmpty())
2299 {
2300 // A time zone abbreviation has been found.
2301 // Use the time zone which contains it, if any, provided that the
2302 // abbreviation applies at the specified date/time.
2303 bool useUtcOffset = false;
2304 const KTimeZones::ZoneMap z = zones->zones();
2305 for (KTimeZones::ZoneMap::ConstIterator it = z.constBegin(); it != z.constEnd(); ++it)
2306 {
2307 if (it.value().abbreviations().contains(zoneAbbrev))
2308 {
2309 int offset2;
2310 int offset = it.value().offsetAtZoneTime(qdt, &offset2);
2311 QDateTime ut(qdt);
2312 ut.setTimeSpec(Qt::UTC);
2313 ut = ut.addSecs(-offset);
2314 if (it.value().abbreviation(ut) != zoneAbbrev)
2315 {
2316 if (offset == offset2)
2317 continue; // abbreviation doesn't apply at specified time
2318 ut = ut.addSecs(offset - offset2);
2319 if (it.value().abbreviation(ut) != zoneAbbrev)
2320 continue; // abbreviation doesn't apply at specified time
2321 offset = offset2;
2322 }
2323 // Found a time zone which uses this abbreviation at the specified date/time
2324 if (zone.isValid())
2325 {
2326 // Abbreviation is used by more than one time zone
2327 if (!offsetIfAmbiguous || offset != utcOffset)
2328 return KDateTime();
2329 useUtcOffset = true;
2330 }
2331 else
2332 {
2333 zone = it.value();
2334 utcOffset = offset;
2335 }
2336 }
2337 }
2338 if (useUtcOffset)
2339 {
2340 zone = KTimeZone();
2341 if (!utcOffset)
2342 qdt.setTimeSpec(Qt::UTC);
2343 }
2344 else
2345 zname = true;
2346 }
2347 else if (utcOffset || qdt.timeSpec() == Qt::UTC)
2348 {
2349 // A UTC offset has been found.
2350 // Use the time zone which contains it, if any.
2351 // For a date-only value, use the start of the day.
2352 QDateTime dtUTC = qdt;
2353 dtUTC.setTimeSpec(Qt::UTC);
2354 dtUTC = dtUTC.addSecs(-utcOffset);
2355 const KTimeZones::ZoneMap z = zones->zones();
2356 for (KTimeZones::ZoneMap::ConstIterator it = z.constBegin(); it != z.constEnd(); ++it)
2357 {
2358 QList<int> offsets = it.value().utcOffsets();
2359 if ((offsets.isEmpty() || offsets.contains(utcOffset))
2360 && it.value().offsetAtUtc(dtUTC) == utcOffset)
2361 {
2362 // Found a time zone which uses this offset at the specified time
2363 if (zone.isValid() || !utcOffset)
2364 {
2365 // UTC offset is used by more than one time zone
2366 if (!offsetIfAmbiguous)
2367 return KDateTime();
2368 if (invalid)
2369 {
2370 KDateTime dt; // date out of range - return invalid KDateTime ...
2371 dt.d->status = invalid; // ... with reason for error
2372 return dt;
2373 }
2374 if (dateOnly)
2375 return KDateTime(qdt.date(), Spec(OffsetFromUTC, utcOffset));
2376 qdt.setTimeSpec(Qt::LocalTime);
2377 return KDateTime(qdt, Spec(OffsetFromUTC, utcOffset));
2378 }
2379 zone = it.value();
2380 }
2381 }
2382 }
2383 }
2384 if (!zone.isValid() && zname)
2385 return KDateTime(); // an unknown zone name or abbreviation was found
2386 if (zone.isValid() && !invalid)
2387 {
2388 if (dateOnly)
2389 return KDateTime(qdt.date(), Spec(zone));
2390 return KDateTime(qdt, Spec(zone));
2391 }
2392 }
2393
2394 // No time zone match was found
2395 if (invalid)
2396 {
2397 KDateTime dt; // date out of range - return invalid KDateTime ...
2398 dt.d->status = invalid; // ... with reason for error
2399 return dt;
2400 }
2401 KDateTime result;
2402 if (utcOffset)
2403 {
2404 qdt.setTimeSpec(Qt::LocalTime);
2405 result = KDateTime(qdt, Spec(OffsetFromUTC, utcOffset));
2406 }
2407 else if (qdt.timeSpec() == Qt::UTC)
2408 result = KDateTime(qdt, UTC);
2409 else
2410 {
2411 result = KDateTime(qdt, Spec(ClockTime));
2412 result.setTimeSpec(KDateTimePrivate::fromStringDefault());
2413 }
2414 if (dateOnly)
2415 result.setDateOnly(true);
2416 return result;
2417}
2418
2419void KDateTime::setFromStringDefault(const Spec &spec)
2420{
2421 KDateTimePrivate::fromStringDefault() = spec;
2422}
2423
2424void KDateTime::setSimulatedSystemTime(const KDateTime& newTime)
2425{
2426 Q_UNUSED(newTime);
2427#ifndef NDEBUG
2428 if (newTime.isValid())
2429 {
2430 KDateTimePrivate::currentDateTimeOffset = realCurrentLocalDateTime().secsTo_long(newTime);
2431 KSystemTimeZones::setLocalZone(newTime.timeZone());
2432 }
2433 else
2434 {
2435 KDateTimePrivate::currentDateTimeOffset = 0;
2436 KSystemTimeZones::setLocalZone(KTimeZone());
2437 }
2438#endif
2439}
2440
2441KDateTime KDateTime::realCurrentLocalDateTime()
2442{
2443#ifndef NDEBUG
2444 return KDateTime(QDateTime::currentDateTime(), KSystemTimeZones::realLocalZone());
2445#else
2446 return KDateTime(QDateTime::currentDateTime(), Spec(KSystemTimeZones::local()));
2447#endif
2448}
2449
2450QDataStream & operator<<(QDataStream &s, const KDateTime &dt)
2451{
2452 s << dt.date() << dt.time() << dt.timeSpec() << quint8(dt.isDateOnly() ? 0x01 : 0x00);
2453 return s;
2454}
2455
2456QDataStream & operator>>(QDataStream &s, KDateTime &kdt)
2457{
2458 QDate d;
2459 QTime t;
2460 KDateTime::Spec spec;
2461 quint8 flags;
2462 s >> d >> t >> spec >> flags;
2463 if (flags & 0x01)
2464 kdt = KDateTime(d, spec);
2465 else
2466 kdt = KDateTime(d, t, spec);
2467 return s;
2468}
2469
2470
2471/*
2472 * Extracts a QDateTime from a string, given a format string.
2473 * The date/time is set to Qt::UTC if a zero UTC offset is found,
2474 * otherwise it is Qt::LocalTime. If Qt::LocalTime is returned and
2475 * utcOffset == 0, that indicates that no UTC offset was found.
2476 */
2477QDateTime fromStr(const QString& string, const QString& format, int& utcOffset,
2478 QString& zoneName, QByteArray& zoneAbbrev, bool& dateOnly, Status &status)
2479{
2480 status = stValid;
2481 QString str = string.simplified();
2482 int year = NO_NUMBER;
2483 int month = NO_NUMBER;
2484 int day = NO_NUMBER;
2485 int dayOfWeek = NO_NUMBER;
2486 int hour = NO_NUMBER;
2487 int minute = NO_NUMBER;
2488 int second = NO_NUMBER;
2489 int millisec = NO_NUMBER;
2490 int ampm = NO_NUMBER;
2491 int tzoffset = NO_NUMBER;
2492 zoneName.clear();
2493 zoneAbbrev.clear();
2494
2495 enum { TZNone, UTCOffset, UTCOffsetColon, TZAbbrev, TZName };
2496 KLocale *locale = KGlobal::locale();
2497 KCalendarSystemQDate calendar(locale);
2498 int zone;
2499 int s = 0;
2500 int send = str.length();
2501 bool escape = false;
2502 ushort flag = 0;
2503 for (int f = 0, fend = format.length(); f < fend && s < send; ++f)
2504 {
2505 zone = TZNone;
2506 ushort ch = format[f].unicode();
2507 if (!escape)
2508 {
2509 if (ch == '%')
2510 escape = true;
2511 else if (format[f].isSpace())
2512 {
2513 if (str[s].isSpace())
2514 ++s;
2515 }
2516 else if (format[f] == str[s])
2517 ++s;
2518 else
2519 return QDateTime();
2520 continue;
2521 }
2522 if (!flag)
2523 {
2524 switch (ch)
2525 {
2526 case '%':
2527 if (str[s++] != QLatin1Char('%'))
2528 return QDateTime();
2529 break;
2530 case ':':
2531 flag = ch;
2532 break;
2533 case 'Y': // full year, 4 digits
2534 if (!getNumber(str, s, 4, 4, NO_NUMBER, -1, year))
2535 return QDateTime();
2536 break;
2537 case 'y': // year, 2 digits
2538 if (!getNumber(str, s, 2, 2, 0, 99, year))
2539 return QDateTime();
2540 year += (year <= 50) ? 2000 : 1999;
2541 break;
2542 case 'm': // month, 2 digits, 01 - 12
2543 if (!getNumber(str, s, 2, 2, 1, 12, month))
2544 return QDateTime();
2545 break;
2546 case 'B':
2547 case 'b': // month name, translated or English
2548 {
2549 int m = matchMonth(str, s, &calendar);
2550 if (m <= 0 || (month != NO_NUMBER && month != m))
2551 return QDateTime();
2552 month = m;
2553 break;
2554 }
2555 case 'd': // day of month, 2 digits, 01 - 31
2556 if (!getNumber(str, s, 2, 2, 1, 31, day))
2557 return QDateTime();
2558 break;
2559 case 'e': // day of month, 1 - 31
2560 if (!getNumber(str, s, 1, 2, 1, 31, day))
2561 return QDateTime();
2562 break;
2563 case 'A':
2564 case 'a': // week day name, translated or English
2565 {
2566 int dow = matchDay(str, s, &calendar);
2567 if (dow <= 0 || (dayOfWeek != NO_NUMBER && dayOfWeek != dow))
2568 return QDateTime();
2569 dayOfWeek = dow;
2570 break;
2571 }
2572 case 'H': // hour, 2 digits, 00 - 23
2573 if (!getNumber(str, s, 2, 2, 0, 23, hour))
2574 return QDateTime();
2575 break;
2576 case 'k': // hour, 0 - 23
2577 if (!getNumber(str, s, 1, 2, 0, 23, hour))
2578 return QDateTime();
2579 break;
2580 case 'I': // hour, 2 digits, 01 - 12
2581 if (!getNumber(str, s, 2, 2, 1, 12, hour))
2582 return QDateTime();
2583 break;
2584 case 'l': // hour, 1 - 12
2585 if (!getNumber(str, s, 1, 2, 1, 12, hour))
2586 return QDateTime();
2587 break;
2588 case 'M': // minutes, 2 digits, 00 - 59
2589 if (!getNumber(str, s, 2, 2, 0, 59, minute))
2590 return QDateTime();
2591 break;
2592 case 'S': // seconds, 2 digits, 00 - 59
2593 if (!getNumber(str, s, 2, 2, 0, 59, second))
2594 return QDateTime();
2595 break;
2596 case 's': // seconds, 0 - 59
2597 if (!getNumber(str, s, 1, 2, 0, 59, second))
2598 return QDateTime();
2599 break;
2600 case 'P':
2601 case 'p': // am/pm
2602 {
2603 int ap = getAmPm(str, s, locale);
2604 if (!ap || (ampm != NO_NUMBER && ampm != ap))
2605 return QDateTime();
2606 ampm = ap;
2607 break;
2608 }
2609 case 'z': // UTC offset in hours and optionally minutes
2610 zone = UTCOffset;
2611 break;
2612 case 'Z': // time zone abbreviation
2613 zone = TZAbbrev;
2614 break;
2615 case 't': // whitespace
2616 if (str[s++] != QLatin1Char(' '))
2617 return QDateTime();
2618 break;
2619 default:
2620 if (s + 2 > send
2621 || str[s++] != QLatin1Char('%')
2622 || str[s++] != format[f])
2623 return QDateTime();
2624 break;
2625 }
2626 }
2627 else if (flag == ':')
2628 {
2629 // It's a "%:" sequence
2630 switch (ch)
2631 {
2632 case 'Y': // full year, >= 4 digits
2633 if (!getNumber(str, s, 4, 100, NO_NUMBER, -1, year))
2634 return QDateTime();
2635 break;
2636 case 'A':
2637 case 'a': // week day name in English
2638 {
2639 int dow = matchDay(str, s, 0);
2640 if (dow <= 0 || (dayOfWeek != NO_NUMBER && dayOfWeek != dow))
2641 return QDateTime();
2642 dayOfWeek = dow;
2643 break;
2644 }
2645 case 'B':
2646 case 'b': // month name in English
2647 {
2648 int m = matchMonth(str, s, 0);
2649 if (m <= 0 || (month != NO_NUMBER && month != m))
2650 return QDateTime();
2651 month = m;
2652 break;
2653 }
2654 case 'm': // month, 1 - 12
2655 if (!getNumber(str, s, 1, 2, 1, 12, month))
2656 return QDateTime();
2657 break;
2658 case 'P':
2659 case 'p': // am/pm in English
2660 {
2661 int ap = getAmPm(str, s, 0);
2662 if (!ap || (ampm != NO_NUMBER && ampm != ap))
2663 return QDateTime();
2664 ampm = ap;
2665 break;
2666 }
2667 case 'M': // minutes, 0 - 59
2668 if (!getNumber(str, s, 1, 2, 0, 59, minute))
2669 return QDateTime();
2670 break;
2671 case 'S': // seconds with ':' prefix, defaults to zero
2672 if (str[s] != QLatin1Char(':'))
2673 {
2674 second = 0;
2675 break;
2676 }
2677 ++s;
2678 if (!getNumber(str, s, 1, 2, 0, 59, second))
2679 return QDateTime();
2680 break;
2681 case 's': // milliseconds, with decimal point prefix
2682 {
2683 if (str[s] != QLatin1Char('.'))
2684 {
2685 // If no locale, try comma, it is preferred by ISO8601 as the decimal point symbol
2686 QString dpt = locale == 0 ? QString::fromLatin1(",") : locale->decimalSymbol();
2687 if (!str.mid(s).startsWith(dpt))
2688 return QDateTime();
2689 s += dpt.length() - 1;
2690 }
2691 ++s;
2692 if (s >= send)
2693 return QDateTime();
2694 QString val = str.mid(s);
2695 int i = 0;
2696 for (int end = val.length(); i < end && val[i].isDigit(); ++i) ;
2697 if (!i)
2698 return QDateTime();
2699 val.truncate(i);
2700 val += QLatin1String("00");
2701 val.truncate(3);
2702 int ms = val.toInt();
2703 if (millisec != NO_NUMBER && millisec != ms)
2704 return QDateTime();
2705 millisec = ms;
2706 s += i;
2707 break;
2708 }
2709 case 'u': // UTC offset in hours and optionally minutes
2710 zone = UTCOffset;
2711 break;
2712 case 'z': // UTC offset in hours and minutes, with colon
2713 zone = UTCOffsetColon;
2714 break;
2715 case 'Z': // time zone name
2716 zone = TZName;
2717 break;
2718 default:
2719 if (s + 3 > send
2720 || str[s++] != QLatin1Char('%')
2721 || str[s++] != QLatin1Char(':')
2722 || str[s++] != format[f])
2723 return QDateTime();
2724 break;
2725 }
2726 flag = 0;
2727 }
2728 if (!flag)
2729 escape = false;
2730
2731 if (zone != TZNone)
2732 {
2733 // Read time zone or UTC offset
2734 switch (zone)
2735 {
2736 case UTCOffset:
2737 case UTCOffsetColon:
2738 if (!zoneAbbrev.isEmpty() || !zoneName.isEmpty())
2739 return QDateTime();
2740 if (!getUTCOffset(str, s, (zone == UTCOffsetColon), tzoffset))
2741 return QDateTime();
2742 break;
2743 case TZAbbrev: // time zone abbreviation
2744 {
2745 if (tzoffset != NO_NUMBER || !zoneName.isEmpty())
2746 return QDateTime();
2747 int start = s;
2748 while (s < send && str[s].isLetterOrNumber())
2749 ++s;
2750 if (s == start)
2751 return QDateTime();
2752 QString z = str.mid(start, s - start);
2753 if (!zoneAbbrev.isEmpty() && z.toLatin1() != zoneAbbrev)
2754 return QDateTime();
2755 zoneAbbrev = z.toLatin1();
2756 break;
2757 }
2758 case TZName: // time zone name
2759 {
2760 if (tzoffset != NO_NUMBER || !zoneAbbrev.isEmpty())
2761 return QDateTime();
2762 QString z;
2763 if (f + 1 >= fend)
2764 {
2765 z = str.mid(s);
2766 s = send;
2767 }
2768 else
2769 {
2770 // Get the terminating character for the zone name
2771 QChar endchar = format[f + 1];
2772 if (endchar == QLatin1Char('%') && f + 2 < fend)
2773 {
2774 QChar endchar2 = format[f + 2];
2775 if (endchar2 == QLatin1Char('n') || endchar2 == QLatin1Char('t'))
2776 endchar = QLatin1Char(' ');
2777 }
2778 // Extract from the input string up to the terminating character
2779 int start = s;
2780 for ( ; s < send && str[s] != endchar; ++s) ;
2781 if (s == start)
2782 return QDateTime();
2783 z = str.mid(start, s - start);
2784 }
2785 if (!zoneName.isEmpty() && z != zoneName)
2786 return QDateTime();
2787 zoneName = z;
2788 break;
2789 }
2790 default:
2791 break;
2792 }
2793 }
2794 }
2795
2796 if (year == NO_NUMBER)
2797 year = KDateTime::currentLocalDate().year();
2798 if (month == NO_NUMBER)
2799 month = 1;
2800 QDate d = checkDate(year, month, (day > 0 ? day : 1), status); // convert date, and check for out-of-range
2801 if (!d.isValid())
2802 return QDateTime();
2803 if (dayOfWeek != NO_NUMBER && !status)
2804 {
2805 if (day == NO_NUMBER)
2806 {
2807 day = 1 + dayOfWeek - QDate(year, month, 1).dayOfWeek();
2808 if (day <= 0)
2809 day += 7;
2810 }
2811 else
2812 {
2813 if (QDate(year, month, day).dayOfWeek() != dayOfWeek)
2814 return QDateTime();
2815 }
2816 }
2817 if (day == NO_NUMBER)
2818 day = 1;
2819 dateOnly = (hour == NO_NUMBER && minute == NO_NUMBER && second == NO_NUMBER && millisec == NO_NUMBER);
2820 if (hour == NO_NUMBER)
2821 hour = 0;
2822 if (minute == NO_NUMBER)
2823 minute = 0;
2824 if (second == NO_NUMBER)
2825 second = 0;
2826 if (millisec == NO_NUMBER)
2827 millisec = 0;
2828 if (ampm != NO_NUMBER)
2829 {
2830 if (!hour || hour > 12)
2831 return QDateTime();
2832 if (ampm == 1 && hour == 12)
2833 hour = 0;
2834 else if (ampm == 2 && hour < 12)
2835 hour += 12;
2836 }
2837
2838 QDateTime dt(d, QTime(hour, minute, second, millisec), (tzoffset == 0 ? Qt::UTC : Qt::LocalTime));
2839
2840 utcOffset = (tzoffset == NO_NUMBER) ? 0 : tzoffset*60;
2841
2842 return dt;
2843}
2844
2845
2846/*
2847 * Find which day name matches the specified part of a string.
2848 * 'offset' is incremented by the length of the match.
2849 * Reply = day number (1 - 7), or <= 0 if no match.
2850 */
2851int matchDay(const QString &string, int &offset, KCalendarSystem *calendar)
2852{
2853 int dayOfWeek;
2854 QString part = string.mid(offset);
2855 if (part.isEmpty())
2856 return -1;
2857 if (calendar)
2858 {
2859 // Check for localised day name first
2860 for (dayOfWeek = 1; dayOfWeek <= 7; ++dayOfWeek)
2861 {
2862 QString name = calendar->weekDayName(dayOfWeek, KCalendarSystem::LongDayName);
2863 if (part.startsWith(name, Qt::CaseInsensitive))
2864 {
2865 offset += name.length();
2866 return dayOfWeek;
2867 }
2868 }
2869 for (dayOfWeek = 1; dayOfWeek <= 7; ++dayOfWeek)
2870 {
2871 QString name = calendar->weekDayName(dayOfWeek, KCalendarSystem::ShortDayName);
2872 if (part.startsWith(name, Qt::CaseInsensitive))
2873 {
2874 offset += name.length();
2875 return dayOfWeek;
2876 }
2877 }
2878 }
2879
2880 // Check for English day name
2881 dayOfWeek = findString(part, longDay, 7, offset);
2882 if (dayOfWeek < 0)
2883 dayOfWeek = findString(part, shortDay, 7, offset);
2884 return dayOfWeek + 1;
2885}
2886
2887/*
2888 * Find which month name matches the specified part of a string.
2889 * 'offset' is incremented by the length of the match.
2890 * Reply = month number (1 - 12), or <= 0 if no match.
2891 */
2892int matchMonth(const QString &string, int &offset, KCalendarSystem *calendar)
2893{
2894 int month;
2895 QString part = string.mid(offset);
2896 if (part.isEmpty())
2897 return -1;
2898 if (calendar)
2899 {
2900 // Check for localised month name first
2901 for (month = 1; month <= 12; ++month)
2902 {
2903 QString name = calendar->monthName(month, 2000, KCalendarSystem::LongName);
2904 if (part.startsWith(name, Qt::CaseInsensitive))
2905 {
2906 offset += name.length();
2907 return month;
2908 }
2909 }
2910 for (month = 1; month <= 12; ++month)
2911 {
2912 QString name = calendar->monthName(month, 2000, KCalendarSystem::ShortName);
2913 if (part.startsWith(name, Qt::CaseInsensitive))
2914 {
2915 offset += name.length();
2916 return month;
2917 }
2918 }
2919 }
2920 // Check for English month name
2921 month = findString(part, longMonth, 12, offset);
2922 if (month < 0)
2923 month = findString(part, shortMonth, 12, offset);
2924 return month + 1;
2925}
2926
2927/*
2928 * Read a UTC offset from the input string.
2929 */
2930bool getUTCOffset(const QString &string, int &offset, bool colon, int &result)
2931{
2932 int sign;
2933 int len = string.length();
2934 if (offset >= len)
2935 return false;
2936 switch (string[offset++].unicode())
2937 {
2938 case '+':
2939 sign = 1;
2940 break;
2941 case '-':
2942 sign = -1;
2943 break;
2944 default:
2945 return false;
2946 }
2947 int tzhour = NO_NUMBER;
2948 int tzmin = NO_NUMBER;
2949 if (!getNumber(string, offset, 2, 2, 0, 99, tzhour))
2950 return false;
2951 if (colon)
2952 {
2953 if (offset >= len || string[offset++] != QLatin1Char(':'))
2954 return false;
2955 }
2956 if (offset >= len || !string[offset].isDigit())
2957 tzmin = 0;
2958 else
2959 {
2960 if (!getNumber(string, offset, 2, 2, 0, 59, tzmin))
2961 return false;
2962 }
2963 tzmin += tzhour * 60;
2964 if (result != NO_NUMBER && result != tzmin)
2965 return false;
2966 result = sign * tzmin;
2967 return true;
2968}
2969
2970/*
2971 * Read an am/pm indicator from the input string.
2972 * 'offset' is incremented by the length of the match.
2973 * Reply = 1 (am), 2 (pm), or 0 if no match.
2974 */
2975int getAmPm(const QString &string, int &offset, KLocale *locale)
2976{
2977 QString part = string.mid(offset);
2978 int ap = 0;
2979 int n = 2;
2980 if (locale)
2981 {
2982 // Check localised form first
2983 QString aps = ki18n("am").toString(locale);
2984 if (part.startsWith(aps, Qt::CaseInsensitive))
2985 {
2986 ap = 1;
2987 n = aps.length();
2988 }
2989 else
2990 {
2991 aps = ki18n("pm").toString(locale);
2992 if (part.startsWith(aps, Qt::CaseInsensitive))
2993 {
2994 ap = 2;
2995 n = aps.length();
2996 }
2997 }
2998 }
2999 if (!ap)
3000 {
3001 if (part.startsWith(QLatin1String("am"), Qt::CaseInsensitive))
3002 ap = 1;
3003 else if (part.startsWith(QLatin1String("pm"), Qt::CaseInsensitive))
3004 ap = 2;
3005 }
3006 if (ap)
3007 offset += n;
3008 return ap;
3009}
3010
3011/* Convert part of 'string' to a number.
3012 * If converted number differs from any current value in 'result', the function fails.
3013 * Reply = true if successful.
3014 */
3015bool getNumber(const QString& string, int& offset, int mindigits, int maxdigits, int minval, int maxval, int& result)
3016{
3017 int end = string.size();
3018 bool neg = false;
3019 if (minval == NO_NUMBER && offset < end && string[offset] == QLatin1Char('-'))
3020 {
3021 neg = true;
3022 ++offset;
3023 }
3024 if (offset + maxdigits > end)
3025 maxdigits = end - offset;
3026 int ndigits;
3027 for (ndigits = 0; ndigits < maxdigits && string[offset + ndigits].isDigit(); ++ndigits) ;
3028 if (ndigits < mindigits)
3029 return false;
3030 bool ok;
3031 int n = string.mid(offset, ndigits).toInt(&ok);
3032 if (neg)
3033 n = -n;
3034 if (!ok || (result != NO_NUMBER && n != result) || (minval != NO_NUMBER && n < minval) || (n > maxval && maxval >= 0))
3035 return false;
3036 result = n;
3037 offset += ndigits;
3038 return true;
3039}
3040
3041int findString_internal(const QString &string, const char *array, int count, int &offset, int disp)
3042{
3043 for (int i = 0; i < count; ++i)
3044 {
3045 if (string.startsWith(QLatin1String(array + i * disp), Qt::CaseInsensitive))
3046 {
3047 offset += qstrlen(array + i * disp);
3048 return i;
3049 }
3050 }
3051 return -1;
3052}
3053
3054/*
3055 * Return the QDate for a given year, month and day.
3056 * If in error, check whether the reason is that the year is out of range.
3057 * If so, return a valid (but wrong) date but with 'status' set to the
3058 * appropriate error code. If no error, 'status' is set to stValid.
3059 */
3060QDate checkDate(int year, int month, int day, Status &status)
3061{
3062 status = stValid;
3063 QDate qdate(year, month, day);
3064 if (qdate.isValid())
3065 return qdate;
3066
3067 // Invalid date - check whether it's simply out of range
3068 if (year < MIN_YEAR)
3069 {
3070 bool leap = (year % 4 == 0) && (year % 100 || year % 400 == 0);
3071 qdate.setYMD((leap ? 2000 : 2001), month, day);
3072 if (qdate.isValid())
3073 status = stTooEarly;
3074 }
3075 return qdate;
3076}
3077
KCalendarSystemQDate
Definition: kcalendarsystemqdate_p.h:42
KCalendarSystemQDate::weekDayName
virtual QString weekDayName(int weekDay, WeekDayNameFormat format=LongDayName) const
Gets specific calendar type week day name.
Definition: kcalendarsystemqdate.cpp:509
KCalendarSystemQDate::monthName
virtual QString monthName(int month, int year, MonthNameFormat format=LongName) const
Gets specific calendar type month name for a given month number If an invalid month is specified,...
Definition: kcalendarsystemqdate.cpp:499
KCalendarSystem
KCalendarSystem abstract base class, provides support for local Calendar Systems in KDE.
Definition: kcalendarsystem.h:41
KCalendarSystem::monthName
virtual QString monthName(int month, int year, MonthNameFormat format=LongName) const =0
Gets specific calendar type month name for a given month number If an invalid month is specified,...
Definition: kcalendarsystem.cpp:1842
KCalendarSystem::ShortName
@ ShortName
Short name format, e.g.
Definition: kcalendarsystem.h:56
KCalendarSystem::LongName
@ LongName
Long name format, e.g.
Definition: kcalendarsystem.h:57
KCalendarSystem::ShortDayName
@ ShortDayName
Short name format, e.g.
Definition: kcalendarsystem.h:67
KCalendarSystem::LongDayName
@ LongDayName
Long name format, e.g.
Definition: kcalendarsystem.h:68
KCalendarSystem::weekDayName
virtual QString weekDayName(int weekDay, WeekDayNameFormat format=LongDayName) const =0
Gets specific calendar type week day name.
Definition: kcalendarsystem.cpp:1881
KDateTime::Spec
The full time specification of a KDateTime instance.
Definition: kdatetime.h:224
KDateTime::Spec::ClockTime
static Spec ClockTime()
The ClockTime time specification.
Definition: kdatetime.cpp:211
KDateTime::Spec::timeZone
KTimeZone timeZone() const
Returns the time zone for the date/time, according to the time specification type as follows:
Definition: kdatetime.cpp:193
KDateTime::Spec::isLocalZone
bool isLocalZone() const
Returns whether the time specification is the current local system time zone.
Definition: kdatetime.cpp:216
KDateTime::Spec::type
SpecType type() const
Returns the time specification type, i.e.
Definition: kdatetime.cpp:214
KDateTime::Spec::LocalZone
static Spec LocalZone()
Returns a local time zone time specification.
Definition: kdatetime.cpp:212
KDateTime::Spec::Spec
Spec()
Constructs an invalid time specification.
Definition: kdatetime.cpp:116
KDateTime::Spec::isValid
bool isValid() const
Returns whether the time specification is valid.
Definition: kdatetime.cpp:215
KDateTime::Spec::OffsetFromUTC
static Spec OffsetFromUTC(int utcOffset)
Returns a UTC offset time specification.
Definition: kdatetime.cpp:213
KDateTime::Spec::isOffsetFromUtc
bool isOffsetFromUtc() const
Returns whether the time specification is a local time at a fixed offset from UTC.
Definition: kdatetime.cpp:218
KDateTime::Spec::setType
void setType(SpecType type, int utcOffset=0)
Initialises the time specification.
Definition: kdatetime.cpp:158
KDateTime::Spec::isUtc
bool isUtc() const
Returns whether the time specification is a UTC time.
Definition: kdatetime.cpp:202
KDateTime::Spec::utcOffset
int utcOffset() const
Returns the UTC offset associated with the time specification.
Definition: kdatetime.cpp:219
KDateTime::Spec::equivalentTo
bool equivalentTo(const Spec &other) const
Checks whether this instance is equivalent to another.
Definition: kdatetime.cpp:230
KDateTime::Spec::operator=
Spec & operator=(const Spec &spec)
Assignment operator.
Definition: kdatetime.cpp:145
KDateTime::Spec::operator==
bool operator==(const Spec &other) const
Comparison operator.
Definition: kdatetime.cpp:221
KDateTime::Spec::isClockTime
bool isClockTime() const
Returns whether the time specification is a local clock time.
Definition: kdatetime.cpp:217
KDateTime::Spec::UTC
static Spec UTC()
The UTC time specification.
Definition: kdatetime.cpp:210
KDateTime::Spec::~Spec
~Spec()
Destructor.
Definition: kdatetime.cpp:140
KDateTime
A class representing a date and time with an associated time zone.
Definition: kdatetime.h:172
KDateTime::currentUtcDateTime
static KDateTime currentUtcDateTime()
Returns the current date and time, as reported by the system clock, expressed in UTC.
Definition: kdatetime.cpp:1240
KDateTime::time
QTime time() const
Returns the time part of the date/time.
Definition: kdatetime.cpp:839
KDateTime::utcOffset
int utcOffset() const
Returns the UTC offset associated with the date/time.
Definition: kdatetime.cpp:858
KDateTime::setTimeSpec
void setTimeSpec(const Spec &spec)
Changes the time specification of the instance.
Definition: kdatetime.cpp:1050
KDateTime::currentLocalTime
static QTime currentLocalTime()
Returns the current time of day in the local time zone, as reported by the system clock.
Definition: kdatetime.cpp:1285
KDateTime::currentLocalDate
static QDate currentLocalDate()
Returns the current date in the local time zone, as reported by the system clock.
Definition: kdatetime.cpp:1280
KDateTime::setTime
void setTime(const QTime &time)
Sets the time part of the date/time.
Definition: kdatetime.cpp:1030
KDateTime::isDateOnly
bool isDateOnly() const
Returns whether the instance represents a date/time or a date-only value.
Definition: kdatetime.cpp:832
KDateTime::isUtc
bool isUtc() const
Returns whether the date/time is a UTC time.
Definition: kdatetime.cpp:835
KDateTime::realCurrentLocalDateTime
static KDateTime realCurrentLocalDateTime()
Return the real (not simulated) system time.
Definition: kdatetime.cpp:2441
KDateTime::setSimulatedSystemTime
static void setSimulatedSystemTime(const KDateTime &newTime)
Set an adjustment to be applied when fetching the current system time.
Definition: kdatetime.cpp:2424
KDateTime::toTime_t
uint toTime_t() const
Converts the time to a UTC time, measured in seconds since 00:00:00 UTC 1st January 1970 (as returned...
Definition: kdatetime.cpp:1001
KDateTime::timeType
SpecType timeType() const
Returns the time specification type of the date/time, i.e.
Definition: kdatetime.cpp:843
KDateTime::Comparison
Comparison
How this KDateTime compares with another.
Definition: kdatetime.h:479
KDateTime::AtEnd
@ AtEnd
This KDateTime starts after the start of the other, and ends at the same time as the other,...
Definition: kdatetime.h:491
KDateTime::Equal
@ Equal
Simultaneous, i.e.
Definition: kdatetime.h:498
KDateTime::AtStart
@ AtStart
This KDateTime starts at the same time as the other, and ends before the end of the other,...
Definition: kdatetime.h:483
KDateTime::Outside
@ Outside
This KDateTime starts before the start of the other, and ends after the end of the other,...
Definition: kdatetime.h:501
KDateTime::After
@ After
This KDateTime is strictly later than the other, i.e.
Definition: kdatetime.h:495
KDateTime::Inside
@ Inside
This KDateTime starts after the start of the other, and ends before the end of the other,...
Definition: kdatetime.h:487
KDateTime::Before
@ Before
This KDateTime is strictly earlier than the other, i.e.
Definition: kdatetime.h:480
KDateTime::isOffsetFromUtc
bool isOffsetFromUtc() const
Returns whether the date/time is a local time at a fixed offset from UTC.
Definition: kdatetime.cpp:836
KDateTime::fromString
static KDateTime fromString(const QString &string, TimeFormat format=ISODate, bool *negZero=0)
Returns the KDateTime represented by string, using the format given.
Definition: kdatetime.cpp:1801
KDateTime::KDateTime
KDateTime()
Constructs an invalid date/time.
Definition: kdatetime.cpp:775
KDateTime::detach
void detach()
Create a separate copy of this instance's data if it is implicitly shared with another instance.
Definition: kdatetime.cpp:828
KDateTime::date
QDate date() const
Returns the date part of the date/time.
Definition: kdatetime.cpp:838
KDateTime::addMonths
KDateTime addMonths(int months) const
Returns a date/time months months later than the stored date/time.
Definition: kdatetime.cpp:1141
KDateTime::isNull
bool isNull() const
Returns whether the date/time is null.
Definition: kdatetime.cpp:829
KDateTime::operator=
KDateTime & operator=(const KDateTime &other)
Definition: kdatetime.cpp:821
KDateTime::isLocalZone
bool isLocalZone() const
Returns whether the time zone for the date/time is the current local system time zone.
Definition: kdatetime.cpp:833
KDateTime::setDateTime
void setDateTime(const QDateTime &dt)
Sets the date/time part of the instance, leaving the time specification unaffected.
Definition: kdatetime.cpp:1035
KDateTime::toString
QString toString(const QString &format) const
Returns the date/time as a string.
Definition: kdatetime.cpp:1434
KDateTime::operator==
bool operator==(const KDateTime &other) const
Check whether this date/time is simultaneous with another.
Definition: kdatetime.cpp:1360
KDateTime::~KDateTime
~KDateTime()
Definition: kdatetime.cpp:817
KDateTime::outOfRange
bool outOfRange() const
Checks whether the date/time returned by the last call to fromString() was invalid because an otherwi...
Definition: kdatetime.cpp:831
KDateTime::toClockTime
KDateTime toClockTime() const
Returns the time converted to the local clock time.
Definition: kdatetime.cpp:953
KDateTime::toOffsetFromUtc
KDateTime toOffsetFromUtc() const
Returns the time expressed as an offset from UTC, using the UTC offset associated with this instance'...
Definition: kdatetime.cpp:885
KDateTime::addSecs
KDateTime addSecs(qint64 secs) const
Returns a date/time secs seconds later than the stored date/time.
Definition: kdatetime.cpp:1107
KDateTime::isClockTime
bool isClockTime() const
Returns whether the date/time is a local clock time.
Definition: kdatetime.cpp:834
KDateTime::setSecondOccurrence
void setSecondOccurrence(bool second)
Sets whether the date/time is the second occurrence of this time.
Definition: kdatetime.cpp:1055
KDateTime::toZone
KDateTime toZone(const KTimeZone &zone) const
Returns the time converted to a specified time zone.
Definition: kdatetime.cpp:966
KDateTime::secsTo
int secsTo(const KDateTime &other) const
Returns the number of seconds from this date/time to the other date/time.
Definition: kdatetime.cpp:1159
KDateTime::toTimeSpec
KDateTime toTimeSpec(const Spec &spec) const
Returns the time converted to a new time specification.
Definition: kdatetime.cpp:984
KDateTime::currentLocalDateTime
static KDateTime currentLocalDateTime()
Returns the current date and time, as reported by the system clock, expressed in the local system tim...
Definition: kdatetime.cpp:1231
KDateTime::timeZone
KTimeZone timeZone() const
Returns the time zone for the date/time.
Definition: kdatetime.cpp:845
KDateTime::dateTime
QDateTime dateTime() const
Returns the date/time component of the instance, ignoring the time zone.
Definition: kdatetime.cpp:840
KDateTime::operator<
bool operator<(const KDateTime &other) const
Check whether this date/time is earlier than another.
Definition: kdatetime.cpp:1392
KDateTime::addYears
KDateTime addYears(int years) const
Returns a date/time years years later than the stored date/time.
Definition: kdatetime.cpp:1150
KDateTime::toUtc
KDateTime toUtc() const
Returns the time converted to UTC.
Definition: kdatetime.cpp:871
KDateTime::isSecondOccurrence
bool isSecondOccurrence() const
Returns whether the date/time is the second occurrence of this time.
Definition: kdatetime.cpp:837
KDateTime::setDate
void setDate(const QDate &date)
Sets the date part of the date/time.
Definition: kdatetime.cpp:1025
KDateTime::addDays
KDateTime addDays(int days) const
Returns a date/time days days later than the stored date/time.
Definition: kdatetime.cpp:1132
KDateTime::isValid
bool isValid() const
Returns whether the date/time is valid.
Definition: kdatetime.cpp:830
KDateTime::TimeFormat
TimeFormat
Format for strings representing date/time values.
Definition: kdatetime.h:420
KDateTime::LocalDate
@ LocalDate
Same format as Qt::LocalDate (i.e.
Definition: kdatetime.h:449
KDateTime::QtTextDate
@ QtTextDate
Same format as Qt::TextDate (i.e.
Definition: kdatetime.h:445
KDateTime::ISODate
@ ISODate
ISO 8601 format, i.e.
Definition: kdatetime.h:421
KDateTime::RFC3339Date
@ RFC3339Date
RFC 3339 format, i.e.
Definition: kdatetime.h:453
KDateTime::RFCDate
@ RFCDate
RFC 2822 format, i.e.
Definition: kdatetime.h:435
KDateTime::RFCDateDay
@ RFCDateDay
RFC 2822 format including day of the week, i.e.
Definition: kdatetime.h:442
KDateTime::addMSecs
KDateTime addMSecs(qint64 msecs) const
Returns a date/time msecs milliseconds later than the stored date/time.
Definition: kdatetime.cpp:1070
KDateTime::SpecType
SpecType
The time specification type of a KDateTime instance.
Definition: kdatetime.h:182
KDateTime::Invalid
@ Invalid
an invalid time specification.
Definition: kdatetime.h:183
KDateTime::UTC
@ UTC
a UTC time.
Definition: kdatetime.h:184
KDateTime::OffsetFromUTC
@ OffsetFromUTC
a local time which has a fixed offset from UTC.
Definition: kdatetime.h:185
KDateTime::LocalZone
@ LocalZone
a time in the current system time zone.
Definition: kdatetime.h:191
KDateTime::ClockTime
@ ClockTime
a clock time which ignores time zones and simply uses whatever the local system clock says the time i...
Definition: kdatetime.h:203
KDateTime::TimeZone
@ TimeZone
a time in a specified time zone.
Definition: kdatetime.h:186
KDateTime::timeSpec
Spec timeSpec() const
Returns the time specification of the date/time, i.e.
Definition: kdatetime.cpp:842
KDateTime::setDateOnly
void setDateOnly(bool dateOnly)
Sets the instance either to being a date and time value, or a date-only value.
Definition: kdatetime.cpp:1020
KDateTime::setTime_t
void setTime_t(qint64 seconds)
Sets the time to a UTC time, specified as seconds since 00:00:00 UTC 1st January 1970 (as returned by...
Definition: kdatetime.cpp:1009
KDateTime::compare
Comparison compare(const KDateTime &other) const
Compare this instance with another to determine whether they are simultaneous, earlier or later,...
Definition: kdatetime.cpp:1290
KDateTime::setFromStringDefault
static void setFromStringDefault(const Spec &spec)
Sets the default time specification for use by fromString() when no time zone or UTC offset is found ...
Definition: kdatetime.cpp:2419
KDateTime::toLocalZone
KDateTime toLocalZone() const
Returns the time converted to the current local system time zone.
Definition: kdatetime.cpp:927
KDateTime::currentDateTime
static KDateTime currentDateTime(const Spec &spec)
Returns the current date and time, as reported by the system clock, expressed in a given time specifi...
Definition: kdatetime.cpp:1262
KDateTime::daysTo
int daysTo(const KDateTime &other) const
Calculates the number of days from this date/time to the other date/time.
Definition: kdatetime.cpp:1195
KDateTime::secsTo_long
qint64 secsTo_long(const KDateTime &other) const
Returns the number of seconds from this date/time to the other date/time.
Definition: kdatetime.cpp:1164
KLocale
KLocale provides support for country specific stuff like the national language.
Definition: klocale.h:70
KLocale::decimalSymbol
QString decimalSymbol() const
Returns what a decimal point should look like ("." or "," etc.) according to the current locale or us...
Definition: klocale.cpp:252
KLocalizedString::toString
QString toString() const
Finalizes the translation, creates QString with placeholders substituted.
Definition: klocalizedstring.cpp:192
KSystemTimeZones::local
static KTimeZone local()
Returns the current local system time zone.
Definition: ksystemtimezone.cpp:195
KSystemTimeZones::setLocalZone
static void setLocalZone(const KTimeZone &tz)
Set or clear the simulated local system time zone.
Definition: ksystemtimezone.cpp:211
KSystemTimeZones::isSimulated
static bool isSimulated()
Check whether there is a simulated local system time zone.
Definition: ksystemtimezone.cpp:219
KSystemTimeZones::realLocalZone
static KTimeZone realLocalZone()
Return the real (not simulated) local system time zone.
Definition: ksystemtimezone.cpp:205
KSystemTimeZones::zone
static KTimeZone zone(const QString &name)
Returns the time zone with the given name.
Definition: ksystemtimezone.cpp:255
KTimeZone
Base class representing a time zone.
Definition: ktimezone.h:417
KTimeZone::InvalidOffset
static const int InvalidOffset
Indicates an invalid UTC offset.
Definition: ktimezone.h:1073
KTimeZone::offsetAtZoneTime
virtual int offsetAtZoneTime(const QDateTime &zoneDateTime, int *secondOffset=0) const
Returns the offset of this time zone to UTC at the given local date/time.
Definition: ktimezone.cpp:865
KTimeZone::name
QString name() const
Returns the name of the time zone.
Definition: ktimezone.cpp:669
KTimeZone::isValid
bool isValid() const
Checks whether the instance is valid.
Definition: ktimezone.cpp:644
KTimeZone::abbreviation
QByteArray abbreviation(const QDateTime &utcDateTime) const
Returns the time zone abbreviation current at a specified time.
Definition: ktimezone.cpp:681
KTimeZone::toZoneTime
QDateTime toZoneTime(const QDateTime &utcDateTime, bool *secondOccurrence=0) const
Converts a UTC date/time into local time in this time zone.
Definition: ktimezone.cpp:808
KTimeZone::toUtc
QDateTime toUtc(const QDateTime &zoneDateTime) const
Converts a date/time, which is interpreted as local time in this time zone, into UTC.
Definition: ktimezone.cpp:796
KTimeZone::utc
static KTimeZone utc()
Returns a standard UTC time zone, with name "UTC".
Definition: ktimezone.cpp:911
KTimeZones
The KTimeZones class represents a time zone database which consists of a collection of individual tim...
Definition: ktimezone.h:309
KTimeZones::zone
KTimeZone zone(const QString &name) const
Returns the time zone with the given name.
Definition: ktimezone.cpp:118
KTimeZones::zones
const ZoneMap zones() const
Returns all the time zones defined in this collection.
Definition: ktimezone.cpp:67
KTimeZones::ZoneMap
QMap< QString, KTimeZone > ZoneMap
Map of KTimeZone instances, indexed by time zone name.
Definition: ktimezone.h:323
QDateTime
QList
Definition: kaboutdata.h:33
QStringList
QString
qint64
isalpha
#define isalpha(c)
Definition: ctype_test_p.h:85
K_GLOBAL_STATIC_WITH_ARGS
#define K_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: kglobal.h:255
kcalendarsystemqdate_p.h
operator<<
QDebug operator<<(QDebug dbg, const KEntryKey &key)
Definition: kconfigdata.cpp:25
fromStr
static QDateTime fromStr(const QString &string, const QString &format, int &utcOffset, QString &zoneName, QByteArray &zoneAbbrev, bool &dateOnly, Status &)
Definition: kdatetime.cpp:2477
longDay
static const char longDay[][10]
Definition: kdatetime.cpp:57
operator>>
QDataStream & operator>>(QDataStream &s, KDateTime::Spec &spec)
Read a KDateTime::Spec object into spec from in, in binary format.
Definition: kdatetime.cpp:274
findString_internal
static int findString_internal(const QString &string, const char *ptr, int count, int &offset, int disp)
Definition: kdatetime.cpp:3041
Status
Status
Definition: kdatetime.cpp:76
stTooEarly
@ stTooEarly
Definition: kdatetime.cpp:78
stValid
@ stValid
Definition: kdatetime.cpp:77
matchMonth
static int matchMonth(const QString &string, int &offset, KCalendarSystem *)
Definition: kdatetime.cpp:2892
NO_NUMBER
static const int NO_NUMBER
Definition: kdatetime.cpp:96
matchDay
static int matchDay(const QString &string, int &offset, KCalendarSystem *)
Definition: kdatetime.cpp:2851
shortDay
static const char shortDay[][4]
Definition: kdatetime.cpp:52
MIN_YEAR
static const int MIN_YEAR
Definition: kdatetime.cpp:95
shortMonth
static const char shortMonth[][4]
Definition: kdatetime.cpp:62
checkDate
static QDate checkDate(int year, int month, int day, Status &)
Definition: kdatetime.cpp:3060
getUTCOffset
static bool getUTCOffset(const QString &string, int &offset, bool colon, int &result)
Definition: kdatetime.cpp:2930
getNumber
static bool getNumber(const QString &string, int &offset, int mindigits, int maxdigits, int minval, int maxval, int &result)
Definition: kdatetime.cpp:3015
operator<<
QDataStream & operator<<(QDataStream &s, const KDateTime::Spec &spec)
Write spec to the datastream out, in binary format.
Definition: kdatetime.cpp:248
longMonth
static const char longMonth[][10]
Definition: kdatetime.cpp:67
findString
static int findString(const QString &string, const char array[][disp], int count, int &offset)
Definition: kdatetime.cpp:91
getAmPm
static int getAmPm(const QString &string, int &offset, KLocale *)
Definition: kdatetime.cpp:2975
kdatetime.h
Date/times with associated time zone.
kdebug.h
kglobal.h
klocale.h
ki18n
KLocalizedString ki18n(const char *msg)
Creates localized string from a given message.
Definition: klocalizedstring.cpp:924
indexOf
static int indexOf(const QByteArray &that, const QByteArray &ba)
Definition: kmimemagicrule.cpp:60
ksystemtimezone.h
System time zone functions.
KGlobal::locale
KLocale * locale()
Returns the global locale object.
Definition: kglobal.cpp:170
KServiceTypeProfile::clearCache
void clearCache()
Clear all cached information.
Definition: kservicetypeprofile.cpp:103
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDECore

Skip menu "KDECore"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal