PLearn 0.1
|
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 :