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

KDE3Support

k3rfcdate.cpp

Go to the documentation of this file.
00001 /*
00002  *  This file is part of the KDE libraries
00003  *  Copyright (c) 2000-2002 Waldo Bastian <bastian@kde.org>
00004  *                2002 Rik Hemsley <rik@kde.org>
00005  *
00006  *  This library is free software; you can redistribute it and/or
00007  *  modify it under the terms of the GNU Library General Public
00008  *  License version 2 as published by the Free Software Foundation.
00009  *
00010  *  This library is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  *  Library General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU Library General Public License
00016  *  along with this library; see the file COPYING.LIB.  If not, write to
00017  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  *  Boston, MA 02110-1301, USA.
00019  **/
00020 
00021 #include "k3rfcdate.h"
00022 
00023 #include <config.h>
00024 
00025 #include <sys/param.h>
00026 #include <ctype.h>
00027 #include <stdlib.h>
00028 
00029 #include <QtCore/QMutableStringListIterator>
00030 #include <QtCore/QCharRef>
00031 #include <QtCore/QByteArray>
00032 
00033 static unsigned int ymdhms_to_seconds(int year, int mon, int day, int hour, int minute, int second)
00034 {
00035     if (sizeof(time_t) == 4)
00036     {
00037        if ((time_t)-1 < 0)
00038        {
00039           if (year >= 2038)
00040           {
00041              year = 2038;
00042              mon = 0;
00043              day = 1;
00044              hour = 0;
00045              minute = 0;
00046              second = 0;
00047           }
00048        }
00049        else
00050        {
00051           if (year >= 2115)
00052           {
00053              year = 2115;
00054              mon = 0;
00055              day = 1;
00056              hour = 0;
00057              minute = 0;
00058              second = 0;
00059           }
00060        }
00061     }
00062 
00063     unsigned int ret = (day - 32075)       /* days */
00064             + 1461L * (year + 4800L + (mon - 14) / 12) / 4
00065             + 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12
00066             - 3 * ((year + 4900L + (mon - 14) / 12) / 100) / 4
00067             - 2440588;
00068     ret = 24*ret + hour;     /* hours   */
00069     ret = 60*ret + minute;   /* minutes */
00070     ret = 60*ret + second;   /* seconds */
00071 
00072     return ret;
00073 }
00074 
00075 static const char haystack[37]="janfebmaraprmayjunjulaugsepoctnovdec";
00076 
00077 // we follow the recommendation of rfc2822 to consider all
00078 // obsolete time zones not listed here equivalent to "-0000"
00079 static const struct {
00080     const char tzName[4];
00081     int tzOffset;
00082 } known_zones[] = {
00083     { "UT", 0 },
00084     { "GMT", 0 },
00085     { "EST", -300 },
00086     { "EDT", -240 },
00087     { "CST", -360 },
00088     { "CDT", -300 },
00089     { "MST", -420 },
00090     { "MDT", -360 },
00091     { "PST", -480 },
00092     { "PDT", -420 },
00093     { { 0,0,0,0 }, 0 }
00094 };
00095 
00096 time_t
00097 K3RFCDate::parseDate(const QString &_date)
00098 {
00099      if (_date.isEmpty())
00100          return 0;
00101 
00102      // This parse a date in the form:
00103      //     Wednesday, 09-Nov-99 23:12:40 GMT
00104      // or
00105      //     Sat, 01-Jan-2000 08:00:00 GMT
00106      // or
00107      //     Sat, 01 Jan 2000 08:00:00 GMT
00108      // or
00109      //     01 Jan 99 22:00 +0100    (exceptions in rfc822/rfc2822)
00110      //
00111      // We ignore the weekday
00112      //
00113      time_t result = 0;
00114      int offset = 0;
00115      char *newPosStr;
00116      const QByteArray dateArray = _date.toLatin1();
00117      const char *dateString = dateArray.data();
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 K3RFCDate::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.indexOf(QLatin1Char('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.count('-');
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).trimmed();
00384 
00385   QString timeString = input.mid(tPos + 1).trimmed();
00386 
00387   QStringList l = dateString.split( '-');
00388   if (l.size() < 3)
00389     return 0;
00390   
00391   year   = l[0].toUInt();
00392   month  = l[1].toUInt();
00393   mday   = l[2].toUInt();
00394 
00395   // Z suffix means UTC.
00396   if ('Z' == timeString.at(timeString.length() - 1)) {
00397     timeString.remove(timeString.length() - 1, 1);
00398   }
00399 
00400   // +zone or -zone suffix (offset from UTC).
00401 
00402   int plusPos = timeString.lastIndexOf('+');
00403 
00404   if (-1 != plusPos) {
00405     QString offsetString = timeString.mid(plusPos + 1);
00406 
00407     offset = offsetString.left(2).toUInt() * 60 + offsetString.right(2).toUInt();
00408 
00409     timeString = timeString.left(plusPos);
00410   } else {
00411     int minusPos = timeString.lastIndexOf('-');
00412 
00413     if (-1 != minusPos) {
00414       QString offsetString = timeString.mid(minusPos + 1);
00415 
00416       offset = - int(offsetString.left(2).toUInt() * 60 + offsetString.right(2).toUInt());
00417 
00418       timeString = timeString.left(minusPos);
00419     }
00420   }
00421 
00422   // secfrac suffix.
00423   int dotPos = timeString.lastIndexOf('.');
00424 
00425   if (-1 != dotPos) {
00426     timeString = timeString.left(dotPos);
00427   }
00428 
00429   // Now parse the time part.
00430 
00431   l = timeString.split( ':');
00432   if (l.size() < 3)
00433     return 0;
00434       
00435   hour   = l[0].toUInt();
00436   min    = l[1].toUInt();
00437   sec    = l[2].toUInt();
00438 
00439   time_t result = ymdhms_to_seconds(year, month, mday, hour, min, sec);
00440 
00441   // avoid negative time values
00442   if ((offset > 0) && (offset > result))
00443      offset = 0;
00444 
00445   result -= offset*60;
00446 
00447   // If epoch 0 return epoch +1 which is Thu, 01-Jan-70 00:00:01 GMT
00448   // This is so that parse error and valid epoch 0 return values won't
00449   // be the same for sensitive applications...
00450   if (result < 1) result = 1;
00451 
00452   return result;
00453 }
00454 
00455 
00456 int K3RFCDate::localUTCOffset()
00457 {
00458   time_t timeNow = time((time_t*) 0);
00459 
00460   tm *tM = gmtime(&timeNow);
00461   unsigned int timeUTC = ymdhms_to_seconds(tM->tm_year+1900, tM->tm_mon+1, tM->tm_mday,
00462                                            tM->tm_hour, tM->tm_min, tM->tm_sec);
00463 
00464   tM = localtime(&timeNow);
00465   unsigned int timeLocal = ymdhms_to_seconds(tM->tm_year+1900, tM->tm_mon+1, tM->tm_mday,
00466                                              tM->tm_hour, tM->tm_min, tM->tm_sec);
00467 
00468   return ((int)(timeLocal-timeUTC))/60;
00469 }
00470 
00471 
00472 static const char day_names[][4] = {
00473     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
00474 };
00475 
00476 static const char month_names[][4] = {
00477     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
00478     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
00479 };
00480 
00481 
00482 QByteArray K3RFCDate::rfc2822DateString(time_t utcTime, int utcOffset)
00483 {
00484     utcTime += utcOffset * 60;
00485     tm *tM = gmtime(&utcTime);
00486     char sgn = (utcOffset < 0) ? '-' : '+';
00487     int z = (utcOffset < 0) ? -utcOffset : utcOffset;
00488     QByteArray dateStr;
00489 
00490     dateStr = QString().sprintf("%s, %02d %s %04d %02d:%02d:%02d %c%02d%02d",
00491                     day_names[tM->tm_wday], tM->tm_mday,
00492                     month_names[tM->tm_mon], tM->tm_year+1900,
00493                     tM->tm_hour, tM->tm_min, tM->tm_sec,
00494                     sgn, z/60%24, z%60).toAscii();
00495 
00496     return dateStr;
00497 }

KDE3Support

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
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