# kdecore Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# krfcdate.cpp

    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 344656 2004-09-07 11:42:17Z staniek $
    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., 59 Temple Place - Suite 330,
    00021  *  Boston, MA 02111-1307, 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      // This parse a date in the form:
    00101      //     Wednesday, 09-Nov-99 23:12:40 GMT
    00102      // or
    00103      //     Sat, 01-Jan-2000 08:00:00 GMT
    00104      // or
    00105      //     Sat, 01 Jan 2000 08:00:00 GMT
    00106      // or
    00107      //     01 Jan 99 22:00 +0100    (exceptions in rfc822/rfc2822)
    00108      //
    00109      // We ignore the weekday
    00110      //
    00111      time_t result = 0;
    00112      int offset = 0;
    00113      char *newPosStr;
    00114      const char *dateString = _date.latin1();
    00115      int day = 0;
    00116      char monthStr[4];
    00117      int month = -1;
    00118      int year = 0;
    00119      int hour = 0;
    00120      int minute = 0;
    00121      int second = 0;
    00122
    00123      // Strip leading space
    00124      while(*dateString && isspace(*dateString))
    00125         dateString++;
    00126
    00127      // Strip weekday
    00128      while(*dateString && !isdigit(*dateString) && !isspace(*dateString))
    00129         dateString++;
    00130
    00131      // Strip trailing space
    00132      while(*dateString && isspace(*dateString))
    00133         dateString++;
    00134
    00135      if (!*dateString)
    00136         return result;  // Invalid date
    00137
    00138      if (isalpha(*dateString))
    00139      {
    00140         // ' Nov 5 1994 18:15:30 GMT'
    00141         // Strip leading space
    00142         while(*dateString && isspace(*dateString))
    00143            dateString++;
    00144
    00145         for(int i=0; i < 3;i++)
    00146         {
    00147            if (!*dateString || (*dateString == '-') || isspace(*dateString))
    00148               return result;  // Invalid date
    00149            monthStr[i] = tolower(*dateString++);
    00150         }
    00151         monthStr[3] = '\0';
    00152
    00153         newPosStr = (char*)strstr(haystack, monthStr);
    00154
    00155         if (!newPosStr)
    00156            return result;  // Invalid date
    00157
    00158         month = (newPosStr-haystack)/3; // Jan=00, Feb=01, Mar=02, ..
    00159
    00160         if ((month < 0) || (month > 11))
    00161            return result;  // Invalid date
    00162
    00163         while (*dateString && isalpha(*dateString))
    00164            dateString++; // Skip rest of month-name
    00165      }
    00166
    00167      // ' 09-Nov-99 23:12:40 GMT'
    00168      // ' 5 1994 18:15:30 GMT'
    00169      day = strtol(dateString, &newPosStr, 10);
    00170      dateString = newPosStr;
    00171
    00172      if ((day < 1) || (day > 31))
    00173          return result; // Invalid date;
    00174
    00175      if (!*dateString)
    00176         return result;  // Invalid date
    00177
    00178      while(*dateString && (isspace(*dateString) || (*dateString == '-')))
    00179         dateString++;
    00180
    00181      if (month == -1)
    00182      {
    00183         for(int i=0; i < 3;i++)
    00184         {
    00185            if (!*dateString || (*dateString == '-') || isspace(*dateString))
    00186               return result;  // Invalid date
    00187            monthStr[i] = tolower(*dateString++);
    00188         }
    00189         monthStr[3] = '\0';
    00190
    00191         newPosStr = (char*)strstr(haystack, monthStr);
    00192
    00193         if (!newPosStr)
    00194            return result;  // Invalid date
    00195
    00196         month = (newPosStr-haystack)/3; // Jan=00, Feb=01, Mar=02, ..
    00197
    00198         if ((month < 0) || (month > 11))
    00199            return result;  // Invalid date
    00200
    00201         while (*dateString && isalpha(*dateString))
    00202            dateString++; // Skip rest of month-name
    00203
    00204      }
    00205
    00206      // '-99 23:12:40 GMT'
    00207      while(*dateString && (isspace(*dateString) || (*dateString == '-')))
    00208         dateString++;
    00209
    00210      if (!*dateString || !isdigit(*dateString))
    00211         return result;  // Invalid date
    00212
    00213      // '99 23:12:40 GMT'
    00214      year = strtol(dateString, &newPosStr, 10);
    00215      dateString = newPosStr;
    00216
    00217      // Y2K: Solve 2 digit years
    00218      if ((year >= 0) && (year < 50))
    00219          year += 2000;
    00220
    00221      if ((year >= 50) && (year < 100))
    00222          year += 1900;  // Y2K
    00223
    00224      if ((year < 1900) || (year > 2500))
    00225         return result; // Invalid date
    00226
    00227      // Don't fail if the time is missing.
    00228      if (*dateString)
    00229      {
    00230         // ' 23:12:40 GMT'
    00231         if (!isspace(*dateString++))
    00232            return result;  // Invalid date
    00233
    00234         hour = strtol(dateString, &newPosStr, 10);
    00235         dateString = newPosStr;
    00236
    00237         if ((hour < 0) || (hour > 23))
    00238            return result; // Invalid date
    00239
    00240         if (!*dateString)
    00241            return result;  // Invalid date
    00242
    00243         // ':12:40 GMT'
    00244         if (*dateString++ != ':')
    00245            return result;  // Invalid date
    00246
    00247         minute = strtol(dateString, &newPosStr, 10);
    00248         dateString = newPosStr;
    00249
    00250         if ((minute < 0) || (minute > 59))
    00251            return result; // Invalid date
    00252
    00253         if (!*dateString)
    00254            return result;  // Invalid date
    00255
    00256         // ':40 GMT'
    00257         if (*dateString != ':' && !isspace(*dateString))
    00258            return result;  // Invalid date
    00259
    00260         // seconds are optional in rfc822 + rfc2822
    00261         if (*dateString ==':') {
    00262            dateString++;
    00263
    00264            second = strtol(dateString, &newPosStr, 10);
    00265            dateString = newPosStr;
    00266
    00267            if ((second < 0) || (second > 59))
    00268               return result; // Invalid date
    00269         } else {
    00270            dateString++;
    00271         }
    00272
    00273         while(*dateString && isspace(*dateString))
    00274            dateString++;
    00275      }
    00276
    00277      // don't fail if the time zone is missing, some
    00278      // broken mail-/news-clients omit the time zone
    00279      if (*dateString) {
    00280         if ((strncasecmp(dateString, "gmt", 3) == 0) ||
    00281             (strncasecmp(dateString, "utc", 3) == 0))
    00282         {
    00283            dateString += 3;
    00284            while(*dateString && isspace(*dateString))
    00285               dateString++;
    00286         }
    00287
    00288         if ((*dateString == '+') || (*dateString == '-')) {
    00289            offset = strtol(dateString, &newPosStr, 10);
    00290            if (abs(offset) < 30)
    00291            {
    00292               dateString = newPosStr;
    00293
    00294               offset = offset * 100;
    00295
    00296               if (*dateString && *(dateString+1))
    00297               {
    00298                  dateString++;
    00299                  int minutes = strtol(dateString, &newPosStr, 10);
    00300                  if (offset > 0)
    00301                     offset += minutes;
    00302                  else
    00303                     offset -= minutes;
    00304               }
    00305            }
    00306
    00307            if ((offset < -9959) || (offset > 9959))
    00308               return result; // Invalid date
    00309
    00310            int sgn = (offset < 0)? -1:1;
    00311            offset = abs(offset);
    00312            offset = ((offset / 100)*60 + (offset % 100))*sgn;
    00313         } else {
    00314            for (int i=0; known_zones[i].tzName != 0; i++) {
    00315               if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) {
    00316                  offset = known_zones[i].tzOffset;
    00317                  break;
    00318               }
    00319            }
    00320         }
    00321      }
    00322
    00323      result = ymdhms_to_seconds(year, month+1, day, hour, minute, second);
    00324
    00325      // avoid negative time values
    00326      if ((offset > 0) && (offset > result))
    00327         offset = 0;
    00328
    00329      result -= offset*60;
    00330
    00331      // If epoch 0 return epoch +1 which is Thu, 01-Jan-70 00:00:01 GMT
    00332      // This is so that parse error and valid epoch 0 return values won't
    00333      // be the same for sensitive applications...
    00334      if (result < 1) result = 1;
    00335
    00336      return result;
    00337 }
    00338
    00339 time_t
    00340 KRFCDate::parseDateISO8601( const QString& input_ )
    00341 {
    00342   // These dates look like this:
    00343   // YYYY-MM-DDTHH:MM:SS
    00344   // But they may also have 0, 1 or 2 suffixes.
    00345   // Suffix 1: .secfrac (fraction of second)
    00346   // Suffix 2: Either 'Z' or +zone or -zone, where zone is HHMM
    00347
    00348   unsigned int year     = 0;
    00349   unsigned int month    = 0;
    00350   unsigned int mday     = 0;
    00351   unsigned int hour     = 0;
    00352   unsigned int min      = 0;
    00353   unsigned int sec      = 0;
    00354
    00355   int offset = 0;
    00356
    00357   QString input = input_;
    00358
    00359   // First find the 'T' separator, if any.
    00360   int tPos = input.find('T');
    00361
    00362   // If there is no time, no month or no day specified, fill those missing
    00363   // fields so that 'input' matches YYYY-MM-DDTHH:MM:SS
    00364   if (-1 == tPos) {
    00365     const int dashes = input.contains('-');
    00366     if (0 == dashes) {
    00367       input += "-01-01";
    00368     } else if (1 == dashes) {
    00369       input += "-01";
    00370     }
    00371     tPos = input.length();
    00372     input += "T12:00:00";
    00373   }
    00374
    00375   // Now parse the date part.
    00376
    00377   QString dateString = input.left(tPos).stripWhiteSpace();
    00378
    00379   QString timeString = input.mid(tPos + 1).stripWhiteSpace();
    00380
    00381   QStringList l = QStringList::split('-', dateString);
    00382
    00383   year   = l[0].toUInt();
    00384   month  = l[1].toUInt();
    00385   mday   = l[2].toUInt();
    00386
    00387   // Z suffix means UTC.
    00388   if ('Z' == timeString.at(timeString.length() - 1)) {
    00389     timeString.remove(timeString.length() - 1, 1);
    00390   }
    00391
    00392   // +zone or -zone suffix (offset from UTC).
    00393
    00394   int plusPos = timeString.findRev('+');
    00395
    00396   if (-1 != plusPos) {
    00397     QString offsetString = timeString.mid(plusPos + 1);
    00398
    00399     offset = offsetString.left(2).toUInt() * 60 + offsetString.right(2).toUInt();
    00400
    00401     timeString = timeString.left(plusPos);
    00402   } else {
    00403     int minusPos = timeString.findRev('-');
    00404
    00405     if (-1 != minusPos) {
    00406       QString offsetString = timeString.mid(minusPos + 1);
    00407
    00408       offset = - int(offsetString.left(2).toUInt() * 60 + offsetString.right(2).toUInt());
    00409
    00410       timeString = timeString.left(minusPos);
    00411     }
    00412   }
    00413
    00414   // secfrac suffix.
    00415   int dotPos = timeString.findRev('.');
    00416
    00417   if (-1 != dotPos) {
    00418     timeString = timeString.left(dotPos);
    00419   }
    00420
    00421   // Now parse the time part.
    00422
    00423   l = QStringList::split(':', timeString);
    00424
    00425   hour   = l[0].toUInt();
    00426   min    = l[1].toUInt();
    00427   sec    = l[2].toUInt();
    00428
    00429   time_t result = ymdhms_to_seconds(year, month, mday, hour, min, sec);
    00430
    00431   // avoid negative time values
    00432   if ((offset > 0) && (offset > result))
    00433      offset = 0;
    00434
    00435   result -= offset*60;
    00436
    00437   // If epoch 0 return epoch +1 which is Thu, 01-Jan-70 00:00:01 GMT
    00438   // This is so that parse error and valid epoch 0 return values won't
    00439   // be the same for sensitive applications...
    00440   if (result < 1) result = 1;
    00441
    00442   return result;
    00443 }
    00444
    00445
    00446 int KRFCDate::localUTCOffset()
    00447 {
    00448   time_t timeNow = time((time_t*) 0);
    00449
    00450   tm *tM = gmtime(&timeNow);
    00451   unsigned int timeUTC = ymdhms_to_seconds(tM->tm_year+1900, tM->tm_mon+1, tM->tm_mday,
    00452                                            tM->tm_hour, tM->tm_min, tM->tm_sec);
    00453
    00454   tM = localtime(&timeNow);
    00455   unsigned int timeLocal = ymdhms_to_seconds(tM->tm_year+1900, tM->tm_mon+1, tM->tm_mday,
    00456                                              tM->tm_hour, tM->tm_min, tM->tm_sec);
    00457
    00458   return ((int)(timeLocal-timeUTC))/60;
    00459 }
    00460
    00461
    00462 static const char * const day_names[] = {
    00463     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
    00464 };
    00465
    00466 static const char * const month_names[] = {
    00467     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    00468     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
    00469 };
    00470
    00471
    00472 QCString KRFCDate::rfc2822DateString(time_t utcTime, int utcOffset)
    00473 {
    00474     utcTime += utcOffset * 60;
    00475     tm *tM = gmtime(&utcTime);
    00476     char sgn = (utcOffset < 0) ? '-' : '+';
    00477     int z = (utcOffset < 0) ? -utcOffset : utcOffset;
    00478     QCString dateStr;
    00479
    00480     dateStr.sprintf("%s, %02d %s %04d %02d:%02d:%02d %c%02d%02d",
    00481                     day_names[tM->tm_wday], tM->tm_mday,
    00482                     month_names[tM->tm_mon], tM->tm_year+1900,
    00483                     tM->tm_hour, tM->tm_min, tM->tm_sec,
    00484                     sgn, z/60%24, z%60);
    00485
    00486     return dateStr;
    00487 }
    00488
    00489
    00490 QCString KRFCDate::rfc2822DateString(time_t utcTime)
    00491 {
    00492     return rfc2822DateString(utcTime, localUTCOffset());
    00493 }

This file is part of the documentation for kdecore Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:18:10 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003