SqlDate.cpp

Go to the documentation of this file.
00001 /*
00002 // $Id: //open/dev/fennel/calculator/SqlDate.cpp#3 $
00003 // Fennel is a library of data storage and processing components.
00004 // Copyright (C) 2005-2009 The Eigenbase Project
00005 // Copyright (C) 2004-2009 SQLstream, Inc.
00006 // Copyright (C) 2009-2009 LucidEra, Inc.
00007 //
00008 // This program is free software; you can redistribute it and/or modify it
00009 // under the terms of the GNU General Public License as published by the Free
00010 // Software Foundation; either version 2 of the License, or (at your option)
00011 // any later version approved by The Eigenbase Project.
00012 //
00013 // This program 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
00016 // GNU General Public License for more details.
00017 //
00018 // You should have received a copy of the GNU General Public License
00019 // along with this program; if not, write to the Free Software
00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021 */
00022 
00034 #include "fennel/common/CommonPreamble.h"
00035 #include "fennel/calculator/SqlDate.h"
00036 #include "boost/date_time/gregorian/parsers.hpp"
00037 #include "boost/regex.hpp"
00038 
00039 FENNEL_BEGIN_NAMESPACE
00040 
00041 using namespace boost::posix_time;
00042 using namespace boost::local_time;
00043 using namespace boost::gregorian;
00044 
00045 typedef boost::date_time::c_local_adjustor<boost::posix_time::ptime> local_adj;
00046 
00047 int DateToIsoString(char *dest, boost::posix_time::ptime t)
00048 {
00049     int y = t.date().year();
00050     int m =  t.date().month();
00051     int dy = t.date().day();
00052     return snprintf(dest,11, "%4d-%02d-%02d", y,m, dy);
00053 }
00054 
00055 
00056 int TimeToIsoString(char *dest, boost::posix_time::ptime t)
00057 {
00058     time_duration td = t.time_of_day();
00059     int h = td.hours();
00060     int m = td.minutes();
00061     int s = td.seconds();
00062     return snprintf(dest,9, "%02d:%02d:%02d", h, m, s);
00063 }
00064 
00065 int TimestampToIsoString(char *dest, boost::posix_time::ptime t)
00066 {
00067     time_duration td = t.time_of_day();
00068     int h   = td.hours();
00069     int min = td.minutes();
00070     int s   = td.seconds();
00071 
00072     int y   = t.date().year();
00073     int mon = t.date().month();
00074     int dy  = t.date().day();
00075     return snprintf(
00076         dest, 20, "%4d-%02d-%02d %02d:%02d:%02d", y,mon, dy, h, min, s);
00077 }
00078 
00079 int64_t milliseconds_per_day = 24 * 60 * 60 * 1000LL;
00080 
00081 // NOTE jvs 14-Aug-2005:  I added this as part of upgrading to Boost 1.33
00082 // because the datetime library is no longer forgiving of spaces.
00083 static inline void trimSpaces(std::string &s)
00084 {
00085     std::string::size_type n = s.find_last_not_of(' ');
00086 
00087     if (n == std::string::npos) {
00088         s.resize(0);
00089     } else {
00090         s.resize(n + 1);
00091         n = s.find_first_not_of(' ');
00092         s.erase(0, n);
00093     }
00094 }
00095 
00096 int64_t IsoStringToDate(const char * const src, int len)
00097 {
00098     std::string s(src,len);
00099     trimSpaces(s);
00100 
00101     boost::regex dateExp("\\d+-\\d+-\\d+");
00102     if (boost::regex_match(s, dateExp)) {
00103         try {
00104             date_duration td = boost::gregorian::from_string(s) - epoc.date();
00105             return td.days() * milliseconds_per_day;
00106         } catch (...) {
00107             // Fall through to throw
00108         }
00109     }
00110 
00111     // Parse of date failed
00112     // SQL2003 Part 2 Section 6.12 General Rule 13 data
00113     // exception -- invalid datetime format
00114     throw "22007";
00115 }
00116 
00117 int64_t IsoStringToTime(const char * const src, int len)
00118 {
00119     std::string s(src, len);
00120     trimSpaces(s);
00121 
00122     // TODO: Boost library doesn't catch invalid hour, min, sec
00123     // TODO: Try updated boost library to see if we can get
00124     // TODO: rid of this tiresome check
00125     boost::cmatch what;
00126     boost::regex timeExp("(\\d+):(\\d+):(\\d+)(\\.\\d+)?");
00127     if (boost::regex_match(s.c_str(), what, timeExp)) {
00128         try {
00129             int hour = atoi(what[1].first);
00130             int min = atoi(what[2].first);
00131             int sec = atoi(what[3].first);
00132 
00133             if ((hour >= 0) && (hour < 24) &&
00134                 (min >= 0) && (min < 60) &&
00135                 (sec >= 0) && (sec < 60)) {
00136                 time_duration td = duration_from_string(s);
00137                 return td.total_milliseconds();
00138             }
00139         } catch (...) {
00140             // Fall through to throw
00141         }
00142     }
00143 
00144     // Parse of time failed
00145     // SQL2003 Part 2 Section 6.12 General Rule 15,16 data
00146     // exception -- invalid datetime format
00147     throw "22007";
00148 }
00149 
00150 int64_t IsoStringToTimestamp(const char * const src, int len)
00151 {
00152     std::string s(src, len);
00153     trimSpaces(s);
00154 
00155     // TODO: Boost library doesn't catch invalid hour, min, sec
00156     // TODO: Try updated boost library to see if we can get
00157     // TODO: rid of this tiresome check
00158     boost::cmatch what;
00159     boost::regex timestampExp("\\d+-\\d+-\\d+ +"
00160                        "(\\d+):(\\d+):(\\d+)(\\.\\d+)?");
00161     if (boost::regex_match(s.c_str(), what, timestampExp)) {
00162         try {
00163             int hour = atoi(what[1].first);
00164             int min = atoi(what[2].first);
00165             int sec = atoi(what[3].first);
00166 
00167             if ((hour >= 0) && (hour < 24) &&
00168                 (min >= 0) && (min < 60) &&
00169                 (sec >= 0) && (sec < 60)) {
00170                 ptime p(time_from_string(s));
00171                 time_duration td = p - epoc;
00172                 return td.total_milliseconds();
00173             }
00174         } catch (...) {
00175             // Fall through to throw
00176         }
00177     }
00178 
00179     // Parse of timestamp failed
00180     // SQL2003 Part 2 Section 6.12 General Rule 17,18 data
00181     // exception -- invalid datetime format
00182     throw "22007";
00183 }
00184 
00185 int64_t UniversalTime()
00186 {
00187     ptime p = second_clock::universal_time();
00188     return p.time_of_day().total_milliseconds();
00189 }
00190 
00191 int64_t UniversalTimestamp()
00192 {
00193     // REVIEW: SWZ: 4/30/2006: In practice, we should return the micro
00194     // second delta (or as much precision as we can muster) and let
00195     // the instruction (which may have been given an explicit
00196     // precision) truncate the fractional seconds.  For now, returning
00197     // millis causes Fennel Calc to behave like the Java Calc for
00198     // CURRENT_TIME[STAMP].
00199     ptime p = microsec_clock::universal_time();
00200     return (p - epoc).total_milliseconds();
00201 }
00202 
00203 int64_t LocalTime(boost::local_time::time_zone_ptr tzPtr)
00204 {
00205     local_date_time plocal = local_microsec_clock::local_time(tzPtr);
00206     return plocal.local_time().time_of_day().total_milliseconds();
00207 }
00208 
00209 int64_t LocalTimestamp(boost::local_time::time_zone_ptr tzPtr)
00210 {
00211     // Create a local epoch. For PST, for example, the epoch is 1970/1/1 PST,
00212     // which occurred 8 hrs after the UTC epoch.
00213     date d(1970, 1, 1);
00214     time_duration td(0, 0, 0);
00215     local_date_time local_epoc(
00216         d, td, tzPtr, local_date_time::NOT_DATE_TIME_ON_ERROR);
00217 
00218     local_date_time plocal = local_microsec_clock::local_time(tzPtr);
00219     time_duration diff = plocal - local_epoc;
00220 
00221     // Adjust the difference if we are now in DST and the epoch is not, or vice
00222     // versa.
00223     if (plocal.is_dst()) {
00224         if (local_epoc.is_dst()) {
00225             // same offset: nothing to do
00226         } else {
00227             diff += tzPtr->dst_offset();
00228         }
00229     } else {
00230         if (local_epoc.is_dst()) {
00231             diff -= tzPtr->dst_offset();
00232         } else {
00233             // same offset: nothing to do
00234         }
00235     }
00236     return diff.total_milliseconds();
00237 }
00238 
00239 
00240 FENNEL_END_NAMESPACE
00241 
00242 // End SqlDate.cpp

Generated on Mon Jun 22 04:00:17 2009 for Fennel by  doxygen 1.5.1