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

KDE3Support

  • sources
  • kde-4.14
  • kdelibs
  • kde3support
  • kdecore
k3rfcdate.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the KDE libraries
3  * Copyright (c) 2000-2002 Waldo Bastian <bastian@kde.org>
4  * 2002 Rik Hemsley <rik@kde.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License version 2 as published by the Free Software Foundation.
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 "k3rfcdate.h"
22 
23 #include <config.h>
24 
25 #include <sys/param.h>
26 #include <ctype.h>
27 #include <stdlib.h>
28 
29 #include <QtCore/QMutableStringListIterator>
30 #include <QtCore/QCharRef>
31 #include <QtCore/QByteArray>
32 
33 static unsigned int ymdhms_to_seconds(int year, int mon, int day, int hour, int minute, int second)
34 {
35  if (sizeof(time_t) == 4)
36  {
37  if ((time_t)-1 < 0)
38  {
39  if (year >= 2038)
40  {
41  year = 2038;
42  mon = 0;
43  day = 1;
44  hour = 0;
45  minute = 0;
46  second = 0;
47  }
48  }
49  else
50  {
51  if (year >= 2115)
52  {
53  year = 2115;
54  mon = 0;
55  day = 1;
56  hour = 0;
57  minute = 0;
58  second = 0;
59  }
60  }
61  }
62 
63  unsigned int ret = (day - 32075) /* days */
64  + 1461L * (year + 4800L + (mon - 14) / 12) / 4
65  + 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12
66  - 3 * ((year + 4900L + (mon - 14) / 12) / 100) / 4
67  - 2440588;
68  ret = 24*ret + hour; /* hours */
69  ret = 60*ret + minute; /* minutes */
70  ret = 60*ret + second; /* seconds */
71 
72  return ret;
73 }
74 
75 static const char haystack[37]="janfebmaraprmayjunjulaugsepoctnovdec";
76 
77 // we follow the recommendation of rfc2822 to consider all
78 // obsolete time zones not listed here equivalent to "-0000"
79 static const struct {
80  const char tzName[4];
81  int tzOffset;
82 } known_zones[] = {
83  { "UT", 0 },
84  { "GMT", 0 },
85  { "EST", -300 },
86  { "EDT", -240 },
87  { "CST", -360 },
88  { "CDT", -300 },
89  { "MST", -420 },
90  { "MDT", -360 },
91  { "PST", -480 },
92  { "PDT", -420 },
93  { { 0,0,0,0 }, 0 }
94 };
95 
96 time_t
97 K3RFCDate::parseDate(const QString &_date)
98 {
99  if (_date.isEmpty())
100  return 0;
101 
102  // This parse a date in the form:
103  // Wednesday, 09-Nov-99 23:12:40 GMT
104  // or
105  // Sat, 01-Jan-2000 08:00:00 GMT
106  // or
107  // Sat, 01 Jan 2000 08:00:00 GMT
108  // or
109  // 01 Jan 99 22:00 +0100 (exceptions in rfc822/rfc2822)
110  //
111  // We ignore the weekday
112  //
113  time_t result = 0;
114  int offset = 0;
115  char *newPosStr;
116  const QByteArray dateArray = _date.toLatin1();
117  const char *dateString = dateArray.data();
118  int day = 0;
119  char monthStr[4];
120  int month = -1;
121  int year = 0;
122  int hour = 0;
123  int minute = 0;
124  int second = 0;
125 
126  // Strip leading space
127  while(*dateString && isspace(*dateString))
128  dateString++;
129 
130  // Strip weekday
131  while(*dateString && !isdigit(*dateString) && !isspace(*dateString))
132  dateString++;
133 
134  // Strip trailing space
135  while(*dateString && isspace(*dateString))
136  dateString++;
137 
138  if (!*dateString)
139  return result; // Invalid date
140 
141  if (isalpha(*dateString))
142  {
143  // ' Nov 5 1994 18:15:30 GMT'
144  // Strip leading space
145  while(*dateString && isspace(*dateString))
146  dateString++;
147 
148  for(int i=0; i < 3;i++)
149  {
150  if (!*dateString || (*dateString == '-') || isspace(*dateString))
151  return result; // Invalid date
152  monthStr[i] = tolower(*dateString++);
153  }
154  monthStr[3] = '\0';
155 
156  newPosStr = (char*)strstr(haystack, monthStr);
157 
158  if (!newPosStr)
159  return result; // Invalid date
160 
161  month = (newPosStr-haystack)/3; // Jan=00, Feb=01, Mar=02, ..
162 
163  if ((month < 0) || (month > 11))
164  return result; // Invalid date
165 
166  while (*dateString && isalpha(*dateString))
167  dateString++; // Skip rest of month-name
168  }
169 
170  // ' 09-Nov-99 23:12:40 GMT'
171  // ' 5 1994 18:15:30 GMT'
172  day = strtol(dateString, &newPosStr, 10);
173  dateString = newPosStr;
174 
175  if ((day < 1) || (day > 31))
176  return result; // Invalid date;
177 
178  if (!*dateString)
179  return result; // Invalid date
180 
181  while(*dateString && (isspace(*dateString) || (*dateString == '-')))
182  dateString++;
183 
184  if (month == -1)
185  {
186  for(int i=0; i < 3;i++)
187  {
188  if (!*dateString || (*dateString == '-') || isspace(*dateString))
189  return result; // Invalid date
190  monthStr[i] = tolower(*dateString++);
191  }
192  monthStr[3] = '\0';
193 
194  newPosStr = (char*)strstr(haystack, monthStr);
195 
196  if (!newPosStr)
197  return result; // Invalid date
198 
199  month = (newPosStr-haystack)/3; // Jan=00, Feb=01, Mar=02, ..
200 
201  if ((month < 0) || (month > 11))
202  return result; // Invalid date
203 
204  while (*dateString && isalpha(*dateString))
205  dateString++; // Skip rest of month-name
206 
207  }
208 
209  // '-99 23:12:40 GMT'
210  while(*dateString && (isspace(*dateString) || (*dateString == '-')))
211  dateString++;
212 
213  if (!*dateString || !isdigit(*dateString))
214  return result; // Invalid date
215 
216  // '99 23:12:40 GMT'
217  year = strtol(dateString, &newPosStr, 10);
218  dateString = newPosStr;
219 
220  // Y2K: Solve 2 digit years
221  if ((year >= 0) && (year < 50))
222  year += 2000;
223 
224  if ((year >= 50) && (year < 100))
225  year += 1900; // Y2K
226 
227  if ((year < 1900) || (year > 2500))
228  return result; // Invalid date
229 
230  // Don't fail if the time is missing.
231  if (*dateString)
232  {
233  // ' 23:12:40 GMT'
234  if (!isspace(*dateString++))
235  return result; // Invalid date
236 
237  hour = strtol(dateString, &newPosStr, 10);
238  dateString = newPosStr;
239 
240  if ((hour < 0) || (hour > 23))
241  return result; // Invalid date
242 
243  if (!*dateString)
244  return result; // Invalid date
245 
246  // ':12:40 GMT'
247  if (*dateString++ != ':')
248  return result; // Invalid date
249 
250  minute = strtol(dateString, &newPosStr, 10);
251  dateString = newPosStr;
252 
253  if ((minute < 0) || (minute > 59))
254  return result; // Invalid date
255 
256  if (!*dateString)
257  return result; // Invalid date
258 
259  // ':40 GMT'
260  if (*dateString != ':' && !isspace(*dateString))
261  return result; // Invalid date
262 
263  // seconds are optional in rfc822 + rfc2822
264  if (*dateString ==':') {
265  dateString++;
266 
267  second = strtol(dateString, &newPosStr, 10);
268  dateString = newPosStr;
269 
270  if ((second < 0) || (second > 59))
271  return result; // Invalid date
272  } else {
273  dateString++;
274  }
275 
276  while(*dateString && isspace(*dateString))
277  dateString++;
278  }
279 
280  // don't fail if the time zone is missing, some
281  // broken mail-/news-clients omit the time zone
282  if (*dateString) {
283  if ((strncasecmp(dateString, "gmt", 3) == 0) ||
284  (strncasecmp(dateString, "utc", 3) == 0))
285  {
286  dateString += 3;
287  while(*dateString && isspace(*dateString))
288  dateString++;
289  }
290 
291  if ((*dateString == '+') || (*dateString == '-')) {
292  offset = strtol(dateString, &newPosStr, 10);
293  if (abs(offset) < 30)
294  {
295  dateString = newPosStr;
296 
297  offset = offset * 100;
298 
299  if (*dateString && *(dateString+1))
300  {
301  dateString++;
302  int minutes = strtol(dateString, &newPosStr, 10);
303  if (offset > 0)
304  offset += minutes;
305  else
306  offset -= minutes;
307  }
308  }
309 
310  if ((offset < -9959) || (offset > 9959))
311  return result; // Invalid date
312 
313  int sgn = (offset < 0)? -1:1;
314  offset = abs(offset);
315  offset = ((offset / 100)*60 + (offset % 100))*sgn;
316  } else {
317  for (int i=0; known_zones[i].tzName != 0; i++) {
318  if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) {
319  offset = known_zones[i].tzOffset;
320  break;
321  }
322  }
323  }
324  }
325 
326  result = ymdhms_to_seconds(year, month+1, day, hour, minute, second);
327 
328  // avoid negative time values
329  if ((offset > 0) && (offset > result))
330  offset = 0;
331 
332  result -= offset*60;
333 
334  // If epoch 0 return epoch +1 which is Thu, 01-Jan-70 00:00:01 GMT
335  // This is so that parse error and valid epoch 0 return values won't
336  // be the same for sensitive applications...
337  if (result < 1) result = 1;
338 
339  return result;
340 }
341 
342 time_t
343 K3RFCDate::parseDateISO8601( const QString& input_ )
344 {
345  if (input_.isEmpty())
346  return 0;
347 
348  // These dates look like this:
349  // YYYY-MM-DDTHH:MM:SS
350  // But they may also have 0, 1 or 2 suffixes.
351  // Suffix 1: .secfrac (fraction of second)
352  // Suffix 2: Either 'Z' or +zone or -zone, where zone is HHMM
353 
354  unsigned int year = 0;
355  unsigned int month = 0;
356  unsigned int mday = 0;
357  unsigned int hour = 0;
358  unsigned int min = 0;
359  unsigned int sec = 0;
360 
361  int offset = 0;
362 
363  QString input = input_;
364 
365  // First find the 'T' separator, if any.
366  int tPos = input.indexOf(QLatin1Char('T'));
367 
368  // If there is no time, no month or no day specified, fill those missing
369  // fields so that 'input' matches YYYY-MM-DDTHH:MM:SS
370  if (-1 == tPos) {
371  const int dashes = input.count('-');
372  if (0 == dashes) {
373  input += "-01-01";
374  } else if (1 == dashes) {
375  input += "-01";
376  }
377  tPos = input.length();
378  input += "T12:00:00";
379  }
380 
381  // Now parse the date part.
382 
383  QString dateString = input.left(tPos).trimmed();
384 
385  QString timeString = input.mid(tPos + 1).trimmed();
386 
387  QStringList l = dateString.split( '-');
388  if (l.size() < 3)
389  return 0;
390 
391  year = l[0].toUInt();
392  month = l[1].toUInt();
393  mday = l[2].toUInt();
394 
395  // Z suffix means UTC.
396  if ('Z' == timeString.at(timeString.length() - 1)) {
397  timeString.remove(timeString.length() - 1, 1);
398  }
399 
400  // +zone or -zone suffix (offset from UTC).
401 
402  int plusPos = timeString.lastIndexOf('+');
403 
404  if (-1 != plusPos) {
405  QString offsetString = timeString.mid(plusPos + 1);
406 
407  offset = offsetString.left(2).toUInt() * 60 + offsetString.right(2).toUInt();
408 
409  timeString = timeString.left(plusPos);
410  } else {
411  int minusPos = timeString.lastIndexOf('-');
412 
413  if (-1 != minusPos) {
414  QString offsetString = timeString.mid(minusPos + 1);
415 
416  offset = - int(offsetString.left(2).toUInt() * 60 + offsetString.right(2).toUInt());
417 
418  timeString = timeString.left(minusPos);
419  }
420  }
421 
422  // secfrac suffix.
423  int dotPos = timeString.lastIndexOf('.');
424 
425  if (-1 != dotPos) {
426  timeString = timeString.left(dotPos);
427  }
428 
429  // Now parse the time part.
430 
431  l = timeString.split( ':');
432  if (l.size() < 3)
433  return 0;
434 
435  hour = l[0].toUInt();
436  min = l[1].toUInt();
437  sec = l[2].toUInt();
438 
439  time_t result = ymdhms_to_seconds(year, month, mday, hour, min, sec);
440 
441  // avoid negative time values
442  if ((offset > 0) && (offset > result))
443  offset = 0;
444 
445  result -= offset*60;
446 
447  // If epoch 0 return epoch +1 which is Thu, 01-Jan-70 00:00:01 GMT
448  // This is so that parse error and valid epoch 0 return values won't
449  // be the same for sensitive applications...
450  if (result < 1) result = 1;
451 
452  return result;
453 }
454 
455 
456 int K3RFCDate::localUTCOffset()
457 {
458  time_t timeNow = time((time_t*) 0);
459 
460  tm *tM = gmtime(&timeNow);
461  unsigned int timeUTC = ymdhms_to_seconds(tM->tm_year+1900, tM->tm_mon+1, tM->tm_mday,
462  tM->tm_hour, tM->tm_min, tM->tm_sec);
463 
464  tM = localtime(&timeNow);
465  unsigned int timeLocal = ymdhms_to_seconds(tM->tm_year+1900, tM->tm_mon+1, tM->tm_mday,
466  tM->tm_hour, tM->tm_min, tM->tm_sec);
467 
468  return ((int)(timeLocal-timeUTC))/60;
469 }
470 
471 
472 static const char day_names[][4] = {
473  "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
474 };
475 
476 static const char month_names[][4] = {
477  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
478  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
479 };
480 
481 
482 QByteArray K3RFCDate::rfc2822DateString(time_t utcTime, int utcOffset)
483 {
484  utcTime += utcOffset * 60;
485  tm *tM = gmtime(&utcTime);
486  char sgn = (utcOffset < 0) ? '-' : '+';
487  int z = (utcOffset < 0) ? -utcOffset : utcOffset;
488  QByteArray dateStr;
489 
490  dateStr = QString().sprintf("%s, %02d %s %04d %02d:%02d:%02d %c%02d%02d",
491  day_names[tM->tm_wday], tM->tm_mday,
492  month_names[tM->tm_mon], tM->tm_year+1900,
493  tM->tm_hour, tM->tm_min, tM->tm_sec,
494  sgn, z/60%24, z%60).toLatin1();
495 
496  return dateStr;
497 }
tzName
const char tzName[4]
Definition: k3rfcdate.cpp:80
QString::indexOf
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
QByteArray
QString::split
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
K3RFCDate::parseDate
static time_t parseDate(const QString &date)
This function tries to parse a string containing a date/time in any of the formats specified by RFC82...
Definition: k3rfcdate.cpp:97
QString::remove
QString & remove(int position, int n)
QList::size
int size() const
QString::lastIndexOf
int lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
haystack
static const char haystack[37]
Definition: k3rfcdate.cpp:75
day_names
static const char day_names[][4]
Definition: k3rfcdate.cpp:472
k3rfcdate.h
QString::isEmpty
bool isEmpty() const
isspace
#define isspace(c)
QString::trimmed
QString trimmed() const
month_names
static const char month_names[][4]
Definition: k3rfcdate.cpp:476
tzOffset
int tzOffset
Definition: k3rfcdate.cpp:81
QString
QStringList
QString::right
QString right(int n) const
QLatin1Char
isalpha
#define isalpha(c)
QString::toLatin1
QByteArray toLatin1() const
QString::mid
QString mid(int position, int n) const
QString::count
int count() const
QString::sprintf
QString & sprintf(const char *cformat,...)
QString::at
const QChar at(int position) const
K3RFCDate::parseDateISO8601
static time_t parseDateISO8601(const QString &date)
This function tries to parse a string containing a date/time in any of the formats specified by http:...
Definition: k3rfcdate.cpp:343
QString::length
int length() const
QByteArray::data
char * data()
QString::left
QString left(int n) const
known_zones
static const struct @1 known_zones[]
K3RFCDate::localUTCOffset
static int localUTCOffset()
Returns the local timezone offset to UTC in minutes.
Definition: k3rfcdate.cpp:456
isdigit
#define isdigit(c)
ymdhms_to_seconds
static unsigned int ymdhms_to_seconds(int year, int mon, int day, int hour, int minute, int second)
Definition: k3rfcdate.cpp:33
K3RFCDate::rfc2822DateString
static QByteArray rfc2822DateString(time_t utcTime, int utcOffset=localUTCOffset())
Returns a string representation of the given date and time formated in conformance to RFC2822...
Definition: k3rfcdate.cpp:482
QString::toUInt
uint toUInt(bool *ok, int base) const
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:26:48 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDE3Support

Skip menu "KDE3Support"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • 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