PLearn 0.1
PDateTime.cc
Go to the documentation of this file.
00001 // -*- C++ -*-
00002 
00003 // PDateTime
00004 // Copyright (c) 2002 by Nicolas Chapados
00005 
00006 // Redistribution and use in source and binary forms, with or without
00007 // modification, are permitted provided that the following conditions are met:
00008 // 
00009 //  1. Redistributions of source code must retain the above copyright
00010 //     notice, this list of conditions and the following disclaimer.
00011 // 
00012 //  2. Redistributions in binary form must reproduce the above copyright
00013 //     notice, this list of conditions and the following disclaimer in the
00014 //     documentation and/or other materials provided with the distribution.
00015 // 
00016 //  3. The name of the authors may not be used to endorse or promote
00017 //     products derived from this software without specific prior written
00018 //     permission.
00019 // 
00020 // THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
00021 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00022 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
00023 // NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00024 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
00025 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00026 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00027 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00028 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00029 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00030 // 
00031 // This file is part of the PLearn library. For more information on the PLearn
00032 // library, go to the PLearn Web site at www.plearn.org
00033 
00034 /* *******************************************************      
00035  * $Id: PDateTime.cc 6351 2006-10-25 19:05:45Z chapados $
00036  * This file is part of the PLearn library.
00037  ******************************************************* */
00038 
00039 //#include <limits.h>                 // from stdc
00040 #include "PDateTime.h"
00041 #include <plearn/base/stringutils.h> 
00042 #include <plearn/base/lexical_cast.h>  // for toint  
00043 #include <plearn/base/tostring.h>  
00044 #include "general.h"                // for MISSING_VALUE
00045 
00046 namespace PLearn {
00047 using namespace std;
00048 
00049 PDateTime::PDateTime()
00050 {
00051     setMissing();
00052 }
00053 
00054 PDateTime::PDateTime(double julian_day)
00055 {
00056     int jw = (int)((julian_day - 1867216.25)/36524.25);
00057     int jx = (int)(jw/4);
00058     int ja = (int)(julian_day + 1 + jw - jx);
00059     int jb = ja + 1524;
00060     int jc = (int)((jb - 122.1)/365.25);
00061     int jd = (int)(365.25*jc);
00062     int je = (int)((jb - jd)/30.6001);
00063     int jf = (int)(30.6001*je);
00064 
00065     day = jb - jd - jf;
00066     month = (je>13) ? je-13 : je-1;
00067     year = (month>2) ? jc-4716 : jc-4715;
00068 
00069     double fraction = julian_day - floor(julian_day);
00070     int hh,mm,ss;
00071     double_to_hhmmss(fraction,hh,mm,ss);
00072     hour = hh;
00073     min = mm;
00074     sec = ss;
00075 }
00076 
00077 PDateTime::PDateTime(string date)
00078 {
00079     // Parse either "YYYY/MM/DD" or "YYYY/MM/DD hh:mm:ss" format
00080     if ((date.size() == 10 || date.size() == 19) &&
00081         date[4] == '/' && date[7] == '/' &&
00082         (date.size() == 19? date[13] == ':' && date[16] == ':' : true)) {
00083         year = toint(date.substr(0,4));
00084         month = toint(date.substr(5,2));
00085         day = toint(date.substr(8,2));
00086         if (date.size() == 10)
00087             hour = min = sec = 0;
00088         else {
00089             hour = toint(date.substr(11,2));
00090             min  = toint(date.substr(14,2));
00091             sec  = toint(date.substr(17,2));
00092         }
00093     }
00094     else
00095         PLERROR("PDateTime::PDateTime: the passed date-time string is not in "
00096                 "\"YYYY/MM/DD\" or \"YYYY/MM/DD hh:mm:ss\" format");
00097 }
00098 
00100 // isMissing //
00102 bool PDateTime::isMissing() const
00103 {
00104     return year == SHRT_MIN && month == 0 && day == 0;
00105 }
00106 
00108 // setMissing //
00110 void PDateTime::setMissing()
00111 {
00112     year = SHRT_MIN;
00113     month = 0;
00114     day = 0;
00115 }  
00116 
00118 // incSecond //
00120 void PDateTime::incSecond(int sec_inc)
00121 {
00122     int new_sec = int(sec) + sec_inc;
00123     int min_inc = new_sec / 60;
00124     sec = (unsigned char) (new_sec % 60);
00125     incMinute(min_inc);
00126 }
00127 
00129 // incMinute //
00131 void PDateTime::incMinute(int min_inc)
00132 {
00133     int new_min = int(min) + min_inc;
00134     int hour_inc = new_min / 60;
00135     min = (unsigned char) (new_min % 60);
00136     incHour(hour_inc);
00137 }
00138 
00140 // incHour //
00142 void PDateTime::incHour(int hour_inc)
00143 {
00144     int new_hour = int(hour) + hour_inc;
00145     int day_inc = new_hour / 24;
00146     hour = (unsigned char) (new_hour % 24);
00147     incDay(day_inc);
00148 }
00149 
00151 // incDay //
00153 void PDateTime::incDay(int day_inc)
00154 {
00155     PLASSERT( day_inc >= 0 );
00156     int new_day = int(day) + day_inc;
00157     int max_day = 31;
00158     if (month == 2) {
00159         if (year < 1900 || year > 2100)
00160             PLERROR("In PDateTime::incDay - This code is probably not going to"
00161                     " work for year %d", int(year));
00162         max_day = year % 4 == 0 ? 29 : 28;
00163     } else if (month == 4 || month == 6 || month == 9 || month == 11)
00164         max_day = 30;
00165     if (new_day <= max_day) {
00166         day = (unsigned char) new_day;
00167         return;
00168     }
00169     // We need to switch to next month.
00170     PLASSERT( max_day >= int(day) );
00171     int days_to_next_month = max_day - int(day) + 1;
00172     month++;
00173     if (month == 13) {
00174         // We need to switch to next year.
00175         year++;
00176         month = 1;
00177     }
00178     day = 1;
00179     incDay(day_inc - days_to_next_month);
00180 }
00181   
00183 // info //
00185 string PDateTime::info() const
00186 {
00187     return tostring(year)+ slash+
00188         right(tostring(int(month)), 2, '0') + slash+
00189         right(tostring(int(day)),   2, '0') + " "+
00190         right(tostring(int(hour)),  2, '0') + ":"+
00191         right(tostring(int(min)),   2, '0') + ":"+
00192         right(tostring(int(sec)),   2, '0');
00193 }
00194 
00196 // currentLocalTime //
00198 PDateTime PDateTime::currentLocalTime() {
00199     time_t current;
00200     tm* ptr;
00201     time(&current);
00202     ptr = ::localtime(&current);
00203     return PDateTime(ptr->tm_year + 1900, ptr->tm_mon + 1, ptr->tm_mday,
00204                      ptr->tm_hour, ptr->tm_min, ptr->tm_sec);
00205 }
00206 
00208 // toJulianDay //
00210 double PDateTime::toJulianDay() const
00211 {
00212     if (year < 1582)
00213         PLERROR("toJulianDay works safely only for year > 1581 (%d)", year);
00214 
00215     double fraction = hhmmss_to_double(hour,min,sec);
00216   
00217     int jy = (month>2) ? year : year-1;
00218     int jm = (month>2) ? month : month+12;
00219     int ja = (int)(jy/100);
00220     int jb = (int)(ja/4);
00221     int jc = 2 - ja + jb;
00222     int je = (int)(365.25*(jy + 4716));
00223     int jf = (int)(30.6001*(jm + 1));
00224 
00225     return jc + day + je + jf - 1524 + fraction;
00226 }
00227 
00228 double datetime_to_double(const PDateTime& t)
00229 {
00230     if (t.isMissing())
00231         return MISSING_VALUE;
00232     else
00233         return double((t.year-1900)*10000 + t.month*100 + t.day) +
00234             hhmmss_to_double(t.hour,t.min,t.sec);
00235 }
00236 
00237 PDateTime double_to_datetime(double f)
00238 {
00239     PDateTime date;                     // missing by default
00240     if (! is_missing(f)) {
00241         long d = long(f);
00242         double fraction = f-d;
00243         date.year = short(1900 + d/10000);
00244         d %= 10000;
00245         date.month = (unsigned char) (d/100);
00246         date.day = (unsigned char) (d%100);
00247 
00248         int hh,mm,ss;
00249         double_to_hhmmss(fraction,hh,mm,ss);
00250         date.hour = hh;
00251         date.min  = mm;
00252         date.sec  = ss;
00253     }
00254     return date;
00255 }
00256 
00257 double hhmmss_to_double(int hh, int mm, int ss)
00258 {
00259     // There are 1440 minutes in a day.
00260     // There are 86400 seconds in a day.
00261     return double(hh)/24. + double(mm)/1440. + double(ss)/86400;
00262 }
00263 
00264 void double_to_hhmmss(double fraction, int& hh, int& mm, int& ss)
00265 {
00266     hh = int(fraction *= 24);
00267     fraction -= hh;
00268     mm = int(fraction *= 60);
00269     fraction -= mm;
00270     ss = int(fraction * 60);
00271 }
00272 
00273 int delta_seconds(const PDateTime& current, const PDateTime& past)
00274 {
00275     if ( current == past )
00276         return 0;
00277 
00278     double jcurrent   = current.toJulianDay();
00279     double jpast      = past.toJulianDay();
00280     double delta_days = jcurrent - jpast;
00281 
00282     return int( round(delta_days*SECONDS_PER_DAY) ); 
00283 }
00284 
00285 
00286 } // end of namespace PLearn
00287 
00288 
00289 /*
00290   Local Variables:
00291   mode:c++
00292   c-basic-offset:4
00293   c-file-style:"stroustrup"
00294   c-file-offsets:((innamespace . 0)(inline-open . 0))
00295   indent-tabs-mode:nil
00296   fill-column:79
00297   End:
00298 */
00299 // 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