• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdecore
 

tdecore

  • tdecore
krfcdate.cpp
1/*
2 *
3 * This file is part of the KDE libraries
4 * Copyright (c) 2000-2002 Waldo Bastian <bastian@kde.org>
5 * 2002 Rik Hemsley <rik@kde.org>
6 *
7 * $Id$
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License version 2 as published by the Free Software Foundation.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 **/
23
24#include <config.h>
25
26#include <sys/param.h>
27#include <ctype.h>
28#include <stdlib.h>
29
30#include <tqstringlist.h>
31
32#include <krfcdate.h>
33
34static unsigned int ymdhms_to_seconds(int year, int mon, int day, int hour, int minute, int second)
35{
36 if (sizeof(time_t) == 4)
37 {
38 if ((time_t)-1 < 0)
39 {
40 if (year >= 2038)
41 {
42 year = 2038;
43 mon = 0;
44 day = 1;
45 hour = 0;
46 minute = 0;
47 second = 0;
48 }
49 }
50 else
51 {
52 if (year >= 2115)
53 {
54 year = 2115;
55 mon = 0;
56 day = 1;
57 hour = 0;
58 minute = 0;
59 second = 0;
60 }
61 }
62 }
63
64 unsigned int ret = (day - 32075) /* days */
65 + 1461L * (year + 4800L + (mon - 14) / 12) / 4
66 + 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12
67 - 3 * ((year + 4900L + (mon - 14) / 12) / 100) / 4
68 - 2440588;
69 ret = 24*ret + hour; /* hours */
70 ret = 60*ret + minute; /* minutes */
71 ret = 60*ret + second; /* seconds */
72
73 return ret;
74}
75
76static const char haystack[37]="janfebmaraprmayjunjulaugsepoctnovdec";
77
78// we follow the recommendation of rfc2822 to consider all
79// obsolete time zones not listed here equivalent to "-0000"
80static const struct {
81 const char tzName[4];
82 int tzOffset;
83} known_zones[] = {
84 { "UT", 0 },
85 { "GMT", 0 },
86 { "EST", -300 },
87 { "EDT", -240 },
88 { "CST", -360 },
89 { "CDT", -300 },
90 { "MST", -420 },
91 { "MDT", -360 },
92 { "PST", -480 },
93 { "PDT", -420 },
94 { { 0,0,0,0 }, 0 }
95};
96
97time_t
98KRFCDate::parseDate(const TQString &_date)
99{
100 if (_date.isEmpty())
101 return 0;
102
103 // This parse a date in the form:
104 // Wednesday, 09-Nov-99 23:12:40 GMT
105 // or
106 // Sat, 01-Jan-2000 08:00:00 GMT
107 // or
108 // Sat, 01 Jan 2000 08:00:00 GMT
109 // or
110 // 01 Jan 99 22:00 +0100 (exceptions in rfc822/rfc2822)
111 //
112 // We ignore the weekday
113 //
114 time_t result = 0;
115 int offset = 0;
116 char *newPosStr;
117 const char *dateString = _date.latin1();
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
343KRFCDate::parseDateISO8601( const TQString& 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 TQString input = input_;
364
365 // First find the 'T' separator, if any.
366 int tPos = input.find('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.contains('-');
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 TQString dateString = input.left(tPos).stripWhiteSpace();
384
385 TQString timeString = input.mid(tPos + 1).stripWhiteSpace();
386
387 TQStringList l = TQStringList::split('-', dateString);
388
389 if (l.size() < 3)
390 return 0;
391
392 year = l[0].toUInt();
393 month = l[1].toUInt();
394 mday = l[2].toUInt();
395
396 // Z suffix means UTC.
397 if ((TQChar)'Z' == timeString.at(timeString.length() - 1)) {
398 timeString.remove(timeString.length() - 1, 1);
399 }
400
401 // +zone or -zone suffix (offset from UTC).
402
403 int plusPos = timeString.findRev('+');
404
405 if (-1 != plusPos) {
406 TQString offsetString = timeString.mid(plusPos + 1);
407
408 offset = offsetString.left(2).toUInt() * 60 + offsetString.right(2).toUInt();
409
410 timeString = timeString.left(plusPos);
411 } else {
412 int minusPos = timeString.findRev('-');
413
414 if (-1 != minusPos) {
415 TQString offsetString = timeString.mid(minusPos + 1);
416
417 offset = - int(offsetString.left(2).toUInt() * 60 + offsetString.right(2).toUInt());
418
419 timeString = timeString.left(minusPos);
420 }
421 }
422
423 // secfrac suffix.
424 int dotPos = timeString.findRev('.');
425
426 if (-1 != dotPos) {
427 timeString = timeString.left(dotPos);
428 }
429
430 // Now parse the time part.
431
432 l = TQStringList::split(':', timeString);
433
434 // If the 'T' separator was included, there must at least
435 // be the hour, if not then it is invalid.
436 if (l.size() < 1)
437 return 0;
438
439 hour = l[0].toUInt();
440
441 // Minutes and seconds can be omitted.
442 min = (l.size() >= 2) ? l[1].toUInt() : 0;
443 sec = (l.size() >= 3) ? l[2].toUInt() : 0;
444
445 time_t result = ymdhms_to_seconds(year, month, mday, hour, min, sec);
446
447 // avoid negative time values
448 if ((offset > 0) && (offset > result))
449 offset = 0;
450
451 result -= offset*60;
452
453 // If epoch 0 return epoch +1 which is Thu, 01-Jan-70 00:00:01 GMT
454 // This is so that parse error and valid epoch 0 return values won't
455 // be the same for sensitive applications...
456 if (result < 1) result = 1;
457
458 return result;
459}
460
461
462int KRFCDate::localUTCOffset()
463{
464 time_t timeNow = time((time_t*) 0);
465
466 tm *tM = gmtime(&timeNow);
467 unsigned int timeUTC = ymdhms_to_seconds(tM->tm_year+1900, tM->tm_mon+1, tM->tm_mday,
468 tM->tm_hour, tM->tm_min, tM->tm_sec);
469
470 tM = localtime(&timeNow);
471 unsigned int timeLocal = ymdhms_to_seconds(tM->tm_year+1900, tM->tm_mon+1, tM->tm_mday,
472 tM->tm_hour, tM->tm_min, tM->tm_sec);
473
474 return ((int)(timeLocal-timeUTC))/60;
475}
476
477
478static const char * const day_names[] = {
479 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
480};
481
482static const char * const month_names[] = {
483 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
484 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
485};
486
487
488TQCString KRFCDate::rfc2822DateString(time_t utcTime, int utcOffset)
489{
490 utcTime += utcOffset * 60;
491 tm *tM = gmtime(&utcTime);
492 char sgn = (utcOffset < 0) ? '-' : '+';
493 int z = (utcOffset < 0) ? -utcOffset : utcOffset;
494 TQCString dateStr;
495
496 dateStr.sprintf("%s, %02d %s %04d %02d:%02d:%02d %c%02d%02d",
497 day_names[tM->tm_wday], tM->tm_mday,
498 month_names[tM->tm_mon], tM->tm_year+1900,
499 tM->tm_hour, tM->tm_min, tM->tm_sec,
500 sgn, z/60%24, z%60);
501
502 return dateStr;
503}
504
505
506TQCString KRFCDate::rfc2822DateString(time_t utcTime)
507{
508 return rfc2822DateString(utcTime, localUTCOffset());
509}
KRFCDate::rfc2822DateString
static TQCString rfc2822DateString(time_t utcTime, int utcOffset)
Returns a string representation of the given date and time formated in conformance to RFC2822.
Definition: krfcdate.cpp:488
KRFCDate::localUTCOffset
static int localUTCOffset()
Returns the local timezone offset to UTC in minutes.
Definition: krfcdate.cpp:462
KRFCDate::parseDateISO8601
static time_t parseDateISO8601(const TQString &date)
This function tries to parse a string containing a date/time in any of the formats specified by http:...
Definition: krfcdate.cpp:343
KRFCDate::parseDate
static time_t parseDate(const TQString &date)
This function tries to parse a string containing a date/time in any of the formats specified by RFC82...
Definition: krfcdate.cpp:98

tdecore

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

tdecore

Skip menu "tdecore"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdecore by doxygen 1.9.4
This website is maintained by Timothy Pearson.