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

KDE3Support

  • 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
33static 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
75static 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"
79static 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
96time_t
97K3RFCDate::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
342time_t
343K3RFCDate::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
456int 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
472static const char day_names[][4] = {
473 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
474};
475
476static const char month_names[][4] = {
477 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
478 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
479};
480
481
482QByteArray 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}
K3RFCDate::localUTCOffset
static int localUTCOffset()
Returns the local timezone offset to UTC in minutes.
Definition: k3rfcdate.cpp:456
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
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
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
isspace
#define isspace(c)
isalpha
#define isalpha(c)
isdigit
#define isdigit(c)
tzName
const char tzName[4]
Definition: k3rfcdate.cpp:80
known_zones
static const struct @1 known_zones[]
month_names
static const char month_names[][4]
Definition: k3rfcdate.cpp:476
tzOffset
int tzOffset
Definition: k3rfcdate.cpp:81
haystack
static const char haystack[37]
Definition: k3rfcdate.cpp:75
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
day_names
static const char day_names[][4]
Definition: k3rfcdate.cpp:472
k3rfcdate.h
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

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-4.14.38 API Reference

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

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