PLearn 0.1
PDate.cc
Go to the documentation of this file.
00001 // -*- C++ -*-
00002 
00003 // PLearn (A C++ Machine Learning Library)
00004 // Copyright (C) 1998 Pascal Vincent
00005 // Copyright (C) 1999-2002 Pascal Vincent, Yoshua Bengio and University of Montreal
00006 //
00007 
00008 // Redistribution and use in source and binary forms, with or without
00009 // modification, are permitted provided that the following conditions are met:
00010 // 
00011 //  1. Redistributions of source code must retain the above copyright
00012 //     notice, this list of conditions and the following disclaimer.
00013 // 
00014 //  2. Redistributions in binary form must reproduce the above copyright
00015 //     notice, this list of conditions and the following disclaimer in the
00016 //     documentation and/or other materials provided with the distribution.
00017 // 
00018 //  3. The name of the authors may not be used to endorse or promote
00019 //     products derived from this software without specific prior written
00020 //     permission.
00021 // 
00022 // THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
00023 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00024 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
00025 // NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00026 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
00027 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00028 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00029 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00030 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00031 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00032 // 
00033 // This file is part of the PLearn library. For more information on the PLearn
00034 // library, go to the PLearn Web site at www.plearn.org
00035 
00036 /* *******************************************************      
00037  * $Id: PDate.cc 9203 2008-07-03 16:39:04Z nouiz $
00038  * This file is part of the PLearn library.
00039  ******************************************************* */
00040 
00041 //#include <limits.h>                 // from stdc
00042 #include "PDate.h"
00043 #include <algorithm>                
00044 #include "stringutils.h"            
00045 #include <plearn/base/tostring.h>  
00046 //#include "general.h"                // for MISSING_VALUE
00047 #include <plearn/math/pl_math.h>                
00048 //#include <ctype.h>
00049 
00050 namespace PLearn {
00051 using namespace std;
00052 
00053 
00054 
00055 //#####  Static Methods  ######################################################
00056 
00057 PDate PDate::lastDateOfMonth(int year, int month)
00058 {
00059     PDate date = PDate(year, month, int(lastDayOfMonth(year, month)));
00060     PLASSERT( date.isValid() );
00061     return date;
00062 }
00063 
00064 unsigned char PDate::lastDayOfMonth(int year, int month)
00065 {
00066     unsigned char day = 28;
00067     switch ( month ) {
00068     case 1: case 3: case 5: case 7: case 8: case 10: case 12:
00069         day = 31;
00070         break;
00071         
00072     case 4: case 6: case 9: case 11:
00073         day = 30;
00074         break;
00075 
00076     case 2:
00077         day = 28;
00078         if ( year %  4  == 0 ) day = 29;
00079         if ( year % 100 == 0 ) day = 28;
00080         if ( year % 400 == 0 ) day = 29;
00081         break;
00082 
00083     default:
00084         PLERROR("%s: Invalid month argument %d", __FUNCTION__, month);
00085     }
00086 
00087     return day;
00088 }
00089 
00090 
00091 //#####  Instance Methods  ####################################################
00092 
00093 PDate::PDate()
00094 {
00095     setMissing();
00096 }
00097 
00098 PDate::PDate(int julian_day)
00099 {
00100     int jw = (int)((julian_day - 1867216.25)/36524.25);
00101     int jx = (int)(jw/4);
00102     int ja = julian_day + 1 + jw - jx;
00103     int jb = ja + 1524;
00104     int jc = (int)((jb - 122.1)/365.25);
00105     int jd = (int)(365.25*jc);
00106     int je = (int)((jb - jd)/30.6001);
00107     int jf = (int)(30.6001*je);
00108  
00109     day = jb - jd - jf;
00110     month = (je>13) ? je-13 : je-1;
00111     year = (month>2) ? jc-4716 : jc-4715;
00112     PLASSERT( isValid() );
00113 }
00114 
00115 PDate::PDate(string date,bool invalid_value_as_missing)
00116 {
00117     date = removeblanks(date);
00118     search_replace(date, "-", "");      // remove dashes
00119 
00120     // Format "2003/01/27"
00121     if (date.size() == 10 && date[4] == '/' && date[7] == '/') 
00122     {
00123         year = (short)toint(date.substr(0,4));
00124         month = (unsigned char)toint(date.substr(5,2));
00125         day = (unsigned char)toint(date.substr(8,2));
00126     }
00127     // Format "27JAN2003" or "27-jan-2003" or "27-jan-03"
00128     else if((date.size()==9 || date.size()==7)
00129             && isalpha(date[2]) && isalpha(date[3]) && isalpha(date[4]))
00130     {
00131         // Convert to YYYY; assume cutoff point of 39 for years in 2000
00132         if (date.size() == 7) {
00133             int yy = toint(date.substr(5));
00134             int yyyy = -1;
00135             if (yy <= 40)
00136                 yyyy = 2000 + yy;
00137             else
00138                 yyyy = 1900 + yy;
00139             date = date.substr(0,5) + tostring(yyyy);
00140         }
00141       
00142         year = toint(date.substr(5,4));
00143         day = toint(date.substr(0,2));
00144         string mo = date.substr(2,3);
00145         // Make uppercase
00146         std::transform(mo.begin(), mo.end(), mo.begin(), (int(*)(int)) toupper);
00147 
00148         if(mo=="JAN")
00149             month = 1;
00150         else if(mo=="FEB")
00151             month = 2;
00152         else if(mo=="MAR")
00153             month = 3;
00154         else if(mo=="APR")
00155             month = 4;
00156         else if(mo=="MAY")
00157             month = 5;
00158         else if(mo=="JUN")
00159             month = 6;
00160         else if(mo=="JUL")
00161             month = 7;
00162         else if(mo=="AUG")
00163             month = 8;
00164         else if(mo=="SEP")
00165             month = 9;
00166         else if(mo=="OCT")
00167             month = 10;
00168         else if(mo=="NOV")
00169             month = 11;
00170         else if(mo=="DEC")
00171             month = 12;
00172         else if(invalid_value_as_missing)
00173             setMissing();
00174         else
00175             PLERROR("Invalid month string: '%s'",mo.c_str());
00176     }
00177 
00178     // Format "20020917"
00179     else if (date.size() == 8 && pl_isnumber(date))
00180     {
00181         year = toint(date.substr(0,4));
00182         month = toint(date.substr(4,2));
00183         day = toint(date.substr(6,2));
00184     }
00185 
00186     // Format 1020917  (102 stands for 2002)
00187     else if (date.size()==7 && pl_isnumber(date))
00188     {
00189         year = 1900+toint(date.substr(0,3));
00190         month = toint(date.substr(3,2));
00191         day = toint(date.substr(5,2));
00192     }
00193     // Format 980917  (99 stands for 1998)
00194     else if (date.size()==6 && pl_isnumber(date))
00195     {
00196         year = 1900+toint(date.substr(0,2));
00197         month = toint(date.substr(2,2));
00198         day = toint(date.substr(4,2));
00199     }
00200     else if(invalid_value_as_missing)
00201         setMissing();
00202     else
00203         PLERROR("PDate::PDate: the passed date string is not in a known format: %s", date.c_str());
00204 
00205     if( !isValid() ){
00206         if(invalid_value_as_missing){
00207             setMissing();
00208             PLWARNING("Invalid date string: %s",date.c_str());
00209         }else
00210             PLERROR("Invalid date string: %s",date.c_str());
00211     }
00212 }
00213 
00214 bool PDate::isMissing() const
00215 {
00216     return year == SHRT_MIN && month == 0 && day == 0;
00217 }
00218 
00219 void PDate::setMissing()
00220 {
00221     year = SHRT_MIN;
00222     month = 0;
00223     day = 0;
00224 }  
00225 
00226 bool PDate::isValid() const
00227 {
00228     // Managing leap years
00229     if (month==2 && day==29)
00230     {
00231         bool valid = false;
00232         if ( year %  4  == 0 ) valid = true;
00233         if ( year % 100 == 0 ) valid = false;
00234         if ( year % 400 == 0 ) valid = true;
00235         return valid;
00236     }
00237 
00238     return year  >= 1582  &&  year  <= 3000 &&
00239            month >=    1  &&  month <=   12 &&
00240            day   >=    1  &&  day   <= lastDayOfMonth();
00241 }
00242 
00243 string PDate::info() const
00244 {
00245     return tostring(year)+slash+
00246         right(tostring(int(month)), 2, '0') +slash+
00247         right(tostring(int(day)),   2, '0');
00248 }
00249 
00250 int PDate::toJulianDay() const
00251 {
00252     if (year < 1582)
00253         PLERROR("toJulianDay works safely only for year > 1581 (%d)", year);
00254     int jy = (month>2) ? year : year-1;
00255     int jm = (month>2) ? month : month+12;
00256     int ja = (int)(jy/100);
00257     int jb = (int)(ja/4);
00258     int jc = 2 - ja + jb;
00259     int je = (int)(365.25*(jy + 4716));
00260     int jf = (int)(30.6001*(jm + 1));
00261 
00262     return jc + day + je + jf - 1524;
00263 }
00264 
00265 int PDate::dayOfYear() const
00266 {
00267     return (*this)-PDate(year,(unsigned char)1,(unsigned char)1);
00268 }
00269 
00270 
00271 int PDate::weekNumber() const
00272 {
00273     // Hack for now, not yet the true iso week number
00274     // See: http://personal.ecu.edu/mccartyr/ISOwdALG.txt
00275 
00276     return dayOfYear()/7;
00277 }
00278 
00279 
00280 PStream& operator<<(PStream& out, const PDate& date)
00281 {
00282     char tmpbuf[50];
00283 
00284     switch(out.outmode)
00285     {
00286     case PStream::plearn_binary:
00287     case PStream::raw_binary:
00288         out.put((char)0xFE);
00289         out << date_to_double(date);
00290         break;
00291     case PStream::plearn_ascii:        
00292         sprintf(tmpbuf,"%04d/%02d/%02d ",date.year,date.month,date.day);
00293         out.write(tmpbuf);
00294         break;
00295 
00296     case PStream::raw_ascii:
00297     case PStream::pretty_ascii:
00298         // same as plearn_ascii but with no ending space
00299         sprintf(tmpbuf,"%04d/%02d/%02d",date.year,date.month,date.day);
00300         out.write(tmpbuf);
00301         break;
00302     }
00303 
00304     return out;
00305 }
00306 
00307 PStream& operator>>(PStream& in, PDate& date)
00308 {
00309     in.skipBlanksAndComments();
00310     int c = in.peek();
00311     if(c==0xFE) // binary PDate
00312     {
00313         double yyyymmdd;
00314         in >> yyyymmdd;
00315         date = double_to_date(yyyymmdd);
00316     }
00317     else if(isdigit(c))
00318     {
00319         in.readAsciiNum(date.year);
00320         in.readExpected('/');
00321         in.readAsciiNum(date.month);
00322         in.readExpected('/');
00323         in.readAsciiNum(date.day);
00324     }
00325     else
00326         PLERROR("Not a valid serialized PDate");
00327     return in;
00328 }
00329 
00330 float date_to_float(const PDate& t)
00331 {
00332     if (t.isMissing())
00333         return MISSING_VALUE;
00334     else
00335         return float((t.year-1900)*10000 + t.month*100 + t.day);
00336 }
00337 
00338 PDate float_to_date(float f)
00339 {
00340     PDate date;                     // missing by default
00341     if (! is_missing(f)) {
00342         long d = long(f);
00343         date.year = short(1900 + d/10000);
00344         d %= 10000;
00345         date.month = (unsigned char) (d/100);
00346         date.day = (unsigned char) (d%100);
00347     }
00348     return date;
00349 }
00350 
00351 double date_to_double(const PDate& t)
00352 {
00353     if (t.isMissing())
00354         return MISSING_VALUE;
00355     else
00356         return double((t.year)*10000 + t.month*100 + t.day);  
00357 }
00358 
00359 PDate double_to_date(double d)
00360 {
00361     PDate date;                     // missing by default
00362     if (! is_missing(d)) {
00363         long l = long(d);
00364         date.year = short(l/10000);
00365         l %= 10000;
00366         date.month = (unsigned char) (l/100);
00367         date.day = (unsigned char) (l%100);
00368     }
00369     return date;
00370 }
00371 
00372 } // end of namespace PLearn
00373 
00374 
00375 /*
00376   Local Variables:
00377   mode:c++
00378   c-basic-offset:4
00379   c-file-style:"stroustrup"
00380   c-file-offsets:((innamespace . 0)(inline-open . 0))
00381   indent-tabs-mode:nil
00382   fill-column:79
00383   End:
00384 */
00385 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=79 :
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines