Qt 4.8
qabstractdatetime.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtXmlPatterns module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include <QStringList>
43 
44 #include "qbuiltintypes_p.h"
45 #include "qitem_p.h"
46 #include "qpatternistlocale_p.h"
47 #include "qvalidationerror_p.h"
48 
49 #include "qabstractdatetime_p.h"
50 
52 
53 using namespace QPatternist;
54 
55 AbstractDateTime::AbstractDateTime(const QDateTime &dateTime) : m_dateTime(dateTime)
56 {
57  Q_ASSERT(dateTime.isValid());
58 }
59 
60 #define badData(msg) errorMessage = ValidationError::createError(msg); return QDateTime()
61 #define getCapt(sym) ((captTable.sym == -1) ? QString() : capts.at(captTable.sym))
62 #define getSafeCapt(sym) ((captTable.sym == -1) ? QString() : capts.value(captTable.sym))
63 
65  const QString &lexicalSource,
66  const CaptureTable &captTable)
67 {
68  QRegExp myExp(captTable.regExp);
69 
70  if(!myExp.exactMatch(lexicalSource))
71  {
72  badData(QString());
73  }
74 
75  const QStringList capts(myExp.capturedTexts());
76  const QString yearStr(getCapt(year));
77 
78  if(yearStr.size() > 4 && yearStr.at(0) == QLatin1Char('0'))
79  {
80  badData(QtXmlPatterns::tr("Year %1 is invalid because it begins with %2.")
81  .arg(formatData(yearStr)).arg(formatData("0")));
82  }
83 
84  /* If the strings are empty, load default values which are
85  * guranteed to pass the validness tests. */
86  const QString monthStr(getCapt(month));
87  const QString dayStr(getCapt(day));
88  YearProperty year = yearStr.isEmpty() ? DefaultYear : yearStr.toInt();
89  if(getCapt(yearSign) == QChar::fromLatin1('-'))
90  year = -year;
91  const MonthProperty month = monthStr.isEmpty() ? DefaultMonth : monthStr.toInt();
92  const MonthProperty day = dayStr.isEmpty() ? DefaultDay : dayStr.toInt();
93 
94  if(!QDate::isValid(year, month, day))
95  {
96  /* Try to give an intelligent message. */
97  if(day > 31 || day < 1)
98  {
99  badData(QtXmlPatterns::tr("Day %1 is outside the range %2..%3.")
100  .arg(formatData(QString::number(day)))
101  .arg(formatData("01"))
102  .arg(formatData("31")));
103  }
104  else if(month > 12 || month < -12 || month == 0)
105  {
106  badData(QtXmlPatterns::tr("Month %1 is outside the range %2..%3.")
107  .arg(month)
108  .arg(formatData("01"))
109  .arg(formatData("12")));
110 
111  }
112  else if(QDate::isValid(DefaultYear, month, day))
113  {
114  /* We can't use the badData() macro here because we need a different
115  * error code: FODT0001 instead of FORG0001. */
116  errorMessage = ValidationError::createError(QtXmlPatterns::tr(
117  "Overflow: Can't represent date %1.")
118  .arg(formatData(QLatin1String("%1-%2-%3"))
119  .arg(year).arg(month).arg(day)),
121  return QDateTime();
122  }
123  else
124  {
125  badData(QtXmlPatterns::tr("Day %1 is invalid for month %2.")
126  .arg(formatData(QString::number(day)))
127  .arg(formatData(QString::number(month))));
128  }
129  }
130 
131  /* Parse the zone offset. */
132  ZoneOffsetParseResult zoResult;
133  const ZOTotal offset = parseZoneOffset(zoResult, capts, captTable);
134 
135  if(zoResult == Error)
136  {
137  errorMessage = ValidationError::createError();
138  /* We encountered an error, so stop processing. */
139  return QDateTime();
140  }
141 
142  QDate date(year, month, day);
143 
144  /* Only deal with time if time is needed. */
145  if(captTable.hour == -1)
146  {
147  QDateTime result(date);
148  setUtcOffset(result, zoResult, offset);
149  return result;
150  }
151  else
152  {
153  /* Now, it's time for the time-part.
154  *
155  * If the strings are empty, toInt() will return 0, which
156  * in all cases is valid properties. */
157  const QString hourStr(getCapt(hour));
158  const QString minutesStr(getCapt(minutes));
159  const QString secondsStr(getCapt(seconds));
160  HourProperty hour = hourStr.toInt();
161  const MinuteProperty mins = minutesStr.toInt();
162  const SecondProperty secs = secondsStr.toInt();
163 
164  QString msecondsStr(getSafeCapt(mseconds));
165  if(!msecondsStr.isEmpty())
166  msecondsStr = msecondsStr.leftJustified(3, QLatin1Char('0'), true);
167  const MSecondProperty msecs = msecondsStr.toInt();
168 
169  if(hour == 24)
170  {
171  /* 24:00:00.00 is an invalid time for QTime, so handle it here. */
172  if(mins != 0 || secs != 0 || msecs != 0)
173  {
174  badData(QtXmlPatterns::tr("Time 24:%1:%2.%3 is invalid. "
175  "Hour is 24, but minutes, seconds, "
176  "and milliseconds are not all 0; ")
177  .arg(mins).arg(secs).arg(msecs));
178  }
179  else
180  {
181  hour = 0;
182  date = date.addDays(1);
183  }
184  }
185  else if(!QTime::isValid(hour, mins, secs, msecs))
186  {
187  badData(QtXmlPatterns::tr("Time %1:%2:%3.%4 is invalid.")
188  .arg(hour).arg(mins).arg(secs).arg(msecs));
189  }
190 
191  const QTime time(hour, mins, secs, msecs);
192  Q_ASSERT(time.isValid());
193 
194  QDateTime result(date, time);
195  setUtcOffset(result, zoResult, offset);
196  return result;
197  }
198 }
199 
201  const QStringList &capts,
202  const CaptureTable &captTable)
203 {
204  const QString zoneOffsetSignStr(getCapt(zoneOffsetSign));
205 
206  if(zoneOffsetSignStr.isEmpty())
207  {
208  const QString zoneOffsetUTCStr(getCapt(zoneOffsetUTCSymbol));
209  Q_ASSERT(zoneOffsetUTCStr.isEmpty() || zoneOffsetUTCStr == QLatin1String("Z"));
210 
211  if(zoneOffsetUTCStr.isEmpty())
212  result = LocalTime;
213  else
214  result = UTC;
215 
216  return 0;
217  }
218 
219  Q_ASSERT(zoneOffsetSignStr == QLatin1String("-") || zoneOffsetSignStr == QLatin1String("+"));
220 
221  const QString zoneOffsetHourStr(getCapt(zoneOffsetHour));
222  Q_ASSERT(!zoneOffsetHourStr.isEmpty());
223  const ZOHourProperty zoHour = zoneOffsetHourStr.toInt();
224 
225  if(zoHour > 14 || zoHour < -14)
226  {
227  result = Error;
228  return 0;
229  /*
230  badZOData(QtXmlPatterns::tr("%1 it is not a valid hour property in a zone offset. "
231  "It must be less than or equal to 14.").arg(zoHour));
232  */
233  }
234 
235  const QString zoneOffsetMinuteStr(getCapt(zoneOffsetMinute));
236  Q_ASSERT(!zoneOffsetMinuteStr.isEmpty());
237  const ZOHourProperty zoMins = zoneOffsetMinuteStr.toInt();
238 
239  if(zoHour == 14 && zoMins != 0)
240  {
241  /*
242  badZOData(QtXmlPatterns::tr("When the hour property in a zone offset is 14, the minute property "
243  "must be 0, not %1.").arg(zoMins));
244  */
245  result = Error;
246  return 0;
247  }
248  else if(zoMins > 59 || zoMins < -59)
249  {
250  /*
251  badZOData(QtXmlPatterns::tr("The minute property in a zone offset cannot be larger than 59. "
252  "%1 is therefore invalid.").arg(zoMins));
253  */
254  result = Error;
255  return 0;
256  }
257 
258  if(zoHour == 0 && zoMins == 0) /* "-00:00" and "+00:00" is equal to 'Z'. */
259  {
260  result = UTC;
261  return 0;
262  }
263  else
264  {
265  ZOTotal zoneOffset = (zoHour * 60 + zoMins) * 60;
266 
267  if(zoneOffsetSignStr == QChar::fromLatin1('-'))
268  zoneOffset = -zoneOffset;
269 
270  result = Offset;
271  return zoneOffset;
272  }
273 }
274 //#undef badZOData
275 
277  const ZoneOffsetParseResult zoResult,
278  const int zoOffset)
279 {
280  if(zoResult == UTC)
281  result.setTimeSpec(Qt::UTC);
282  else if(zoResult == LocalTime)
283  result.setTimeSpec(Qt::LocalTime);
284  else
285  {
286  Q_ASSERT(zoResult == Offset);
287  result.setUtcOffset(zoOffset);
288  }
289 }
290 
291 #undef badData
292 #undef getCapt
293 #undef getSafeCapt
294 
296  QString &message)
297 {
298  if(date.isValid())
299  return true;
300  else
301  {
302  message = QtXmlPatterns::tr("Overflow: Date can't be represented.");
303  return false;
304  }
305 }
306 
308 {
309  return m_dateTime.toString(QLatin1String("yyyy-MM-dd"));
310 }
311 
313 {
314  QString retval;
315  retval.append(QLatin1Char('.'));
316  int div = 100;
317  MSecondProperty msecs = mseconds;
318 
319  while(msecs > 0)
320  {
321  int d = msecs / div;
322  retval.append(QLatin1Char(d + '0'));
323  msecs = msecs % div;
324  div = div / 10;
325  }
326 
327  return retval;
328 }
329 
331 {
333  const MSecondProperty msecs = m_dateTime.time().msec();
334 
335  if(msecs)
336  base.append(serializeMSeconds(msecs));
337 
338  return base;
339 }
340 
342 {
343  switch(m_dateTime.timeSpec())
344  {
345  case Qt::LocalTime:
346  return QString();
347  case Qt::UTC:
348  return QLatin1String("Z");
349  default:
350  {
352 
353  const int zoneOffset = m_dateTime.utcOffset();
354  Q_ASSERT(zoneOffset != 0);
355  const int posZoneOffset = qAbs(zoneOffset);
356 
357  /* zoneOffset is in seconds. */
358  const int hours = posZoneOffset/(60 * 60);
359  const int minutes = (posZoneOffset % (60 * 60)) / 60;
360 
361  QString result;
362  result.reserve(6);
363 
364  result.append(zoneOffset < 0 ? QLatin1Char('-') : QLatin1Char('+'));
365  result.append(QString::number(hours).rightJustified(2, QLatin1Char('0')));
366  result.append(QLatin1Char(':'));
367  result.append(QString::number(minutes).rightJustified(2, QLatin1Char('0')));
368  return result;
369  }
370  }
371 }
372 
374  QDateTime &to)
375 {
376  switch(from.timeSpec())
377  {
378  case Qt::UTC:
379  /* Fallthrough. */
380  case Qt::LocalTime:
381  {
382  to.setTimeSpec(from.timeSpec());
383  return;
384  }
385  case Qt::OffsetFromUTC:
386  {
387  to.setUtcOffset(from.utcOffset());
389  return;
390  }
391  }
392 }
393 
395 {
396  Q_ASSERT_X(false, Q_FUNC_INFO,
397  "Calling AbstractDateTime::fromDateTime() makes no sense.");
398  return Item();
399 }
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: qstring.cpp:6448
double d
Definition: qnumeric_p.h:62
#define getCapt(sym)
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
The QRegExp class provides pattern matching using regular expressions.
Definition: qregexp.h:61
bool isValid() const
Returns true if this date is valid; otherwise returns false.
Definition: qdatetime.cpp:340
int toInt(bool *ok=0, int base=10) const
Returns the string converted to an int using base base, which is 10 by default and must be between 2 ...
Definition: qstring.cpp:6090
QString leftJustified(int width, QChar fill=QLatin1Char(' '), bool trunc=false) const Q_REQUIRED_RESULT
Returns a string of size width that contains this string padded by the fill character.
Definition: qstring.cpp:5318
Due to strong interdependencies, this file contains the definitions for the classes Item...
static AtomicValue::Ptr createError(const QString &description=QString(), const ReportContext::ErrorCode=ReportContext::FORG0001)
#define badData(msg)
qint8 MinuteProperty
bool isValid() const
Returns true if both the date and the time are valid; otherwise returns false.
Definition: qdatetime.cpp:2346
qint32 SecondProperty
The QDate class provides date functions.
Definition: qdatetime.h:55
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
int msec() const
Returns the millisecond part (0 to 999) of the time.
Definition: qdatetime.cpp:1611
The QString class provides a Unicode character string.
Definition: qstring.h:83
Q_DECL_CONSTEXPR T qAbs(const T &t)
Definition: qglobal.h:1201
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
qint8 ZOHourProperty
static void setUtcOffset(QDateTime &result, const ZoneOffsetParseResult zoResult, const int zoOffset)
static const uint base
Definition: qurl.cpp:268
int utcOffset() const
Definition: qdatetime.cpp:3449
QString toString(Qt::DateFormat f=Qt::TextDate) const
Returns the datetime as a string in the format given.
Definition: qdatetime.cpp:2628
static QDateTime create(AtomicValue::Ptr &errorMessage, const QString &lexicalSource, const CaptureTable &captTable)
qint8 MonthProperty
void reserve(int size)
Attempts to allocate memory for at least size characters.
Definition: qstring.h:881
The QTime class provides clock time functions.
Definition: qdatetime.h:148
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
AbstractDateTime(const QDateTime &dateTime)
#define getSafeCapt(sym)
QStringList capturedTexts() const
Returns a list of the captured text strings.
Definition: qregexp.cpp:4267
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
The QStringList class provides a list of strings.
Definition: qstringlist.h:66
Acts as a mapping table for AbstractDateTime::create() and describes where certain fields in a QRegEx...
The namespace for the internal API of QtXmlPatterns.
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal...
Definition: qstring.h:654
static QChar fromLatin1(char c)
Converts the Latin-1 character c to its equivalent QChar.
Definition: qchar.h:378
void setTimeSpec(Qt::TimeSpec spec)
Sets the time specification used in this datetime to spec.
Definition: qdatetime.cpp:2431
QDate addDays(int days) const
Returns a QDate object containing a date ndays later than the date of this object (or earlier if nday...
Definition: qdatetime.cpp:989
static QString formatData(const QString &data)
static ZOTotal parseZoneOffset(ZoneOffsetParseResult &result, const QStringList &capts, const CaptureTable &captTable)
Parses the zone offset. All types use zone offsets.
qint8 HourProperty
qint32 YearProperty
static void copyTimeSpec(const QDateTime &from, QDateTime &to)
Makes the QDateTime::timeSpec() and QDateTime::zoneOffset() of ot * consistent to from...
#define Q_ASSERT_X(cond, where, what)
Definition: qglobal.h:1837
QString & append(QChar c)
Definition: qstring.cpp:1777
Contains functions used for formatting arguments, such as keywords and paths, in translated strings...
The QDateTime class provides date and time functions.
Definition: qdatetime.h:216
Represents an item in the XPath 2.0 Data Model.
Definition: qitem_p.h:182
static bool isRangeValid(const QDate &date, QString &message)
Qt::TimeSpec timeSpec() const
Returns the time specification of the datetime.
Definition: qdatetime.cpp:2379
bool exactMatch(const QString &str) const
Returns true if str is matched exactly by this regular expression; otherwise returns false...
Definition: qregexp.cpp:4094
virtual Item fromValue(const QDateTime &dt) const
QTime time() const
Returns the time part of the datetime.
Definition: qdatetime.cpp:2368
qint16 MSecondProperty
static QString serializeMSeconds(const MSecondProperty msecs)
qint32 ZOTotal
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:55
quint16 Offset
bool isValid() const
Returns true if the time is valid; otherwise returns false.
Definition: qdatetime.cpp:1566
#define Q_FUNC_INFO
Definition: qglobal.h:1871
void setUtcOffset(int seconds)
Definition: qdatetime.cpp:3416