• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

KDECore

krfcdate.cpp

Go to the documentation of this file.
00001 /*
00002  *
00003  *  This file is part of the KDE libraries
00004  *  Copyright (c) 2000-2002 Waldo Bastian <bastian@kde.org>
00005  *                2002 Rik Hemsley <rik@kde.org>
00006  *
00007  * $Id: krfcdate.cpp 514036 2006-02-27 09:36:44Z osterfeld $
00008  *
00009  *  This library is free software; you can redistribute it and/or
00010  *  modify it under the terms of the GNU Library General Public
00011  *  License version 2 as published by the Free Software Foundation.
00012  *
00013  *  This library is distributed in the hope that it will be useful,
00014  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  *  Library General Public License for more details.
00017  *
00018  *  You should have received a copy of the GNU Library General Public License
00019  *  along with this library; see the file COPYING.LIB.  If not, write to
00020  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00021  *  Boston, MA 02110-1301, USA.
00022  **/
00023 
00024 #include <config.h>
00025 
00026 #include <sys/param.h>
00027 #include <ctype.h>
00028 #include <stdlib.h>
00029 
00030 #include <qstringlist.h>
00031 
00032 #include <krfcdate.h>
00033 
00034 static unsigned int ymdhms_to_seconds(int year, int mon, int day, int hour, int minute, int second)
00035 {
00036     if (sizeof(time_t) == 4)
00037     {
00038        if ((time_t)-1 < 0)
00039        {
00040           if (year >= 2038)
00041           {
00042              year = 2038;
00043              mon = 0;
00044              day = 1;
00045              hour = 0;
00046              minute = 0;
00047              second = 0;
00048           }
00049        }
00050        else
00051        {
00052           if (year >= 2115)
00053           {
00054              year = 2115;
00055              mon = 0;
00056              day = 1;
00057              hour = 0;
00058              minute = 0;
00059              second = 0;
00060           }
00061        }
00062     }
00063 
00064     unsigned int ret = (day - 32075)       /* days */
00065             + 1461L * (year + 4800L + (mon - 14) / 12) / 4
00066             + 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12
00067             - 3 * ((year + 4900L + (mon - 14) / 12) / 100) / 4
00068             - 2440588;
00069     ret = 24*ret + hour;     /* hours   */
00070     ret = 60*ret + minute;   /* minutes */
00071     ret = 60*ret + second;   /* seconds */
00072 
00073     return ret;
00074 }
00075 
00076 static const char haystack[37]="janfebmaraprmayjunjulaugsepoctnovdec";
00077 
00078 // we follow the recommendation of rfc2822 to consider all
00079 // obsolete time zones not listed here equivalent to "-0000"
00080 static const struct {
00081     const char tzName[4];
00082     int tzOffset;
00083 } known_zones[] = {
00084     { "UT", 0 },
00085     { "GMT", 0 },
00086     { "EST", -300 },
00087     { "EDT", -240 },
00088     { "CST", -360 },
00089     { "CDT", -300 },
00090     { "MST", -420 },
00091     { "MDT", -360 },
00092     { "PST", -480 },
00093     { "PDT", -420 },
00094     { { 0,0,0,0 }, 0 }
00095 };
00096 
00097 time_t
00098 KRFCDate::parseDate(const QString &_date)
00099 {
00100      if (_date.isEmpty())
00101          return 0;
00102 
00103      // This parse a date in the form:
00104      //     Wednesday, 09-Nov-99 23:12:40 GMT
00105      // or
00106      //     Sat, 01-Jan-2000 08:00:00 GMT
00107      // or
00108      //     Sat, 01 Jan 2000 08:00:00 GMT
00109      // or
00110      //     01 Jan 99 22:00 +0100    (exceptions in rfc822/rfc2822)
00111      //
00112      // We ignore the weekday
00113      //
00114      time_t result = 0;
00115      int offset = 0;
00116      char *newPosStr;
00117      const char *dateString = _date.latin1();
00118      int day = 0;
00119      char monthStr[4];
00120      int month = -1;
00121      int year = 0;
00122      int hour = 0;
00123      int minute = 0;
00124      int second = 0;
00125 
00126      // Strip leading space
00127      while(*dateString && isspace(*dateString))
00128         dateString++;
00129 
00130      // Strip weekday
00131      while(*dateString && !isdigit(*dateString) && !isspace(*dateString))
00132         dateString++;
00133 
00134      // Strip trailing space
00135      while(*dateString && isspace(*dateString))
00136         dateString++;
00137 
00138      if (!*dateString)
00139         return result;  // Invalid date
00140 
00141      if (isalpha(*dateString))
00142      {
00143         // ' Nov 5 1994 18:15:30 GMT'
00144         // Strip leading space
00145         while(*dateString && isspace(*dateString))
00146            dateString++;
00147 
00148         for(int i=0; i < 3;i++)
00149         {
00150            if (!*dateString || (*dateString == '-') || isspace(*dateString))
00151               return result;  // Invalid date
00152            monthStr[i] = tolower(*dateString++);
00153         }
00154         monthStr[3] = '\0';
00155 
00156         newPosStr = (char*)strstr(haystack, monthStr);
00157 
00158         if (!newPosStr)
00159            return result;  // Invalid date
00160 
00161         month = (newPosStr-haystack)/3; // Jan=00, Feb=01, Mar=02, ..
00162 
00163         if ((month < 0) || (month > 11))
00164            return result;  // Invalid date
00165 
00166         while (*dateString && isalpha(*dateString))
00167            dateString++; // Skip rest of month-name
00168      }
00169 
00170      // ' 09-Nov-99 23:12:40 GMT'
00171      // ' 5 1994 18:15:30 GMT'
00172      day = strtol(dateString, &newPosStr, 10);
00173      dateString = newPosStr;
00174 
00175      if ((day < 1) || (day > 31))
00176          return result; // Invalid date;
00177 
00178      if (!*dateString)
00179         return result;  // Invalid date
00180 
00181      while(*dateString && (isspace(*dateString) || (*dateString == '-')))
00182         dateString++;
00183 
00184      if (month == -1)
00185      {
00186         for(int i=0; i < 3;i++)
00187         {
00188            if (!*dateString || (*dateString == '-') || isspace(*dateString))
00189               return result;  // Invalid date
00190            monthStr[i] = tolower(*dateString++);
00191         }
00192         monthStr[3] = '\0';
00193         
00194         newPosStr = (char*)strstr(haystack, monthStr);
00195 
00196         if (!newPosStr)
00197            return result;  // Invalid date
00198 
00199         month = (newPosStr-haystack)/3; // Jan=00, Feb=01, Mar=02, ..
00200 
00201         if ((month < 0) || (month > 11))
00202            return result;  // Invalid date
00203            
00204         while (*dateString && isalpha(*dateString))
00205            dateString++; // Skip rest of month-name
00206            
00207      }
00208 
00209      // '-99 23:12:40 GMT'
00210      while(*dateString && (isspace(*dateString) || (*dateString == '-')))
00211         dateString++;
00212 
00213      if (!*dateString || !isdigit(*dateString))
00214         return result;  // Invalid date
00215 
00216      // '99 23:12:40 GMT'
00217      year = strtol(dateString, &newPosStr, 10);
00218      dateString = newPosStr;
00219 
00220      // Y2K: Solve 2 digit years
00221      if ((year >= 0) && (year < 50))
00222          year += 2000;
00223 
00224      if ((year >= 50) && (year < 100))
00225          year += 1900;  // Y2K
00226 
00227      if ((year < 1900) || (year > 2500))
00228         return result; // Invalid date
00229 
00230      // Don't fail if the time is missing.
00231      if (*dateString)
00232      {
00233         // ' 23:12:40 GMT'
00234         if (!isspace(*dateString++))
00235            return result;  // Invalid date
00236 
00237         hour = strtol(dateString, &newPosStr, 10);
00238         dateString = newPosStr;
00239 
00240         if ((hour < 0) || (hour > 23))
00241            return result; // Invalid date
00242 
00243         if (!*dateString)
00244            return result;  // Invalid date
00245 
00246         // ':12:40 GMT'
00247         if (*dateString++ != ':')
00248            return result;  // Invalid date
00249 
00250         minute = strtol(dateString, &newPosStr, 10);
00251         dateString = newPosStr;
00252 
00253         if ((minute < 0) || (minute > 59))
00254            return result; // Invalid date
00255 
00256         if (!*dateString)
00257            return result;  // Invalid date
00258 
00259         // ':40 GMT'
00260         if (*dateString != ':' && !isspace(*dateString))
00261            return result;  // Invalid date
00262 
00263         // seconds are optional in rfc822 + rfc2822
00264         if (*dateString ==':') {
00265            dateString++;
00266 
00267            second = strtol(dateString, &newPosStr, 10);
00268            dateString = newPosStr;
00269 
00270            if ((second < 0) || (second > 59))
00271               return result; // Invalid date
00272         } else {
00273            dateString++;
00274         }
00275 
00276         while(*dateString && isspace(*dateString))
00277            dateString++;
00278      }
00279 
00280      // don't fail if the time zone is missing, some
00281      // broken mail-/news-clients omit the time zone
00282      if (*dateString) {
00283         if ((strncasecmp(dateString, "gmt", 3) == 0) ||
00284             (strncasecmp(dateString, "utc", 3) == 0))
00285         {
00286            dateString += 3;
00287            while(*dateString && isspace(*dateString))
00288               dateString++;
00289         }
00290 
00291         if ((*dateString == '+') || (*dateString == '-')) {
00292            offset = strtol(dateString, &newPosStr, 10);
00293            if (abs(offset) < 30)
00294            {
00295               dateString = newPosStr;
00296               
00297               offset = offset * 100;
00298               
00299               if (*dateString && *(dateString+1))
00300               {
00301                  dateString++;
00302                  int minutes = strtol(dateString, &newPosStr, 10);
00303                  if (offset > 0)
00304                     offset += minutes;
00305                  else
00306                     offset -= minutes;
00307               }
00308            }
00309 
00310            if ((offset < -9959) || (offset > 9959))
00311               return result; // Invalid date
00312 
00313            int sgn = (offset < 0)? -1:1;
00314            offset = abs(offset);
00315            offset = ((offset / 100)*60 + (offset % 100))*sgn;
00316         } else {
00317            for (int i=0; known_zones[i].tzName != 0; i++) {
00318               if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) {
00319                  offset = known_zones[i].tzOffset;
00320                  break;
00321               }
00322            }
00323         }
00324      }
00325 
00326      result = ymdhms_to_seconds(year, month+1, day, hour, minute, second);
00327 
00328      // avoid negative time values
00329      if ((offset > 0) && (offset > result))
00330         offset = 0;
00331 
00332      result -= offset*60;
00333 
00334      // If epoch 0 return epoch +1 which is Thu, 01-Jan-70 00:00:01 GMT
00335      // This is so that parse error and valid epoch 0 return values won't
00336      // be the same for sensitive applications...
00337      if (result < 1) result = 1;
00338 
00339      return result;
00340 }
00341 
00342 time_t
00343 KRFCDate::parseDateISO8601( const QString& input_ )
00344 {
00345   if (input_.isEmpty())
00346     return 0;
00347 
00348   // These dates look like this:
00349   // YYYY-MM-DDTHH:MM:SS
00350   // But they may also have 0, 1 or 2 suffixes.
00351   // Suffix 1: .secfrac (fraction of second)
00352   // Suffix 2: Either 'Z' or +zone or -zone, where zone is HHMM
00353 
00354   unsigned int year     = 0;
00355   unsigned int month    = 0;
00356   unsigned int mday     = 0;
00357   unsigned int hour     = 0;
00358   unsigned int min      = 0;
00359   unsigned int sec      = 0;
00360 
00361   int offset = 0;
00362 
00363   QString input = input_;
00364 
00365   // First find the 'T' separator, if any.
00366   int tPos = input.find('T');
00367 
00368   // If there is no time, no month or no day specified, fill those missing
00369   // fields so that 'input' matches YYYY-MM-DDTHH:MM:SS
00370   if (-1 == tPos) {
00371     const int dashes = input.contains('-');
00372     if (0 == dashes) {
00373       input += "-01-01";
00374     } else if (1 == dashes) {
00375       input += "-01";
00376     }
00377     tPos = input.length();
00378     input += "T12:00:00";
00379   }
00380 
00381   // Now parse the date part.
00382 
00383   QString dateString = input.left(tPos).stripWhiteSpace();
00384 
00385   QString timeString = input.mid(tPos + 1).stripWhiteSpace();
00386 
00387   QStringList l = QStringList::split('-', dateString);
00388 
00389   if (l.size() < 3)
00390     return 0;
00391 
00392   year   = l[0].toUInt();
00393   month  = l[1].toUInt();
00394   mday   = l[2].toUInt();
00395 
00396   // Z suffix means UTC.
00397   if ('Z' == timeString.at(timeString.length() - 1)) {
00398     timeString.remove(timeString.length() - 1, 1);
00399   }
00400 
00401   // +zone or -zone suffix (offset from UTC).
00402 
00403   int plusPos = timeString.findRev('+');
00404 
00405   if (-1 != plusPos) {
00406     QString offsetString = timeString.mid(plusPos + 1);
00407 
00408     offset = offsetString.left(2).toUInt() * 60 + offsetString.right(2).toUInt();
00409 
00410     timeString = timeString.left(plusPos);
00411   } else {
00412     int minusPos = timeString.findRev('-');
00413 
00414     if (-1 != minusPos) {
00415       QString offsetString = timeString.mid(minusPos + 1);
00416 
00417       offset = - int(offsetString.left(2).toUInt() * 60 + offsetString.right(2).toUInt());
00418 
00419       timeString = timeString.left(minusPos);
00420     }
00421   }
00422 
00423   // secfrac suffix.
00424   int dotPos = timeString.findRev('.');
00425 
00426   if (-1 != dotPos) {
00427     timeString = timeString.left(dotPos);
00428   }
00429 
00430   // Now parse the time part.
00431 
00432   l = QStringList::split(':', timeString);
00433 
00434   if (l.size() < 3)
00435     return 0;
00436 
00437   hour   = l[0].toUInt();
00438   min    = l[1].toUInt();
00439   sec    = l[2].toUInt();
00440 
00441   time_t result = ymdhms_to_seconds(year, month, mday, hour, min, sec);
00442 
00443   // avoid negative time values
00444   if ((offset > 0) && (offset > result))
00445      offset = 0;
00446 
00447   result -= offset*60;
00448 
00449   // If epoch 0 return epoch +1 which is Thu, 01-Jan-70 00:00:01 GMT
00450   // This is so that parse error and valid epoch 0 return values won't
00451   // be the same for sensitive applications...
00452   if (result < 1) result = 1;
00453 
00454   return result;
00455 }
00456 
00457 
00458 int KRFCDate::localUTCOffset()
00459 {
00460   time_t timeNow = time((time_t*) 0);
00461 
00462   tm *tM = gmtime(&timeNow);
00463   unsigned int timeUTC = ymdhms_to_seconds(tM->tm_year+1900, tM->tm_mon+1, tM->tm_mday,
00464                                            tM->tm_hour, tM->tm_min, tM->tm_sec);
00465 
00466   tM = localtime(&timeNow);
00467   unsigned int timeLocal = ymdhms_to_seconds(tM->tm_year+1900, tM->tm_mon+1, tM->tm_mday,
00468                                              tM->tm_hour, tM->tm_min, tM->tm_sec);
00469 
00470   return ((int)(timeLocal-timeUTC))/60;
00471 }
00472 
00473 
00474 static const char * const day_names[] = {
00475     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
00476 };
00477 
00478 static const char * const month_names[] = {
00479     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
00480     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
00481 };
00482 
00483 
00484 QCString KRFCDate::rfc2822DateString(time_t utcTime, int utcOffset)
00485 {
00486     utcTime += utcOffset * 60;
00487     tm *tM = gmtime(&utcTime);
00488     char sgn = (utcOffset < 0) ? '-' : '+';
00489     int z = (utcOffset < 0) ? -utcOffset : utcOffset;
00490     QCString dateStr;
00491 
00492     dateStr.sprintf("%s, %02d %s %04d %02d:%02d:%02d %c%02d%02d",
00493                     day_names[tM->tm_wday], tM->tm_mday,
00494                     month_names[tM->tm_mon], tM->tm_year+1900,
00495                     tM->tm_hour, tM->tm_min, tM->tm_sec,
00496                     sgn, z/60%24, z%60);
00497 
00498     return dateStr;
00499 }
00500 
00501 
00502 QCString KRFCDate::rfc2822DateString(time_t utcTime)
00503 {
00504     return rfc2822DateString(utcTime, localUTCOffset());
00505 }

KDECore

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

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal