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

KDECore

  • sources
  • kde-4.14
  • kdelibs
  • 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 
52 static const char shortDay[][4] = {
53  "Mon", "Tue", "Wed",
54  "Thu", "Fri", "Sat",
55  "Sun"
56 };
57 static const char longDay[][10] = {
58  "Monday", "Tuesday", "Wednesday",
59  "Thursday", "Friday", "Saturday",
60  "Sunday"
61 };
62 static const char shortMonth[][4] = {
63  "Jan", "Feb", "Mar", "Apr",
64  "May", "Jun", "Jul", "Aug",
65  "Sep", "Oct", "Nov", "Dec"
66 };
67 static 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()
76 enum Status {
77  stValid = 0, // either valid, or really invalid
78  stTooEarly // invalid (valid date before QDate range)
79 };
80 
81 
82 static QDateTime fromStr(const QString& string, const QString& format, int& utcOffset,
83  QString& zoneName, QByteArray& zoneAbbrev, bool& dateOnly, Status&);
84 static int matchDay(const QString &string, int &offset, KCalendarSystem*);
85 static int matchMonth(const QString &string, int &offset, KCalendarSystem*);
86 static bool getUTCOffset(const QString &string, int &offset, bool colon, int &result);
87 static int getAmPm(const QString &string, int &offset, KLocale*);
88 static bool getNumber(const QString &string, int &offset, int mindigits, int maxdigits, int minval, int maxval, int &result);
89 static int findString_internal(const QString &string, const char *ptr, int count, int &offset, int disp);
90 template<int disp> static inline
91 int findString(const QString &string, const char array[][disp], int count, int &offset)
92 { return findString_internal(string, array[0], count, offset, disp); }
93 static QDate checkDate(int year, int month, int day, Status&);
94 
95 static const int MIN_YEAR = -4712; // minimum year which QDate allows
96 static const int NO_NUMBER = 0x8000000; // indicates that no number is present in string conversion functions
97 
98 #ifdef COMPILING_TESTS
99 KDECORE_EXPORT int KDateTime_utcCacheHit = 0;
100 KDECORE_EXPORT int KDateTime_zoneCacheHit = 0;
101 #endif
102 
103 /*----------------------------------------------------------------------------*/
104 
105 class 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 
116 KDateTime::Spec::Spec()
117  : d(new KDateTimeSpecPrivate)
118 {
119  d->type = KDateTime::Invalid;
120 }
121 
122 KDateTime::Spec::Spec(const KTimeZone &tz)
123  : d(new KDateTimeSpecPrivate())
124 {
125  setType(tz);
126 }
127 
128 KDateTime::Spec::Spec(SpecType type, int utcOffset)
129  : d(new KDateTimeSpecPrivate())
130 {
131  setType(type, utcOffset);
132 }
133 
134 KDateTime::Spec::Spec(const Spec& spec)
135  : d(new KDateTimeSpecPrivate())
136 {
137  operator=(spec);
138 }
139 
140 KDateTime::Spec::~Spec()
141 {
142  delete d;
143 }
144 
145 KDateTime::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 
158 void 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 
180 void 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 
193 KTimeZone 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 
202 bool 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 
210 KDateTime::Spec KDateTime::Spec::UTC() { return Spec(KDateTime::UTC); }
211 KDateTime::Spec KDateTime::Spec::ClockTime() { return Spec(KDateTime::ClockTime); }
212 KDateTime::Spec KDateTime::Spec::LocalZone() { return Spec(KDateTime::LocalZone); }
213 KDateTime::Spec KDateTime::Spec::OffsetFromUTC(int utcOffset) { return Spec(KDateTime::OffsetFromUTC, utcOffset); }
214 KDateTime::SpecType KDateTime::Spec::type() const { return d->type; }
215 bool KDateTime::Spec::isValid() const { return d->type != KDateTime::Invalid; }
216 bool KDateTime::Spec::isLocalZone() const { return d->type == KDateTime::TimeZone && d->tz == KSystemTimeZones::local(); }
217 bool KDateTime::Spec::isClockTime() const { return d->type == KDateTime::ClockTime; }
218 bool KDateTime::Spec::isOffsetFromUtc() const { return d->type == KDateTime::OffsetFromUTC; }
219 int KDateTime::Spec::utcOffset() const { return d->type == KDateTime::OffsetFromUTC ? d->utcOffset : 0; }
220 
221 bool 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 
230 bool 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 
248 QDataStream & 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 
274 QDataStream & 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 
313 K_GLOBAL_STATIC_WITH_ARGS(KDateTime::Spec, s_fromStringDefault, (KDateTime::ClockTime))
314 
315 class 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  */
442 private:
443  QDateTime mDt;
444 public:
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;
452 private:
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;
458 public:
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
464 private:
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 
470 QTime KDateTimePrivate::sod(0,0,0);
471 #ifndef NDEBUG
472 qint64 KDateTimePrivate::currentDateTimeOffset = 0;
473 #endif
474 
475 KDateTime::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 
483 void 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 
534 bool 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 
543 void 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. */
559 void 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  */
592 int 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  */
633 QDateTime 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  */
712 QDateTime 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  */
741 void 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 /*----------------------------------------------------------------------------*/
773 K_GLOBAL_STATIC_WITH_ARGS(QSharedDataPointer<KDateTimePrivate>, emptyDateTimePrivate, (new KDateTimePrivate))
774 
775 KDateTime::KDateTime()
776  : d(*emptyDateTimePrivate)
777 {
778 }
779 
780 KDateTime::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 
787 KDateTime::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 
794 KDateTime::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 
807 KDateTime::KDateTime(const QDateTime &dt)
808  : d(new KDateTimePrivate(dt, (dt.timeSpec() == Qt::LocalTime ? Spec(LocalZone) : Spec(UTC))))
809 {
810 }
811 
812 KDateTime::KDateTime(const KDateTime &other)
813  : d(other.d)
814 {
815 }
816 
817 KDateTime::~KDateTime()
818 {
819 }
820 
821 KDateTime &KDateTime::operator=(const KDateTime &other)
822 {
823  if (&other != this)
824  d = other.d;
825  return *this;
826 }
827 
828 void KDateTime::detach() { d.detach(); }
829 bool KDateTime::isNull() const { return d->dt().isNull(); }
830 bool KDateTime::isValid() const { return d->specType != Invalid && d->dt().isValid(); }
831 bool KDateTime::outOfRange() const { return d->status == stTooEarly; }
832 bool KDateTime::isDateOnly() const { return d->dateOnly(); }
833 bool KDateTime::isLocalZone() const { return d->specType == TimeZone && d->specZone == KSystemTimeZones::local(); }
834 bool KDateTime::isClockTime() const { return d->specType == ClockTime; }
835 bool KDateTime::isUtc() const { return d->specType == UTC || (d->specType == OffsetFromUTC && d->specUtcOffset == 0); }
836 bool KDateTime::isOffsetFromUtc() const { return d->specType == OffsetFromUTC; }
837 bool KDateTime::isSecondOccurrence() const { return d->specType == TimeZone && d->secondOccurrence(); }
838 QDate KDateTime::date() const { return d->date(); }
839 QTime KDateTime::time() const { return d->dt().time(); }
840 QDateTime KDateTime::dateTime() const { return d->dt(); }
841 
842 KDateTime::Spec KDateTime::timeSpec() const { return d->spec(); }
843 KDateTime::SpecType KDateTime::timeType() const { return d->specType; }
844 
845 KTimeZone 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 
858 int 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 
871 KDateTime 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 
885 KDateTime 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 
916 KDateTime 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 
927 KDateTime 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 
953 KDateTime 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 
966 KDateTime 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 
979 KDateTime KDateTime::toTimeSpec(const KDateTime &dt) const
980 {
981  return toTimeSpec(dt.timeSpec());
982 }
983 
984 KDateTime 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 
1001 uint 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 
1009 void 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 
1020 void KDateTime::setDateOnly(bool dateOnly)
1021 {
1022  d->setDateOnly(dateOnly);
1023 }
1024 
1025 void KDateTime::setDate(const QDate &date)
1026 {
1027  d->setDate(date);
1028 }
1029 
1030 void KDateTime::setTime(const QTime &time)
1031 {
1032  d->setTime(time);
1033 }
1034 
1035 void 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 
1050 void KDateTime::setTimeSpec(const Spec &other)
1051 {
1052  d->setSpec(other);
1053 }
1054 
1055 void 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 
1070 KDateTime 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 
1107 KDateTime 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 
1132 KDateTime 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 
1141 KDateTime 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 
1150 KDateTime 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 
1159 int KDateTime::secsTo(const KDateTime &t2) const
1160 {
1161  return static_cast<int>(secsTo_long(t2));
1162 }
1163 
1164 qint64 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 
1195 int 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 
1231 KDateTime 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 
1240 KDateTime 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 
1262 KDateTime 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 
1280 QDate KDateTime::currentLocalDate()
1281 {
1282  return currentLocalDateTime().date();
1283 }
1284 
1285 QTime KDateTime::currentLocalTime()
1286 {
1287  return currentLocalDateTime().time();
1288 }
1289 
1290 KDateTime::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 
1360 bool 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 
1392 bool 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 
1434 QString 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 
1677 QString 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 
1801 KDateTime 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 
2273 KDateTime 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 
2419 void KDateTime::setFromStringDefault(const Spec &spec)
2420 {
2421  KDateTimePrivate::fromStringDefault() = spec;
2422 }
2423 
2424 void 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 
2441 KDateTime 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 
2450 QDataStream & 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 
2456 QDataStream & 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  */
2477 QDateTime 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  */
2851 int 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  */
2892 int 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  */
2930 bool 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  */
2975 int 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  */
3015 bool 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 
3041 int 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  */
3060 QDate 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 
operator<<
QDataStream & operator<<(QDataStream &s, const KDateTime::Spec &spec)
Write spec to the datastream out, in binary format.
Definition: kdatetime.cpp:248
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::RFCDateDay
RFC 2822 format including day of the week, i.e.
Definition: kdatetime.h:442
QDate::daysTo
int daysTo(const QDate &d) const
KSystemTimeZones::isSimulated
static bool isSimulated()
Check whether there is a simulated local system time zone.
Definition: ksystemtimezone.cpp:219
QTime::minute
int minute() const
QString::indexOf
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
KDateTime::LocalZone
a time in the current system time zone.
Definition: kdatetime.h:191
qint64
KDateTime::SpecType
SpecType
The time specification type of a KDateTime instance.
Definition: kdatetime.h:181
KDateTime::toTimeSpec
KDateTime toTimeSpec(const Spec &spec) const
Returns the time converted to a new time specification.
Definition: kdatetime.cpp:984
KDateTime::Spec::ClockTime
static Spec ClockTime()
The ClockTime time specification.
Definition: kdatetime.cpp:211
QDate::addYears
QDate addYears(int nyears) const
QString::toUpper
QString toUpper() const
KDateTime::KDateTime
KDateTime()
Constructs an invalid date/time.
Definition: kdatetime.cpp:775
KDateTime::timeZone
KTimeZone timeZone() const
Returns the time zone for the date/time.
Definition: kdatetime.cpp:845
QByteArray::clear
void clear()
KDateTime::Equal
Simultaneous, i.e.
Definition: kdatetime.h:498
QString::truncate
void truncate(int position)
KDateTime::operator>>
friend QDataStream & operator>>(QDataStream &in, KDateTime &dateTime)
Read a KDateTime object into dateTime from in, in binary format.
Definition: kdatetime.cpp:2456
KLocalizedString::toString
QString toString() const
Finalizes the translation, creates QString with placeholders substituted.
Definition: klocalizedstring.cpp:192
KDateTime::isValid
bool isValid() const
Returns whether the date/time is valid.
Definition: kdatetime.cpp:830
KDateTime::Inside
This KDateTime starts after the start of the other, and ends before the end of the other...
Definition: kdatetime.h:487
kdebug.h
matchMonth
static int matchMonth(const QString &string, int &offset, KCalendarSystem *)
Definition: kdatetime.cpp:2892
kdatetime.h
Date/times with associated time zone.
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::Spec::LocalZone
static Spec LocalZone()
Returns a local time zone time specification.
Definition: kdatetime.cpp:212
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
QDate::toString
QString toString(Qt::DateFormat format) const
QByteArray
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
KSystemTimeZones::zone
static KTimeZone zone(const QString &name)
Returns the time zone with the given name.
Definition: ksystemtimezone.cpp:255
checkDate
static QDate checkDate(int year, int month, int day, Status &)
Definition: kdatetime.cpp:3060
ki18n
KLocalizedString ki18n(const char *msg)
Creates localized string from a given message.
Definition: klocalizedstring.cpp:924
QDataStream
QChar
KDateTime::timeSpec
Spec timeSpec() const
Returns the time specification of the date/time, i.e.
Definition: kdatetime.cpp:842
KDateTime::addDays
KDateTime addDays(int days) const
Returns a date/time days days later than the stored date/time.
Definition: kdatetime.cpp:1132
KDateTime::setTimeSpec
void setTimeSpec(const Spec &spec)
Changes the time specification of the instance.
Definition: kdatetime.cpp:1050
KDateTime::setSimulatedSystemTime
static void setSimulatedSystemTime(const KDateTime &newTime)
Set an adjustment to be applied when fetching the current system time.
Definition: kdatetime.cpp:2424
KTimeZone::isValid
bool isValid() const
Checks whether the instance is valid.
Definition: ktimezone.cpp:644
KDateTime::After
This KDateTime is strictly later than the other, i.e.
Definition: kdatetime.h:495
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
NO_NUMBER
static const int NO_NUMBER
Definition: kdatetime.cpp:96
QMap::constBegin
const_iterator constBegin() const
QMap
KDateTime::Comparison
Comparison
How this KDateTime compares with another.
Definition: kdatetime.h:478
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
QByteArray::isEmpty
bool isEmpty() const
QString::simplified
QString simplified() const
QTime::isValid
bool isValid() const
KDateTime::QtTextDate
Same format as Qt::TextDate (i.e.
Definition: kdatetime.h:445
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::Invalid
an invalid time specification.
Definition: kdatetime.h:183
KDateTime::toString
QString toString(const QString &format) const
Returns the date/time as a string.
Definition: kdatetime.cpp:1434
QDateTime::time
QTime time() const
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
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
KDateTime::setSecondOccurrence
void setSecondOccurrence(bool second)
Sets whether the date/time is the second occurrence of this time.
Definition: kdatetime.cpp:1055
KDateTime::isDateOnly
bool isDateOnly() const
Returns whether the instance represents a date/time or a date-only value.
Definition: kdatetime.cpp:832
KDateTime::realCurrentLocalDateTime
static KDateTime realCurrentLocalDateTime()
Return the real (not simulated) system time.
Definition: kdatetime.cpp:2441
KSystemTimeZones::setLocalZone
static void setLocalZone(const KTimeZone &tz)
Set or clear the simulated local system time zone.
Definition: ksystemtimezone.cpp:211
QByteArray::length
int length() const
KTimeZones
The KTimeZones class represents a time zone database which consists of a collection of individual tim...
Definition: ktimezone.h:308
QDate::month
int month() const
KDateTime::Spec::isClockTime
bool isClockTime() const
Returns whether the time specification is a local clock time.
Definition: kdatetime.cpp:217
klocale.h
KDateTime::RFCDate
RFC 2822 format, i.e.
Definition: kdatetime.h:435
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
QTime
KDateTime::setTime
void setTime(const QTime &time)
Sets the time part of the date/time.
Definition: kdatetime.cpp:1030
K_GLOBAL_STATIC_WITH_ARGS
K_GLOBAL_STATIC_WITH_ARGS(KComponentData, fakeComponent,(KGlobalPrivate::initFakeComponent())) KStandardDirs *KGlobal
Definition: kglobal.cpp:129
KDateTime::Spec::equivalentTo
bool equivalentTo(const Spec &other) const
Checks whether this instance is equivalent to another.
Definition: kdatetime.cpp:230
QTime::second
int second() const
KCalendarSystem
KCalendarSystem abstract base class, provides support for local Calendar Systems in KDE...
Definition: kcalendarsystem.h:40
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
QList::size
int size() const
longDay
static const char longDay[][10]
Definition: kdatetime.cpp:57
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::operator==
bool operator==(const Spec &other) const
Comparison operator.
Definition: kdatetime.cpp:221
QList::value
T value(int i) const
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::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
QString::clear
void clear()
QDate::dayOfWeek
int dayOfWeek() const
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::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::operator==
bool operator==(const KDateTime &other) const
Check whether this date/time is simultaneous with another.
Definition: kdatetime.cpp:1360
KDateTime::Spec::utcOffset
int utcOffset() const
Returns the UTC offset associated with the time specification.
Definition: kdatetime.cpp:219
ksystemtimezone.h
System time zone functions.
QRegExp
QDateTime::setTimeSpec
void setTimeSpec(Qt::TimeSpec spec)
QDate::fromString
QDate fromString(const QString &string, Qt::DateFormat format)
longMonth
static const char longMonth[][10]
Definition: kdatetime.cpp:67
kcalendarsystemqdate_p.h
kglobal.h
KDateTime::addMSecs
KDateTime addMSecs(qint64 msecs) const
Returns a date/time msecs milliseconds later than the stored date/time.
Definition: kdatetime.cpp:1070
QSharedData
QString::number
QString number(int n, int base)
QList::count
int count(const T &value) const
KDateTime::utcOffset
int utcOffset() const
Returns the UTC offset associated with the date/time.
Definition: kdatetime.cpp:858
KDateTime::operator=
KDateTime & operator=(const KDateTime &other)
Definition: kdatetime.cpp:821
KDateTime::LocalDate
Same format as Qt::LocalDate (i.e.
Definition: kdatetime.h:449
getAmPm
static int getAmPm(const QString &string, int &offset, KLocale *)
Definition: kdatetime.cpp:2975
QDate::addMonths
QDate addMonths(int nmonths) const
getNumber
static bool getNumber(const QString &string, int &offset, int mindigits, int maxdigits, int minval, int maxval, int &result)
Definition: kdatetime.cpp:3015
Status
Status
Definition: kdatetime.cpp:76
KDateTime::TimeFormat
TimeFormat
Format for strings representing date/time values.
Definition: kdatetime.h:419
KDateTime::isClockTime
bool isClockTime() const
Returns whether the date/time is a local clock time.
Definition: kdatetime.cpp:834
QDate::isNull
bool isNull() const
QRegExp::capturedTexts
QStringList capturedTexts() const
shortMonth
static const char shortMonth[][4]
Definition: kdatetime.cpp:62
KTimeZone::abbreviation
QByteArray abbreviation(const QDateTime &utcDateTime) const
Returns the time zone abbreviation current at a specified time.
Definition: ktimezone.cpp:681
KDateTime::Spec::type
SpecType type() const
Returns the time specification type, i.e.
Definition: kdatetime.cpp:214
QDate::setYMD
bool setYMD(int y, int m, int d)
QString::toInt
int toInt(bool *ok, int base) const
QList::isEmpty
bool isEmpty() const
findString_internal
static int findString_internal(const QString &string, const char *ptr, int count, int &offset, int disp)
Definition: kdatetime.cpp:3041
QString::isEmpty
bool isEmpty() const
QString::trimmed
QString trimmed() const
QMap::constEnd
const_iterator constEnd() const
QDate::day
int day() const
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::toUtc
KDateTime toUtc() const
Returns the time converted to UTC.
Definition: kdatetime.cpp:871
KDateTime::date
QDate date() const
Returns the date part of the date/time.
Definition: kdatetime.cpp:838
QString::startsWith
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
KDateTime::dateTime
QDateTime dateTime() const
Returns the date/time component of the instance, ignoring the time zone.
Definition: kdatetime.cpp:840
QDate::isValid
bool isValid() const
KSystemTimeZones::local
static KTimeZone local()
Returns the current local system time zone.
Definition: ksystemtimezone.cpp:195
KDateTime::Spec::OffsetFromUTC
static Spec OffsetFromUTC(int utcOffset)
Returns a UTC offset time specification.
Definition: kdatetime.cpp:213
QDate
KDateTime::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::toClockTime
KDateTime toClockTime() const
Returns the time converted to the local clock time.
Definition: kdatetime.cpp:953
QDate::year
int year() const
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
QString
QList< int >
KTimeZone::InvalidOffset
static const int InvalidOffset
Indicates an invalid UTC offset.
Definition: ktimezone.h:1073
KDateTime::addYears
KDateTime addYears(int years) const
Returns a date/time years years later than the stored date/time.
Definition: kdatetime.cpp:1150
QStringList
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
KDateTime::Spec::Spec
Spec()
Constructs an invalid time specification.
Definition: kdatetime.cpp:116
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
QTime::hour
int hour() const
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
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
KDateTime::addSecs
KDateTime addSecs(qint64 secs) const
Returns a date/time secs seconds later than the stored date/time.
Definition: kdatetime.cpp:1107
matchDay
static int matchDay(const QString &string, int &offset, KCalendarSystem *)
Definition: kdatetime.cpp:2851
KDateTime::Spec::UTC
static Spec UTC()
The UTC time specification.
Definition: kdatetime.cpp:210
KDateTime
A class representing a date and time with an associated time zone.
Definition: kdatetime.h:171
KSystemTimeZones::realLocalZone
static KTimeZone realLocalZone()
Return the real (not simulated) local system time zone.
Definition: ksystemtimezone.cpp:205
QLatin1Char
QDateTime::timeSpec
Qt::TimeSpec timeSpec() const
isalpha
#define isalpha(c)
Definition: ctype_test_p.h:85
QDateTime::fromString
QDateTime fromString(const QString &string, Qt::DateFormat format)
QList::contains
bool contains(const T &value) const
KTimeZone
Base class representing a time zone.
Definition: ktimezone.h:416
QDateTime::toTime_t
uint toTime_t() const
QDateTime::isValid
bool isValid() const
KGlobal::locale
KLocale * locale()
Returns the global locale object.
Definition: kglobal.cpp:170
KDateTime::Spec::operator=
Spec & operator=(const Spec &spec)
Assignment operator.
Definition: kdatetime.cpp:145
QDate::setDate
bool setDate(int year, int month, int day)
QString::unicode
const QChar * unicode() const
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::OffsetFromUTC
a local time which has a fixed offset from UTC.
Definition: kdatetime.h:185
KServiceTypeProfile::clearCache
void clearCache()
Clear all cached information.
Definition: kservicetypeprofile.cpp:103
KCalendarSystem::ShortDayName
Short name format, e.g.
Definition: kcalendarsystem.h:67
QDateTime::currentDateTime
QDateTime currentDateTime()
KDateTime::toLocalZone
KDateTime toLocalZone() const
Returns the time converted to the current local system time zone.
Definition: kdatetime.cpp:927
QString::toLatin1
QByteArray toLatin1() const
QString::mid
QString mid(int position, int n) const
KDateTime::Spec::isLocalZone
bool isLocalZone() const
Returns whether the time specification is the current local system time zone.
Definition: kdatetime.cpp:216
QDateTime::date
QDate date() const
KDateTime::UTC
a UTC time.
Definition: kdatetime.h:184
KLocale
KLocale provides support for country specific stuff like the national language.
Definition: klocale.h:69
KDateTime::Spec::~Spec
~Spec()
Destructor.
Definition: kdatetime.cpp:140
QLatin1String
QDateTime::secsTo
int secsTo(const QDateTime &other) const
fromStr
static QDateTime fromStr(const QString &string, const QString &format, int &utcOffset, QString &zoneName, QByteArray &zoneAbbrev, bool &dateOnly, Status &)
Definition: kdatetime.cpp:2477
KDateTime::operator<<
friend QDataStream & operator<<(QDataStream &out, const KDateTime &dateTime)
Write dateTime to the datastream out, in binary format.
Definition: kdatetime.cpp:2450
KDateTime::addMonths
KDateTime addMonths(int months) const
Returns a date/time months months later than the stored date/time.
Definition: kdatetime.cpp:1141
QString::sprintf
QString & sprintf(const char *cformat,...)
KDateTime::AtEnd
This KDateTime starts after the start of the other, and ends at the same time as the other...
Definition: kdatetime.h:491
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::isLocalZone
bool isLocalZone() const
Returns whether the time zone for the date/time is the current local system time zone.
Definition: kdatetime.cpp:833
operator>>
QDataStream & operator>>(QDataStream &s, KDateTime::Spec &spec)
Read a KDateTime::Spec object into spec from in, in binary format.
Definition: kdatetime.cpp:274
KDateTime::ISODate
ISO 8601 format, i.e.
Definition: kdatetime.h:421
KDateTime::Before
This KDateTime is strictly earlier than the other, i.e.
Definition: kdatetime.h:480
KDateTime::Spec::setType
void setType(SpecType type, int utcOffset=0)
Initialises the time specification.
Definition: kdatetime.cpp:158
KDateTime::Outside
This KDateTime starts before the start of the other, and ends after the end of the other...
Definition: kdatetime.h:501
QString::length
int length() const
KDateTime::~KDateTime
~KDateTime()
Definition: kdatetime.cpp:817
KDateTime::toZone
KDateTime toZone(const KTimeZone &zone) const
Returns the time converted to a specified time zone.
Definition: kdatetime.cpp:966
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::AtStart
This KDateTime starts at the same time as the other, and ends before the end of the other...
Definition: kdatetime.h:483
KCalendarSystem::ShortName
Short name format, e.g.
Definition: kcalendarsystem.h:56
stTooEarly
Definition: kdatetime.cpp:78
QString::fromLatin1
QString fromLatin1(const char *str, int size)
KDateTime::isUtc
bool isUtc() const
Returns whether the date/time is a UTC time.
Definition: kdatetime.cpp:835
MIN_YEAR
static const int MIN_YEAR
Definition: kdatetime.cpp:95
stValid
Definition: kdatetime.cpp:77
KDateTime::currentUtcDateTime
static KDateTime currentUtcDateTime()
Returns the current date and time, as reported by the system clock, expressed in UTC.
Definition: kdatetime.cpp:1240
KTimeZone::name
QString name() const
Returns the name of the time zone.
Definition: ktimezone.cpp:669
shortDay
static const char shortDay[][4]
Definition: kdatetime.cpp:52
QDate::addDays
QDate addDays(int ndays) const
getUTCOffset
static bool getUTCOffset(const QString &string, int &offset, bool colon, int &result)
Definition: kdatetime.cpp:2930
KTimeZones::zones
const ZoneMap zones() const
Returns all the time zones defined in this collection.
Definition: ktimezone.cpp:67
KDateTime::RFC3339Date
RFC 3339 format, i.e.
Definition: kdatetime.h:453
KDateTime::Spec::isValid
bool isValid() const
Returns whether the time specification is valid.
Definition: kdatetime.cpp:215
QDateTime::addSecs
QDateTime addSecs(int s) const
QMap::ConstIterator
typedef ConstIterator
KCalendarSystem::LongName
Long name format, e.g.
Definition: kcalendarsystem.h:57
KDateTime::setDate
void setDate(const QDate &date)
Sets the date part of the date/time.
Definition: kdatetime.cpp:1025
QByteArray::size
int size() const
KDateTime::Spec
The full time specification of a KDateTime instance.
Definition: kdatetime.h:223
QDateTime::addDays
QDateTime addDays(int ndays) const
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
KCalendarSystemQDate
Definition: kcalendarsystemqdate_p.h:41
KDateTime::timeType
SpecType timeType() const
Returns the time specification type of the date/time, i.e.
Definition: kdatetime.cpp:843
QTime::secsTo
int secsTo(const QTime &t) const
KCalendarSystem::LongDayName
Long name format, e.g.
Definition: kcalendarsystem.h:68
KCalendarSystemQDate::weekDayName
virtual QString weekDayName(int weekDay, WeekDayNameFormat format=LongDayName) const
Gets specific calendar type week day name.
Definition: kcalendarsystemqdate.cpp:509
KDateTime::time
QTime time() const
Returns the time part of the date/time.
Definition: kdatetime.cpp:839
KTimeZone::utc
static KTimeZone utc()
Returns a standard UTC time zone, with name "UTC".
Definition: ktimezone.cpp:911
KCalendarSystem::weekDayName
virtual QString weekDayName(int weekDay, WeekDayNameFormat format=LongDayName) const =0
Gets specific calendar type week day name.
Definition: kcalendarsystem.cpp:1881
KDateTime::isSecondOccurrence
bool isSecondOccurrence() const
Returns whether the date/time is the second occurrence of this time.
Definition: kdatetime.cpp:837
KDateTime::operator<
bool operator<(const KDateTime &other) const
Check whether this date/time is earlier than another.
Definition: kdatetime.cpp:1392
KDateTime::Spec::isUtc
bool isUtc() const
Returns whether the time specification is a UTC time.
Definition: kdatetime.cpp:202
QSharedDataPointer< KDateTimePrivate >
KTimeZones::zone
KTimeZone zone(const QString &name) const
Returns the time zone with the given name.
Definition: ktimezone.cpp:118
QDateTime
findString
static int findString(const QString &string, const char array[][disp], int count, int &offset)
Definition: kdatetime.cpp:91
KDateTime::TimeZone
a time in a specified time zone.
Definition: kdatetime.h:186
indexOf
static int indexOf(const QByteArray &that, const QByteArray &ba)
Definition: kmimemagicrule.cpp:60
QDateTime::setTime_t
void setTime_t(uint seconds)
QMap::value
const T value(const Key &key) const
KDateTime::isNull
bool isNull() const
Returns whether the date/time is null.
Definition: kdatetime.cpp:829
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:22:11 by doxygen 1.8.7 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 API Reference

Skip menu "kdelibs 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

Search



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