• 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 
34 static 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 
76 static 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"
80 static 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 
97 time_t
98 KRFCDate::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 
342 time_t
343 KRFCDate::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 (l.size() < 3)
435  return 0;
436 
437  hour = l[0].toUInt();
438  min = l[1].toUInt();
439  sec = l[2].toUInt();
440 
441  time_t result = ymdhms_to_seconds(year, month, mday, hour, min, sec);
442 
443  // avoid negative time values
444  if ((offset > 0) && (offset > result))
445  offset = 0;
446 
447  result -= offset*60;
448 
449  // If epoch 0 return epoch +1 which is Thu, 01-Jan-70 00:00:01 GMT
450  // This is so that parse error and valid epoch 0 return values won't
451  // be the same for sensitive applications...
452  if (result < 1) result = 1;
453 
454  return result;
455 }
456 
457 
458 int KRFCDate::localUTCOffset()
459 {
460  time_t timeNow = time((time_t*) 0);
461 
462  tm *tM = gmtime(&timeNow);
463  unsigned int timeUTC = ymdhms_to_seconds(tM->tm_year+1900, tM->tm_mon+1, tM->tm_mday,
464  tM->tm_hour, tM->tm_min, tM->tm_sec);
465 
466  tM = localtime(&timeNow);
467  unsigned int timeLocal = 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  return ((int)(timeLocal-timeUTC))/60;
471 }
472 
473 
474 static const char * const day_names[] = {
475  "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
476 };
477 
478 static const char * const month_names[] = {
479  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
480  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
481 };
482 
483 
484 TQCString KRFCDate::rfc2822DateString(time_t utcTime, int utcOffset)
485 {
486  utcTime += utcOffset * 60;
487  tm *tM = gmtime(&utcTime);
488  char sgn = (utcOffset < 0) ? '-' : '+';
489  int z = (utcOffset < 0) ? -utcOffset : utcOffset;
490  TQCString dateStr;
491 
492  dateStr.sprintf("%s, %02d %s %04d %02d:%02d:%02d %c%02d%02d",
493  day_names[tM->tm_wday], tM->tm_mday,
494  month_names[tM->tm_mon], tM->tm_year+1900,
495  tM->tm_hour, tM->tm_min, tM->tm_sec,
496  sgn, z/60%24, z%60);
497 
498  return dateStr;
499 }
500 
501 
502 TQCString KRFCDate::rfc2822DateString(time_t utcTime)
503 {
504  return rfc2822DateString(utcTime, localUTCOffset());
505 }
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:484
KRFCDate::localUTCOffset
static int localUTCOffset()
Returns the local timezone offset to UTC in minutes.
Definition: krfcdate.cpp:458
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.1
This website is maintained by Timothy Pearson.