krfcdate.cpp Source File (kdecore Library)

| # kdecore Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | 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,v 1.16 2002/10/07 01:07:45 maragato Exp $
    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;
    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 }
    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   // First find the 'T' separator.
    00358   int tPos = input.find('T');
    00359
    00360   if (-1 == tPos)
    00361     return 0;
    00362
    00363   // Now parse the date part.
    00364
    00365   QString dateString = input.left(tPos).stripWhiteSpace();
    00366
    00367   QString timeString = input.mid(tPos + 1).stripWhiteSpace();
    00368
    00369   QStringList l = QStringList::split('-', dateString);
    00370
    00371   year   = l[0].toUInt();
    00372   month  = l[1].toUInt();
    00373   mday   = l[2].toUInt();
    00374
    00375   // Z suffix means UTC.
    00376   if ('Z' == timeString.at(timeString.length() - 1)) {
    00377     timeString.remove(timeString.length() - 1, 1);
    00378   }
    00379
    00380   // +zone or -zone suffix (offset from UTC).
    00381
    00382   int plusPos = timeString.findRev('+');
    00383
    00384   if (-1 != plusPos) {
    00385     QString offsetString = timeString.mid(plusPos + 1);
    00386
    00387     offset = offsetString.left(2).toUInt() * 60 + offsetString.right(2).toUInt();
    00388
    00389     timeString = timeString.left(plusPos);
    00390   } else {
    00391     int minusPos = timeString.findRev('-');
    00392
    00393     if (-1 != minusPos) {
    00394       QString offsetString = timeString.mid(minusPos + 1);
    00395
    00396       offset = - (offsetString.left(2).toUInt() * 60 + offsetString.right(2).toUInt());
    00397
    00398       timeString = timeString.left(minusPos);
    00399     }
    00400   }
    00401
    00402   // secfrac suffix.
    00403   int dotPos = timeString.findRev('.');
    00404
    00405   if (-1 != dotPos) {
    00406     timeString = timeString.left(dotPos);
    00407   }
    00408
    00409   // Now parse the time part.
    00410
    00411   l = QStringList::split(':', timeString);
    00412
    00413   hour   = l[0].toUInt();
    00414   min    = l[1].toUInt();
    00415   sec    = l[2].toUInt();
    00416
    00417   time_t result = ymdhms_to_seconds(year, month, mday, hour, min, sec);
    00418
    00419   // avoid negative time values
    00420   if ((offset > 0) && (offset > result))
    00421      offset = 0;
    00422
    00423   result -= offset*60;
    00424
    00425   // If epoch 0 return epoch +1 which is Thu, 01-Jan-70 00:00:01 GMT
    00426   // This is so that parse error and valid epoch 0 return values won't
    00427   // be the same for sensitive applications...
    00428   if (result < 1) result = 1;
    00429
    00430   return result;
    00431 }
    00432
    00433
    00434 int KRFCDate::localUTCOffset()
    00435 {
    00436   time_t timeNow = time((time_t*) 0);
    00437
    00438   tm *tM = gmtime(&timeNow);
    00439   unsigned int timeUTC = ymdhms_to_seconds(tM->tm_year+1900, tM->tm_mon+1, tM->tm_mday,
    00440                                            tM->tm_hour, tM->tm_min, tM->tm_sec);
    00441
    00442   tM = localtime(&timeNow);
    00443   unsigned int timeLocal = ymdhms_to_seconds(tM->tm_year+1900, tM->tm_mon+1, tM->tm_mday,
    00444                                              tM->tm_hour, tM->tm_min, tM->tm_sec);
    00445
    00446   return ((int)(timeLocal-timeUTC))/60;
    00447 }
    00448
    00449
    00450 static const char * const day_names[] = {
    00451     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
    00452 };
    00453
    00454 static const char * const month_names[] = {
    00455     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    00456     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
    00457 };
    00458
    00459
    00460 QCString KRFCDate::rfc2822DateString(time_t utcTime, int utcOffset)
    00461 {
    00462     utcTime += utcOffset * 60;
    00463     tm *tM = gmtime(&utcTime);
    00464     char sgn = (utcOffset < 0) ? '-' : '+';
    00465     int z = (utcOffset < 0) ? -utcOffset : utcOffset;
    00466     QCString dateStr;
    00467
    00468     dateStr.sprintf("%s, %02d %s %04d %02d:%02d:%02d %c%02d%02d",
    00469                     day_names[tM->tm_wday], tM->tm_mday,
    00470                     month_names[tM->tm_mon], tM->tm_year+1900,
    00471                     tM->tm_hour, tM->tm_min, tM->tm_sec,
    00472                     sgn, z/60%24, z%60);
    00473
    00474     return dateStr;
    00475 }
    00476
    00477
    00478 QCString KRFCDate::rfc2822DateString(time_t utcTime)
    00479 {
    00480     return rfc2822DateString(utcTime, localUTCOffset());
    00481 }

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 12:46:49 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001