/* ---- This file is part of SECONDO. Copyright (C) 2004, University in Hagen, Department of Computer Science, Database Systems for New Applications. SECONDO is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. SECONDO is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with SECONDO; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ---- //[_] [\_] //[TOC] [\tableofcontents] //[Title] [ \title{DateTime Algebra} \author{Thomas Behr} \maketitle] //[times] [\ensuremath{\times}] //[->] [\ensuremath{\rightarrow}] December 2005, Victor Almeida deleted the deprecated algebra levels (~executable~, ~descriptive~, and ~hibrid~). Only the executable level remains. Models are also removed from type constructors. [Title] [TOC] \noindent 0 Introduction Time is a very important datatype. They are two different kinds of time, namely *duration* and *instant*. Both types can be handled by the same data structure. Unfortunately, not all combinations of types makes any sense in each operator, e.g. the addition of two instants. To handle this problem, the type information is included in the data-structure. The correct use of the operators is checked via assert() callings. Note, that several operations changes the type of the this-object, e.g. if ~Minus~ is called on an instant and an instant as argument, the this object will be changed from instant to duration. The Algebra provides the following operators. \begin{tabular}{|l|l|l|}\hline *Operator* & *Signature* & *Remarks* \\\hline + & instant [times] duration [->] instant & addition of the arguments \\\cline{2-2} & duration [times] instant [->] instant & possible change of the type \\\cline{2-2} & duration [times] duration [->] duration & \\\hline - & instant [times] duration [->] instant & difference of two time instances \\\cline{2-2} & instant [times] instant [->] duration & possible change of the type \\\cline{2-2} & duration [times] duration [->] duration & \\\hline * & duration [times] real [->] duration & the multiple of a duration \\\hline =, $<$, $>$ & instant [times] instant [->] bool & the familiar comparisons \\\cline{2-2} & duration [times] duration [->] bool & \\\hline weekday & instant [->] string & the weekday in a human readable format \\\hline leapyear & int [->] bool & checks for leapyear \\\hline year[_]of,month[_]of,day[_]of & instant [->] int & the date parts of an instant \\\hline hour[_]of, minute[_]of, & instant [->] int & the time parts of an instant \\ second[_]of, millisecond[_]of & & \\\hline now & [->] instant & creates a new instant from the systemtime \\\hline today & [->] instant & creates a new instant today at 0:00 \\\hline \end{tabular} 1 Includes and Definitions */ #include "DateTime.h" #include "BigInt.h" #include #include #include #include "NestedList.h" #include "Algebra.h" #include "QueryProcessor.h" #include "AlgebraManager.h" #include "SecondoSystem.h" #include "Attribute.h" #include "StandardTypes.h" #include "Algebras/Standard-C++/LongInt.h" #include "Algebras/FText/FTextAlgebra.h" #include #include #include #include "LogMsg.h" #include "ListUtils.h" #include "StringUtils.h" #include "Symbols.h" #include extern "C" { #include "dateconvert.h" } #define POS "DateTimeAlgebra.cpp:" << __LINE__ extern NestedList* nl; extern QueryProcessor *qp; extern AlgebraManager *am; using namespace std; static int64_t min_VALUE = numeric_limits::min(); static int64_t max_VALUE = numeric_limits::max(); static string begin_of_time="begin of time"; static string end_of_time="end of time"; static int64_t MAX_REPRESENTABLE = ((int64_t)2450000) * (int64_t)MILLISECONDS; static int64_t MIN_REPRESENTABLE = ((int64_t)-2450000) * (int64_t)MILLISECONDS; //static int64_t MAX_REPRESENTABLE = max_VALUE; //static int64_t MIN_REPRESENTABLE = min_VALUE; namespace datetime{ /* ~GetValue~ The function ~GetValue~ returns the integer value of an given character. If this character does not represent any digit, -1 is returned. */ static int GetValue(const char c){ switch(c){ case '0' : return 0; case '1' : return 1; case '2' : return 2; case '3' : return 3; case '4' : return 4; case '5' : return 5; case '6' : return 6; case '7' : return 7; case '8' : return 8; case '9' : return 9; default : return -1; } } /* 2 The Implementation of the Class DateTime ~The Standard Constructor~ This constructor makes nothing and should never be called. It is used in a special way in a cast function. */ DateTime::DateTime():IndexableAttribute(){} /* ~Constructor~ This constructor creates a DateTime at the NULL[_]DAY and duration zero, respectively. */ DateTime::DateTime(const TimeType type1): IndexableAttribute(true), type(type1), value(0){ } /* ~A Constructor ~ The Value of MilliSeconds has to be greater than or equals to zero. */ DateTime::DateTime(const int32_t Day, const int32_t MilliSeconds, const TimeType Type): IndexableAttribute(true), type(Type), value ( (((int64_t)Day)*MILLISECONDS) + MilliSeconds) { } DateTime::DateTime(const int64_t v): IndexableAttribute(true), type(instanttype), value(v) {} /* ~Constructor~ This conmstructor creates a DateTime with the same value like the argument. */ DateTime::DateTime(const DateTime& DT): IndexableAttribute(DT), type(DT.type), value(DT.value) { } DateTime::DateTime(const double d): IndexableAttribute(true), type(instanttype), value(0) { ReadFrom(d); } DateTime::DateTime(const TimeType t, const uint64_t v): IndexableAttribute(true), type(t), value(v){} /* ~Assignment operator~ */ DateTime& DateTime::operator=(const DateTime& DT){ Equalize(&DT); return (*this); } /* ~Destructor~ */ DateTime::~DateTime(){} /* ~Set~ This function sets an instant to the given values. */ void DateTime::Set(const int32_t year,const int32_t month, const int32_t day, const int32_t hour, const int32_t minute, const int32_t second, const int32_t millisecond){ assert(type == instanttype); int64_t ms = ((hour*60+minute)*60+second)*1000+millisecond; int64_t d = ToJulian(year,month,day); value = d*MILLISECONDS + ms; SetDefined(true); } /* ~Now~ Gets the value of this DateTime from the System. Cannot be applied to a duration. */ void DateTime::Now(){ assert(type!=(durationtype)); struct timeval tp; time_t now; int ms; gettimeofday(&tp, NULL); now = tp.tv_sec; ms = tp.tv_usec / 1000; tm* time = localtime(&now); int64_t day = ToJulian(time->tm_year+1900,time->tm_mon+1,time->tm_mday); int64_t milliseconds = ((((time->tm_hour)*60)+time->tm_min)* 60+time->tm_sec)*1000+ms; value = day*MILLISECONDS + milliseconds; SetDefined(true); } /* ~Today~ This function reads this DateTime value from the Systemtime. The time part is ignored here. This means, that hour ... millisecond are assumed to be zero. Cannot applied to a duration. */ void DateTime::Today(){ assert(type != (durationtype)); time_t today; time(&today); tm* lt = localtime(&today); int64_t day = ToJulian(lt->tm_year+1900,lt->tm_mon+1,lt->tm_mday); value= day*MILLISECONDS; SetDefined(true); } /* ~ToMinimum~ Sets this instant to the mimimum possible value. */ void DateTime::ToMinimum(){ SetDefined(true); value = min_VALUE; } /* ~ToMaximum~ Sets this instant to the maximum possible value. */ void DateTime::ToMaximum(){ SetDefined(true); value = max_VALUE; } /* ~IsMinimum~ Checks if this value is the most minimum representable one. */ bool DateTime::IsMinimum()const { if(!IsDefined()){ return false; } return value == min_VALUE; } /* ~IsMaximum~ Checks if this value is the most maximum representable one. */ bool DateTime::IsMaximum()const{ if(!IsDefined()){ return false; } return value==max_VALUE; } /* ~GetDay~ This functions yields the day-part of a duration. The function can't applied to an instant. */ int64_t DateTime::GetDay()const{ int64_t d = (value / (int64_t) MILLISECONDS); if((value<0) && (value%MILLISECONDS!=0)){ d--; } return d; } /* ~GetAllMilliSeconds~ This function returns the milliseconds of the day of this Time instance. */ int32_t DateTime::GetAllMilliSeconds()const{ int32_t ms = (int32_t) (value % MILLISECONDS); if(value<0 && ms!=0){ ms += MILLISECONDS; } return ms; } /* ~Gregorian Calender~ The following functions return single values of this DateTime instance. This functions cannot applied to durations. */ int32_t DateTime::GetGregDay()const{ assert(type != (durationtype)); int64_t y; int32_t m,d; ToGregorian(y,m,d); return d; } int DateTime::GetMonth()const{ assert(type !=(durationtype)); int64_t y; int32_t m,d; ToGregorian(y,m,d); return m; } int32_t DateTime::GetYear()const{ assert(type != (durationtype)); int64_t y; int32_t m,d; ToGregorian(y,m,d); return y; } int32_t DateTime::GetHour()const{ assert(type != (durationtype)); int32_t milliseconds = GetAllMilliSeconds(); return (int32_t)(milliseconds / 3600000); } int32_t DateTime::GetMinute()const{ assert(type != (durationtype)); int32_t milliseconds = GetAllMilliSeconds(); return (int32_t) ( (milliseconds / 60000) % 60); } int32_t DateTime::GetSecond()const{ assert(type != (durationtype)); int32_t milliseconds = GetAllMilliSeconds(); return (int32_t) ( (milliseconds / 1000) % 60); } int32_t DateTime::GetMillisecond()const{ assert(type != (durationtype)); int32_t milliseconds = GetAllMilliSeconds(); return (int32_t) (milliseconds % 1000); } int32_t DateTime::GetWeekday()const{ int32_t day = GetDay(); if(day>=0){ return day % 7; } else { return (day % 7 ) + 7; } } /* ~ToJulian~ This function computes the Julian day number of the given gregorian date + the reference time. Positive year signifies A.D., negative year B.C. Remember that the year after 1 B.C. was 1 A.D. Julian day 0 is a Monday. This algorithm is from Press et al., Numerical Recipes in C, 2nd ed., Cambridge University Press 1992 */ // computes floor(a/b) int64_t intfloor(int64_t a, int64_t b){ assert(b>0); if(a>=0){ return a / b; } else { int64_t c = (a - b) + 1; int64_t res = c / b; return res; } } int64_t DateTime::ToJulian(const int64_t year, const int32_t month, const int32_t day){ int64_t jy = year; if (year < 0) jy++; int32_t jm = month; if (month > 2) jm++; else{ jy--; jm += 13; } //int32_t jul1 = (int32_t)(floor(365.25 * jy) + floor(30.6001*jm) // + day + 1720995.0); int64_t jul = intfloor(1461*jy,4) + intfloor(306001*jm,10000) + day + 1720995; int32_t IGREG = 15 + 31*(10+12*1582); // Gregorian Calendar adopted Oct. 15, 1582 if (day + 31 * (month + 12 * year) >= IGREG){ // change over to Gregorian calendar int64_t ja =(jy/100); jul += 2 - ja + ja/4; } return jul-NULL_DAY; } /* ~ToGregorian~ This function converts a Julian day to a date in the gregorian calender. This algorithm is from Press et al., Numerical Recipes in C, 2nd ed., Cambridge University Press 1992 */ void DateTime::ToGregorian(const int64_t Julian, int64_t &year, int32_t &month, int32_t &day){ int64_t j=(int64_t)(Julian+NULL_DAY); int64_t ja = j; static int64_t JGREG = 2299161; /* the Julian date of the adoption of the Gregorian calendar */ if (j >= JGREG){ /* cross-over to Gregorian Calendar produces this correction */ // int64_t jalpha = (int64_t)(((double)(j - 1867216) - 0.25)/36524.25); static int64_t c1 = 7468865; static int64_t c2 = 146097; int64_t jalpha= (4*j - c1) / c2; ja += 1 + jalpha - ( jalpha / 4); } int64_t jb = ja + 1524; // int64_t jc = (int64_t)(6680.0 + ((double)(jb-2439870) - 122.1)/365.25); int64_t cx = (20*(jb-2439870) - 2442); if(cx<0){ cx -= 7304; } int64_t jc = 6680 + cx/7305; int64_t jd = (365 * jc + (jc/4)); //int64_t je = (int64_t)((jb - jd)/30.6001); int64_t je = ((jb-jd)*10000) / 306001; day = jb - jd - (306001 * je)/10000; month = je - 1; if (month > 12) month -= 12; year = jc - 4715; if (month > 2) --year; if (year <= 0) --year; } void DateTime::ToGregorian(int64_t &year, int32_t &month, int32_t &day) const{ ToGregorian(GetDay(),year,month,day); } /* ~ToDouble~ This function converts this Time instance to the corresponding double value; */ double DateTime::ToDouble() const{ return ((double)value) / MILLISECONDS; } /* ~ToString~ This function returns the string representation of this DateTime instance. */ string DateTime::ToString(const bool sql92conform /*=false*/ ) const{ ostringstream tmp; if(!IsDefined()){ return Symbol::UNDEFINED(); } if(type == (durationtype)){ //a duration int days = GetDay(); int ms = GetAllMilliSeconds(); int hours = ms / (1000*60*60); ms = ms % (1000*60*60); int minutes = ms / 60000; ms = ms % 60000; int seconds = ms / 1000; ms = ms % 1000; if(days > 0){ tmp << days << " d "; } if(days!=0 || hours!=0){ tmp << hours << " h "; } if(days!=0 || hours !=0 || minutes!=0){ tmp << minutes << " m "; } // seconds are given if seconds > 0 // or milliseconds > 0 and days, hour, minutes is given if(seconds > 0 || ( (ms>0 && (days!=0 || hours!=0 || minutes!=0)))){ tmp << seconds << " s "; } if(ms > 0){ tmp << ms << " ms"; } }else if(type ==(instanttype)){ // an instant if(IsMinimum()){ return begin_of_time; } if(IsMaximum()){ return end_of_time; } // SOME DATES CAN'T BE CONVERTED CORRECTLY INTO THE GREGORIAN // calendar if(value < MIN_REPRESENTABLE || value >MAX_REPRESENTABLE){ tmp << ToDouble(); return tmp.str(); } int32_t day,month; int64_t year; ToGregorian(year,month,day); if(!(day>0 && month>0 && month<13 && day<32)){ cmsg.error() << "error in ToString function of instant detected \n" << "day ("<0) tmp << "0"; if(year < 100 && year >0) tmp << "0"; if(year < 10 && year > 0) tmp << "0"; tmp << year << "-"; if(month<10) tmp << "0"; tmp << month << "-"; if(day<10) tmp << "0"; tmp << day; int32_t milliseconds = GetAllMilliSeconds(); if(milliseconds==0) // without time return tmp.str(); int32_t v = GetAllMilliSeconds(); int32_t ms = v % 1000; v = v / 1000; int32_t sec = v % 60; v = v / 60; int32_t min = v % 60; int32_t hour = v / 60; tmp << (sql92conform?" ":"-"); if(hour<10) tmp << "0"; tmp << hour << ":"; if(min<10) tmp << "0"; tmp << min; if((sec==0) && (ms == 0)) return tmp.str(); tmp << ":"; if(sec<10) tmp << "0"; tmp << sec; if(ms==0) return tmp.str(); tmp << "."; if(ms <100) tmp << "0"; if(ms <10) tmp << "0"; tmp << ms; } else{ tmp << "unknown type, def=" << IsDefined() << " type=" << GetType() << " day = " << GetDay() << " ms = " << GetAllMilliSeconds(); } string res = tmp.str(); stringutils::trim(res); return res; } ostream& DateTime::Print(ostream &os) const { os << ToString(); return os; } /* ~ReadFrom~ This function reads the Time from a given string. If the string don't represent a valid Time value, this instance remains unchanged and false is returned. In the other case, this instance will hold the the time represented by the string and the result is true. The format of the string must be: * YEAR-MONTH-DAY-HOUR:MIN[:SECOND[.MILLISECOND]] Spaces are not allowed in this string. The squared brackets indicates optional parts. This function is not defined for durations. */ bool DateTime::ReadFrom(const string Time1){ string Time = Time1; stringutils::trim(Time); SetDefined(true); if(type == (instanttype)){ // read instant type from string if(listutils::isSymbolUndefined(Time)){ SetDefined(false); return true; } if(Time==begin_of_time){ ToMinimum(); return true; } if(Time==end_of_time){ ToMaximum(); return true; } int32_t year = 0; int32_t digit; int32_t len = Time.length(); if(len==0) return false; int32_t pos = 0; // read the year int32_t signum = 1; if(Time[0]=='-'){ signum=-1; pos++; } if(pos==len) return false; while(Time[pos]!='-'){ digit = datetime::GetValue(Time[pos]); if(digit<0) return false; pos++; if(pos==len) return false; year = year*10+digit; } year = year*signum; pos++; // read over '-' if(pos==len) return false; // read the month int32_t month = 0; while(Time[pos]!='-'){ digit = datetime::GetValue(Time[pos]); if(digit<0) return false; pos++; if(pos==len) return false; month = month*10+digit; } pos++; // read over '-' if(pos==len) return false; // read the day int32_t day = 0; while( (Time[pos]!='-') && (Time[pos]!=' ') ){ digit = datetime::GetValue(Time[pos]); if(digit<0) return false; pos++; day = day*10+digit; if(pos==len){ // we allow pure date string without any hour if(!IsValid(year,month,day)) { return false; } value = ((int64_t)ToJulian(year,month,day))*MILLISECONDS; SetDefined(true); return true; } } pos++; // read over '-' or ' ' if(pos==len) return false; if(!IsValid(year,month,day)){ return false; } // read the hour int32_t hour = 0; while(Time[pos]!=':'){ digit = datetime::GetValue(Time[pos]); if(digit<0) return false; pos++; if(pos==len) return false; hour = hour*10+digit; } pos++; // read over ':' if(pos==len) return false; // read the minute int32_t minute = 0; bool done = false; bool next = false; while(!done && !next){ digit = datetime::GetValue(Time[pos]); if(digit<0) return false; pos++; minute = minute*10+digit; done = pos==len; if(!done) next = Time[pos]==':'; } // initialize seconds and milliseconds with zero int32_t seconds = 0; int32_t mseconds = 0; if(!done){ // we have to read seconds pos++; // read over the ':' if(pos==len) return false; next = false; while(!done && !next){ digit = datetime::GetValue(Time[pos]); if(digit<0) return false; pos++; seconds = seconds*10+digit; done = pos==len; if(!done) next = Time[pos]=='.'; } if(!done ){ // milliseconds are available pos++; // read over the '.' if(pos==len) return false; next = false; while(!done){ digit = datetime::GetValue(Time[pos]); if(digit<0) return false; pos++; mseconds = mseconds*10+digit; done = pos==len; } } } // At this place we have all needed information to create a date day = ToJulian(year,month,day); int64_t milliseconds = ((hour*60+minute)*60+seconds)*1000+mseconds; value = ((int64_t)day)*MILLISECONDS + milliseconds; SetDefined(true); return true; } else { // read durationtype from string assert(type ==(durationtype)); if(listutils::isSymbolUndefined(Time)){ SetDefined(false); return true; } int32_t day = 0; int32_t digit; int32_t len = Time.length(); if(len==0) return false; int32_t pos = 0; // read the day int32_t signum = 1; if(Time[0]=='-'){ signum=-1; pos++; } if(pos==len) return false; while(Time[pos]!=';'){ digit = datetime::GetValue(Time[pos]); if(digit<0) return false; pos++; if(pos==len) return false; day = day*10+digit; } day = day*signum; pos++; // read over ';' bool done = (pos==len); if(done) return false; // read the millisecond int32_t mseconds = 0; signum = 1; if(Time[pos]=='-'){ signum=-1; pos++; done = (pos==len); } while(!done){ digit = datetime::GetValue(Time[pos]); if(digit<0) return false; pos++; mseconds = mseconds*10+digit; done = pos==len; } mseconds = mseconds * signum; // store data to attributesa value = ((int64_t)day) + mseconds; SetDefined(true); return true; } } enum DATETIMECOMPONENT { YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, MILLI , error }; DATETIMECOMPONENT getCode(char c){ switch(c){ case 'Y' : return YEAR; case 'M' : return MONTH; case 'D' : return DAY; case 'h' : return HOUR; case 'm' : return MINUTE; case 's' : return SECOND; case 'f' : return MILLI; } return error; } ostream& operator<<(ostream& o, const DATETIMECOMPONENT& c){ switch(c){ case YEAR: o << "YYYY"; break; case MONTH: o << "MM"; break; case DAY: o << "DD"; break; case HOUR: o << "hh"; break; case MINUTE: o << "mm"; break; case SECOND: o << "ss"; break; case MILLI: o << "ffff"; break; case error : o << "error" ; break; } return o; } bool DateTime::readFrom(const string& value, const string& format){ vector f; //separator, date component size_t pos = format.find_first_of("YMDhmsf"); while(f.size() <= 7 && (pos != string::npos)){ f.push_back(getCode(format[pos])); string L = format.substr(pos,1); pos = format.find_first_not_of(L,pos+1); if(pos!=string::npos){ if(getCode(format[pos])!=error){ // separator missing return false; } pos = format.find_first_of("YMDhmsf", pos+1); } } bool year = false; bool month = false; bool day = false; bool hour = false; bool minute = false; bool second = false; bool milli = false; for(unsigned int i=0;iListLength(LE)!=2){ return false; } ListExpr TypeList = nl->First(LE); if(!listutils::isSymbol(TypeList,"datetime")){ if( (type == (instanttype)) && !listutils::isSymbol(TypeList,DateTime::BasicType())){ return false; } if( (type == (durationtype)) && !listutils::isSymbol(TypeList,Duration::BasicType())){ return false; } } ValueList = nl->Second(LE); }else{ ValueList=LE; } // Special Representation in this Algebra if(listutils::isSymbolUndefined(ValueList)){ SetDefined(false); return true; } if(listutils::isSymbol(ValueList,"currenttime") || listutils::isSymbol(ValueList,"CURRENTTIME")){ if(type == (instanttype)){ Now(); return true; } else return false; } if(listutils::isSymbol(ValueList,"today") || listutils::isSymbol(ValueList,"TODAY")){ if(type == (instanttype)){ Today(); return true; } else return false; } // string representation if(nl->AtomType(ValueList)==StringType){ if(type ==(instanttype)) return ReadFrom(nl->StringValue(ValueList)); else return false; } // real representation if(nl->AtomType(ValueList)==RealType ){ bool res = ReadFrom(nl->RealValue(ValueList)); return res; } // accept also integer values if(nl->AtomType(ValueList)==IntType ){ if(type ==(instanttype)){ bool res = ReadFrom(static_cast(nl->IntValue(ValueList))); return res; } else return false; } // (day month year [hour minute [second [millisecond]]]) if( (nl->ListLength(ValueList)>=3) && nl->ListLength(ValueList)<=7){ if(type == (durationtype)) return false; int32_t len = nl->ListLength(ValueList); if(len==4) return false; // only hours is not allowed ListExpr tmp = ValueList; while(!nl->IsEmpty(tmp)){ if(nl->AtomType(nl->First(tmp))!=IntType) return false; tmp = nl->Rest(tmp); } int32_t d,m,y,h,min,sec,ms; d = nl->IntValue(nl->First(ValueList)); m = nl->IntValue(nl->Second(ValueList)); y = nl->IntValue(nl->Third(ValueList)); h = len>3? nl->IntValue(nl->Fourth(ValueList)):0; min = len>4? nl->IntValue(nl->Fifth(ValueList)):0; sec = len>5? nl->IntValue(nl->Sixth(ValueList)):0; ms = 0; if(len==7){ ValueList = nl->Rest(ValueList); ms = nl->IntValue(nl->Sixth(ValueList)); } // check the ranges if(!IsValid(y,m,d)) return false; if(h<0 || h>23) return false; if(min<0 || min > 59) return false; if(sec<0 || sec > 59) return false; if(ms<0 || ms > 999) return false; // set the values int64_t day = ToJulian(y,m,d); int64_t milliseconds = (((h*60)+min)*60 + sec)*1000 +ms; this->value = day*MILLISECONDS + milliseconds; SetDefined(true); return true; } // (julianday milliseconds) // for durations if(nl->ListLength(ValueList)!=2){ return false; } if(type == (instanttype)) return false; ListExpr DayList = nl->First(ValueList); ListExpr MSecList = nl->Second(ValueList); if(nl->AtomType(DayList)!=IntType || nl->AtomType(MSecList)!=IntType){ return false; } int64_t day = nl->IntValue(DayList); int64_t milliseconds = nl->IntValue(MSecList); this->value = day*MILLISECONDS + milliseconds; return true; } /* ~CompareTo~ This function compares this DateTime instance with another one. The result will be: * -1 if this instance is before P2 * 0 if this instance is equals to P2 * 1 if this instance is after P2 The types of the arguments has to be equals. */ int DateTime::CompareTo(const DateTime* P2)const{ if(GetType()!=P2->GetType()){ cerr << "try to compare " << this->ToString() << " with " << P2->ToString() << endl; assert(GetType()==P2->GetType()); } if(!IsDefined() && !P2->IsDefined()) return 0; if(!IsDefined() && P2->IsDefined()) return -1; if(IsDefined() && !P2->IsDefined()) return 1; // at this point this and P2 are defined if(value < P2->value) return -1; if(value > P2->value) return 1; return 0; } /* ~Operators for Comparisons~ */ bool DateTime::operator==(const DateTime& T2)const{ return CompareTo(&T2)==0; } bool DateTime::operator!=(const DateTime& T2)const{ return CompareTo(&T2)!=0; } bool DateTime::operator<(const DateTime& T2)const{ return CompareTo(&T2)<0; } bool DateTime::operator>(const DateTime& T2)const{ return CompareTo(&T2)>0; } bool DateTime::operator<=(const DateTime& T2)const{ return CompareTo(&T2)<=0; } bool DateTime::operator>=(const DateTime& T2)const{ return CompareTo(&T2)>=0; } /* ~Clone~ This funtion returns a copy of this instance. */ DateTime* DateTime::Clone() const { return new DateTime(*this); } /* ~Split~ The function ~Split~ splits a duration into two ones. */ bool DateTime::Split(const double delta, DateTime& Rest){ assert(type == (durationtype)); assert((delta>=0) && (delta<=1)); Rest.Equalize(this); Mul(delta); Rest.Minus(this); return true; } /* ~Compare~ This function compare this DateTime with the given Attribute. */ int DateTime::Compare(const Attribute* arg) const{ return CompareTo( (const DateTime*) arg); } /* ~Adjacent~ We treat time as continuous. For this reason, in our discrete representation we never find adjacent instants and the result will be __false__. */ bool DateTime::Adjacent(const Attribute* arg) const{ return false; /* // adjacent in discrete case: const DateTime* T2 = (const DateTime*) arg; if(day==T2->day && abs(milliseconds-T2->milliseconds)==1) return true; if((day-1==T2->day) && (milliseconds==MILLISECONDS-1) && (T2->milliseconds==0)) return true; if( (day==T2->day-1) && (milliseconds==0) && (T2->milliseconds==MILLISECONDS-1)) return true; return false; */ } /* ~Sizeof~ The function ~Sizeof~ returns the ~sizeof~ of and instance of the ~DateTime~ class. */ size_t DateTime::Sizeof() const{ return sizeof(*this); } /* ~HashValue~ This function return the HashValue for this DateTime instance. */ size_t DateTime::HashValue() const{ if(!IsDefined()) return 0; return (size_t) value; } /* ~CopyFrom~ This Time instance take its value from arg if this function is called. */ void DateTime::CopyFrom(const Attribute* arg){ Equalize(((const DateTime*) arg)); } /* ~add~ Adds P2 to this instance. P2 remains unchanged. The ~Add~ function requires least one argument to be a duration type. */ void DateTime::Add(const DateTime* P2){ // do not allow to add two instants assert( (type == (durationtype)) || (P2->type == durationtype)); if(P2->type==instanttype){ this->type = instanttype; } if(!IsDefined()) return; if(!P2->IsDefined()){ SetDefined(false); return; } value += P2->value; } /* ~Operator +~ This operator has the same functionality like the ~Add~ function returning the result in a new instance. */ DateTime DateTime::operator+(const DateTime& T2)const{ DateTime Result(*this); Result.Add(&T2); return Result; } /* ~Operator +=~ This operator has the same functionality like the ~Add~ function. */ DateTime DateTime::operator+=(const DateTime& T2){ Add(&T2); return *this; } /* ~Operator -=~ This operator has the same functionality like the ~Minus~ function. */ DateTime DateTime::operator-=(const DateTime& T2){ Minus(&T2); return *this; } /* ~minus~ Subtracts P2 from this instance. If this instance is of type duration the, type of the argument has also to be a duration. Its possible that this function changes the type of this instance. */ void DateTime::Minus(const DateTime* P2) { assert(type ==(instanttype) || P2->type==(durationtype)); if(P2->type==instanttype){ type=durationtype; } if(!IsDefined()){ return; } if(!P2->IsDefined()){ SetDefined(false); return; } value -= P2->value; } /* ~Operator -~ This operator has the same functionality like the ~Minus~ function returning the result in a new instance. */ DateTime DateTime::operator-(const DateTime& T2)const{ DateTime Result(*this); Result.Minus(&T2); return Result; } /* ~Operator /~ This Operator divides a DateTime by another dateTime */ double DateTime::operator/(const DateTime& T2)const{ double myms = (double)(value); double t2ms = (double) T2.value; return myms / t2ms; } /* ~Operator /~ This Operator divides a DateTime by an integer */ DateTime DateTime::operator/(const int32_t divisor)const{ assert(type==(durationtype)); assert(divisor != 0); int64_t v = value / divisor; DateTime res(durationtype,v); return res; } /* ~mul~ Computes a multiple of a duration. */ void DateTime::Mul(const int32_t factor){ assert(type==(durationtype)); value *= factor; } /* ~mul~ Computes a multiple of a duration. This function is not numerical robust. Use this function only when you know what you do. */ void DateTime::Mul(const double factor){ value = (int64_t)(value*factor + 0.5); } /* ~Div~ This operator computes how often ~dividend~ is contained whithin this DateTime. This DateTime, the dividend, and ~remainder~ must be of type ~duration~. */ int64_t DateTime::Div(const DateTime& dividend, DateTime& remainder){ int64_t res = value / dividend.value; int64_t rem = value % dividend.value; remainder.SetDefined(true); remainder.value = rem; return res; } /* ~Operator mul~ This operator has the same functionality like the ~Mul~ function returning the result in a new instance. */ DateTime DateTime::operator*(const int32_t factor)const{ DateTime Result(*this); Result.Mul(factor); return Result; } DateTime DateTime::operator*(const double factor)const{ DateTime Result(*this); Result.Mul(factor); return Result; } /* ~Abs~ ~Abs~ compute the absolute value of a duration. */ void DateTime::Abs(){ if(value<0){ value = -value; } } /* ~ToListExpr~ This functions returns this time value in nested list format. The argument controls the format of the output. If absolute is false, the value-representation will be a list containing two int atoms. The first integer is the day of this time and the second one the part of this day in milliseconds. If the parameter is true, the value will be a string in format year-month-day-hour:minute:second.millisecond */ ListExpr DateTime::ToListExpr(const bool typeincluded)const { assert(IsDefined() ); ListExpr value; if(type==(instanttype)){ if( (this->valuevalue>MAX_REPRESENTABLE ) && !IsMinimum() && !IsMaximum()){ value = nl->RealAtom(ToDouble()); }else{ value = nl->StringAtom(this->ToString()); } } else { // a duration int64_t day = GetDay(); int32_t day2=0; int32_t ms = GetAllMilliSeconds(); if(day != ((int32_t) day)){ // out of the representable range ms = 0; if(day<0){ day2 = numeric_limits::min(); } else { day2 = numeric_limits::max(); } } else { day2 = (int32_t) day; } value = nl->TwoElemList( nl->IntAtom(day2), nl->IntAtom(ms) ); } if(typeincluded) if(type==(instanttype)) return nl->TwoElemList(nl->SymbolAtom(DateTime::BasicType()),value); else if(type==(durationtype)) return nl->TwoElemList(nl->SymbolAtom(Duration::BasicType()),value); else return nl->TwoElemList(nl->SymbolAtom("datetime"),value); else return value; } /* ~Equalize~ This function changes the value of this Time instance to be equal to P2. */ void DateTime::Equalize(const DateTime* P2){ this->type = P2->type; this->SetDefined(P2->IsDefined()); this->value = P2->value; } /* ~SetToZero~ A call of this function will set the value of this datetime to be zero, this means to have length zero or be the NULLDATE respectively. */ void DateTime::SetToZero(){ value =0; SetDefined(true); } /* ~IsZero~ ~IsZero~ returns true iff this */ bool DateTime::IsZero()const { return IsDefined() && value==0; } /* ~LessThanZero~ This function returns true if this instnace is before the Null-Day */ bool DateTime::LessThanZero()const{ return IsDefined() && value < 0; } SmiSize DateTime::SizeOfChars() const { return ToString().length()+1; } void DateTime::WriteTo( char *dest ) const { strcpy( dest, ToString().c_str() ); } void DateTime::ReadFrom( const char *src ) { ReadFrom( string(src) ); } DateTime GetNow() { DateTime dt(instanttype); dt.Now(); return dt; } /* 2 Algebra Functions 2.1 In and Out functions */ ListExpr OutDateTime( ListExpr typeInfo, Word value ){ DateTime* T = (DateTime*) value.addr; if( T->IsDefined() ) return T->ToListExpr(false); else return nl->SymbolAtom(Symbol::UNDEFINED()); } Word InInstant( const ListExpr typeInfo, const ListExpr instance, const int errorPos, ListExpr& errorInfo, bool& correct ){ DateTime* T = new DateTime(instanttype); ListExpr value = instance; if( !nl->IsAtom(instance) && (nl->ListLength(instance)==2) ){ if(nl->IsEqual(nl->First(instance),DateTime::BasicType())) value = nl->Second(instance); } if(T->ReadFrom(value,false)){ correct=true; return SetWord(T); } correct = false; delete(T); return SetWord(Address(0)); } Word InInstantValueOnly( const ListExpr typeInfo, const ListExpr instance, const int errorPos, ListExpr& errorInfo, bool& correct ){ DateTime* T = new DateTime(instanttype); if(T->ReadFrom(instance,false)){ correct=true; return SetWord(T); } correct = false; delete(T); return SetWord(Address(0)); } Word InDuration( const ListExpr typeInfo, const ListExpr instance, const int errorPos, ListExpr& errorInfo, bool& correct ){ DateTime* T = new DateTime(durationtype); if(T->ReadFrom(instance,false)){ correct=true; return SetWord(T); } correct = false; delete(T); return SetWord(Address(0)); } /* 2.2 Property Functions */ ListExpr InstantProperty(){ return (nl->TwoElemList( nl->FiveElemList( nl->StringAtom("Signature"), nl->StringAtom("Example Type List"), nl->StringAtom("List Rep"), nl->StringAtom("Example List"), nl->StringAtom("Remarks")), nl->FiveElemList( nl->StringAtom("-> Data"), nl->StringAtom(DateTime::BasicType()), nl->StringAtom(CcString::BasicType()), nl->StringAtom("2004-4-12-8:03:32.645"), nl->StringAtom("This type represents a point of time") ))); } ListExpr DurationProperty(){ return (nl->TwoElemList( nl->FiveElemList( nl->StringAtom("Signature"), nl->StringAtom("Example Type List"), nl->StringAtom("List Rep"), nl->StringAtom("Example List"), nl->StringAtom("Remarks")), nl->FiveElemList( nl->StringAtom("-> Data"), nl->StringAtom(DateTime::BasicType()), nl->StringAtom("(int int)"), nl->StringAtom("(12 273673)"), nl->StringAtom("the arguments are days and milliseconds") ))); } /* 2.3 ~Create~ function */ Word CreateInstant(const ListExpr typeInfo){ return SetWord(new DateTime(instanttype)); } Word CreateDuration(const ListExpr typeInfo){ return SetWord(new DateTime(durationtype)); } /* 2.4 ~Delete~ function */ void DeleteDateTime(const ListExpr typeInfo, Word &w){ DateTime* T = (DateTime*) w.addr; delete T; w.addr=0; } /* 2.5 ~Open~ function */ bool OpenDateTime( SmiRecord& valueRecord, size_t& offset, const ListExpr typeInfo, Word& value ){ // This Open function is implemented in the Attribute class // and uses the same method of the Tuple manager to open objects DateTime *dt = (DateTime*)Attribute::Open( valueRecord, offset, typeInfo ); value = SetWord( dt ); return true; } /* 2.6 ~Save~ function */ bool SaveDateTime( SmiRecord& valueRecord, size_t& offset, const ListExpr typeInfo, Word& value ){ DateTime *dt = (DateTime *)value.addr; Attribute::Save( valueRecord, offset, typeInfo, dt ); return true; } /* 2.7 ~Close~ function */ void CloseDateTime( const ListExpr typeInfo, Word& w ){ delete (DateTime *)w.addr; w.addr = 0; } /* 2.8 ~Clone~ function */ Word CloneDateTime( const ListExpr typeInfo, const Word& w ) { return SetWord( ((DateTime *)w.addr)->Clone() ); } /* 2.9 ~SizeOf~-Function */ int SizeOfDateTime(){ return sizeof(DateTime); } /* 2.10 ~Cast~-Function */ void* CastDateTime( void* addr ) { return new (addr) DateTime; } /* 2.11 Kind Checking Function This function checks whether the type constructor is applied correctly. Since the type constructor don't have arguments, this is trivial. */ bool CheckInstant(ListExpr type, ListExpr& errorInfo){ return (nl->IsEqual(type,DateTime::BasicType())); } bool CheckDuration(ListExpr type, ListExpr& errorInfo){ return (nl->IsEqual(type,Duration::BasicType())); } /* 3 Type Constructor */ TypeConstructor instant( DateTime::BasicType(), //name InstantProperty, //property function describing signature OutDateTime, InInstantValueOnly, //Out and In functions 0, //SaveToList and 0, // RestoreFromList functions CreateInstant, DeleteDateTime,//object creation and deletion OpenDateTime, SaveDateTime,//object open and save CloseDateTime, CloneDateTime,//object close and clone CastDateTime, //cast function SizeOfDateTime, //sizeof function CheckInstant ); //kind checking function TypeConstructor duration( Duration::BasicType(), //name DurationProperty, //property function describing signature OutDateTime, InDuration, //Out and In functions 0, //SaveToList and 0, // RestoreFromList functions CreateDuration, DeleteDateTime, //object creation and deletion OpenDateTime, SaveDateTime, //object open and save CloseDateTime, CloneDateTime, //object close and clone CastDateTime, //cast function SizeOfDateTime, //sizeof function CheckDuration ); //kind checking function /* 4 Operators 4.1 Type Mappings */ ListExpr VoidInstant(ListExpr args){ if(nl->IsEmpty(args)) return nl->SymbolAtom(DateTime::BasicType()); ErrorReporter::ReportError("no argument allowed\n"); return nl->SymbolAtom(Symbol::TYPEERROR()); } ListExpr IntBool(ListExpr args){ if(nl->ListLength(args)!=1){ ErrorReporter::ReportError("one argument expected\n"); return nl->SymbolAtom(Symbol::TYPEERROR()); } if(nl->IsEqual(nl->First(args),CcInt::BasicType())) return nl->SymbolAtom(CcBool::BasicType()); ErrorReporter::ReportError("argument must be of type int\n"); return nl->SymbolAtom(Symbol::TYPEERROR()); } ListExpr InstantInt(ListExpr args){ if(nl->ListLength(args)==1){ if(nl->IsEqual(nl->First(args),DateTime::BasicType())){ return nl->SymbolAtom(CcInt::BasicType()); } else { ErrorReporter::ReportError("instant parameter expected \n"); } } ErrorReporter::ReportError("exactly one argument required"); return nl->SymbolAtom(Symbol::TYPEERROR()); } ListExpr PlusCheck(ListExpr args){ if(nl->ListLength(args)!=2){ ErrorReporter::ReportError("plus expects two arguments\n"); return nl->SymbolAtom(Symbol::TYPEERROR()); } if(nl->IsEqual(nl->First(args),DateTime::BasicType()) && nl->IsEqual(nl->Second(args),Duration::BasicType())) return nl->SymbolAtom(DateTime::BasicType()); if(nl->IsEqual(nl->First(args),Duration::BasicType()) && nl->IsEqual(nl->Second(args),DateTime::BasicType())) return nl->SymbolAtom(DateTime::BasicType()); if(nl->IsEqual(nl->First(args),Duration::BasicType()) && nl->IsEqual(nl->Second(args),Duration::BasicType())) return nl->SymbolAtom(Duration::BasicType()); ErrorReporter::ReportError("duration/instant or" " duration/duration expected\n"); return nl->SymbolAtom(Symbol::TYPEERROR()); } ListExpr MinusCheck(ListExpr args){ if(nl->ListLength(args)!=2){ ErrorReporter::ReportError("operator - requires two arguments\n"); return nl->SymbolAtom(Symbol::TYPEERROR()); } if(nl->IsEqual(nl->First(args),DateTime::BasicType()) && nl->IsEqual(nl->Second(args),Duration::BasicType())) return nl->SymbolAtom(DateTime::BasicType()); if(nl->IsEqual(nl->First(args),DateTime::BasicType()) && nl->IsEqual(nl->Second(args),DateTime::BasicType())) return nl->SymbolAtom(Duration::BasicType()); if(nl->IsEqual(nl->First(args),Duration::BasicType()) && nl->IsEqual(nl->Second(args),Duration::BasicType())) return nl->SymbolAtom(Duration::BasicType()); ErrorReporter::ReportError("duration/instant or" " duration/duration expected\n"); return nl->SymbolAtom(Symbol::TYPEERROR()); } ListExpr DurationIntDuration(ListExpr args){ if(nl->ListLength(args)!=2){ ErrorReporter::ReportError("Two arguments required\n"); return nl->SymbolAtom(Symbol::TYPEERROR()); } if(nl->IsEqual(nl->First(args),Duration::BasicType()) && nl->IsEqual(nl->Second(args),CcInt::BasicType())) return nl->SymbolAtom(Duration::BasicType()); ErrorReporter::ReportError("duration x int expected\n" ); return nl->SymbolAtom(Symbol::TYPEERROR()); } ListExpr MulTM(ListExpr args){ string err ="{int,real} x duration or duration x {int,real} expected"; if(!nl->HasLength(args,2)){ return listutils::typeError(err); } ListExpr arg1 = nl->First(args); ListExpr arg2 = nl->Second(args); if(Duration::checkType(arg1)){ if(!CcReal::checkType(arg2) && !CcInt::checkType(arg2)){ return listutils::typeError(err); } } else if(Duration::checkType(arg2)){ if(!CcReal::checkType(arg1) && !CcInt::checkType(arg1)){ return listutils::typeError(err); } } else { return listutils::typeError(err); } return nl->SymbolAtom(Duration::BasicType()); } ListExpr DurationRealDuration(ListExpr args){ if(nl->ListLength(args)!=2){ ErrorReporter::ReportError("Two arguments required\n"); return nl->SymbolAtom(Symbol::TYPEERROR()); } if(nl->IsEqual(nl->First(args),Duration::BasicType()) && nl->IsEqual(nl->Second(args),CcReal::BasicType())) return nl->SymbolAtom(Duration::BasicType()); ErrorReporter::ReportError("duration x real expected\n" ); return nl->SymbolAtom(Symbol::TYPEERROR()); } ListExpr InstantString(ListExpr args){ if(nl->ListLength(args)!=1){ ErrorReporter::ReportError("one argument expected\n"); return nl->SymbolAtom(Symbol::TYPEERROR()); } if(nl->IsEqual(nl->First(args),DateTime::BasicType())) return nl->SymbolAtom(CcString::BasicType()); ErrorReporter::ReportError("instant expected\n"); return nl->SymbolAtom(Symbol::TYPEERROR()); } ListExpr DateTimeString(ListExpr args){ if(nl->ListLength(args)!=1){ ErrorReporter::ReportError("one argument expected\n"); return nl->SymbolAtom(Symbol::TYPEERROR()); } if(nl->IsEqual(nl->First(args),DateTime::BasicType()) || nl->IsEqual(nl->First(args),Duration::BasicType())) return nl->SymbolAtom(CcString::BasicType()); ErrorReporter::ReportError("instant or duration expected\n"); return nl->SymbolAtom(Symbol::TYPEERROR()); } ListExpr CheckComparisons(ListExpr args){ if(nl->ListLength(args)!=2){ ErrorReporter::ReportError("two arguments required\n"); return nl->SymbolAtom(Symbol::TYPEERROR()); } if(nl->IsEqual(nl->First(args),DateTime::BasicType()) && nl->IsEqual(nl->Second(args),DateTime::BasicType())) return nl->SymbolAtom(CcBool::BasicType()); if(nl->IsEqual(nl->First(args),Duration::BasicType()) && nl->IsEqual(nl->Second(args),Duration::BasicType())) return nl->SymbolAtom(CcBool::BasicType()); ErrorReporter::ReportError("(instant x instant) or" "(duratin x duration) required"); return nl->SymbolAtom(Symbol::TYPEERROR()); } ListExpr TheInstantTM(ListExpr args){ int l = nl->ListLength(args); if(l<1 || l>7){ ErrorReporter::ReportError(" 1..7 arguements required\n"); return nl->SymbolAtom(Symbol::TYPEERROR()); } ListExpr rest = args; while(!nl->IsEmpty(rest)){ if(!nl->IsEqual(nl->First(rest),CcInt::BasicType())){ ErrorReporter::ReportError("All arguments must be of type int\n"); return nl->SymbolAtom(Symbol::TYPEERROR()); } rest = nl->Rest(rest); } return nl->SymbolAtom(DateTime::BasicType()); } ListExpr DivTM(ListExpr args){ if(nl->ListLength(args)!=2){ ErrorReporter::ReportError("Two arguments required\n"); return nl->SymbolAtom(Symbol::TYPEERROR()); } if(!nl->IsEqual(nl->First(args),Duration::BasicType()) || !nl->IsEqual(nl->Second(args),Duration::BasicType())){ ErrorReporter::ReportError("two duration values expected\n"); return nl->SymbolAtom(Symbol::TYPEERROR()); } return nl->SymbolAtom(CcInt::BasicType()); } ListExpr DivTM2(ListExpr args){ string err ="duration x int expected"; if(!nl->HasLength(args,2)){ return listutils::typeError(err); } if(!Duration::checkType(nl->First(args)) || !CcInt::checkType(nl->Second(args))){ return listutils::typeError(err); } return nl->SymbolAtom(Duration::BasicType()); } ListExpr MinMaxInstantTM(ListExpr args){ if(nl->IsEmpty(args)){ return nl->SymbolAtom(DateTime::BasicType()); } ErrorReporter::ReportError("no arguments allowed"); return nl->SymbolAtom(Symbol::TYPEERROR()); } ListExpr MinMaxDurationTM(ListExpr args){ if(nl->IsEmpty(args)){ return nl->SymbolAtom(Duration::BasicType()); } ErrorReporter::ReportError("no arguments allowed"); return nl->SymbolAtom(Symbol::TYPEERROR()); } ListExpr CreateDurationTM(ListExpr args){ if(nl->ListLength(args)==1){ if ( nl->IsEqual(nl->First(args),CcReal::BasicType()) ) { return nl->SymbolAtom(Duration::BasicType()); } else { ErrorReporter::ReportError("one real value expected\n"); return nl->SymbolAtom(Symbol::TYPEERROR()); } } if(!nl->HasLength(args,2)){ return listutils::typeError("one or two arguments required"); } ListExpr first = nl->First(args); ListExpr second = nl->Second(args); if(CcInt::checkType(first) && CcInt::checkType(second)){ return listutils::basicSymbol(); } if(CcInt::checkType(first) && CcString::checkType(second)){ return listutils::basicSymbol(); } if(LongInt::checkType(first) && CcString::checkType(second)){ return listutils::basicSymbol(); } return listutils::typeError("real or (int x int ) or " "([int,longint} x string) required"); } ListExpr CreateInstantTM(ListExpr args){ if(nl->ListLength(args)==1){ if ( nl->IsEqual(nl->First(args),CcReal::BasicType()) ) { return nl->SymbolAtom(DateTime::BasicType()); } else { ErrorReporter::ReportError("one real value expected\n"); return nl->SymbolAtom(Symbol::TYPEERROR()); } } if(nl->ListLength(args)==2){ if(nl->IsEqual(nl->First(args),CcInt::BasicType()) && nl->IsEqual(nl->Second(args),CcInt::BasicType())) { return nl->SymbolAtom(DateTime::BasicType()); } else { ErrorReporter::ReportError("two int values expected\n"); return nl->SymbolAtom(Symbol::TYPEERROR()); } } ErrorReporter::ReportError("One or two arguments required\n"); return nl->SymbolAtom(Symbol::TYPEERROR()); } ListExpr Duration2RealTM(ListExpr args){ if(nl->ListLength(args)==1){ if ( nl->IsEqual(nl->First(args),Duration::BasicType()) ) { return nl->SymbolAtom(CcReal::BasicType()); } else { ErrorReporter::ReportError("one duration value expected\n"); return nl->SymbolAtom(Symbol::TYPEERROR()); } } ErrorReporter::ReportError("One argument required\n"); return nl->SymbolAtom(Symbol::TYPEERROR()); } ListExpr Instant2RealTM(ListExpr args){ if(nl->ListLength(args)==1){ if ( nl->IsEqual(nl->First(args),DateTime::BasicType()) ) { return nl->SymbolAtom(CcReal::BasicType()); } else { ErrorReporter::ReportError("one instant value expected\n"); return nl->SymbolAtom(Symbol::TYPEERROR()); } } ErrorReporter::ReportError("One argument required\n"); return nl->SymbolAtom(Symbol::TYPEERROR()); } ListExpr InstantOrDurationIntTM(ListExpr args){ if(nl->ListLength(args)==1){ if(nl->IsEqual(nl->First(args),DateTime::BasicType())){ return nl->SymbolAtom(CcInt::BasicType()); } if(nl->IsEqual(nl->First(args),Duration::BasicType())){ return nl->SymbolAtom(CcInt::BasicType()); } else { ErrorReporter::ReportError("instant/duration parameter expected \n"); } } ErrorReporter::ReportError("exactly one argument required"); return nl->SymbolAtom(Symbol::TYPEERROR()); } ListExpr str2instantTM(ListExpr args){ if(!nl->HasLength(args,1) && !nl->HasLength(args,2)){ return listutils::typeError("string expected"); } if(!listutils::isSymbol(nl->First(args),CcString::BasicType()) && !listutils::isSymbol(nl->First(args),FText::BasicType())){ return listutils::typeError("{string | text} [x string} expected"); } if(nl->HasLength(args,2)){ if(!CcString::checkType(nl->Second(args))){ return listutils::typeError("{string | text} [x string} expected"); } } return nl->SymbolAtom(DateTime::BasicType()); } ListExpr transformDateTimeTM(ListExpr args){ if(!nl->HasLength(args,1) ){ return listutils::typeError("wrong number of " "arguments-one string expected"); } if(!listutils::isSymbol(nl->First(args),CcString::BasicType())) { return listutils::typeError("string expected"); } return nl->SymbolAtom(CcString::BasicType()); } /* 4.2 Value Mappings */ int LeapYearFun(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); CcInt* Y = (CcInt*) args[0].addr; DateTime T; bool res = T.IsValid(Y->GetIntval(),2,29); ((CcBool*) result.addr)->Set(true,res); return 0; } int TheInstantFun_Int1(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); ((DateTime*) result.addr)->Set(((CcInt*)args[0].addr)->GetIntval()); return 0; } int TheInstantFun_Int2(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); ((DateTime*) result.addr)->Set(((CcInt*)args[0].addr)->GetIntval(), ((CcInt*)args[1].addr)->GetIntval() ); return 0; } int TheInstantFun_Int3(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); ((DateTime*) result.addr)->Set(((CcInt*)args[0].addr)->GetIntval(), ((CcInt*)args[1].addr)->GetIntval(), ((CcInt*)args[2].addr)->GetIntval() ); return 0; } int TheInstantFun_Int4(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); ((DateTime*) result.addr)->Set(((CcInt*)args[0].addr)->GetIntval(), ((CcInt*)args[1].addr)->GetIntval(), ((CcInt*)args[2].addr)->GetIntval(), ((CcInt*)args[3].addr)->GetIntval() ); return 0; } int TheInstantFun_Int5(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); ((DateTime*) result.addr)->Set(((CcInt*)args[0].addr)->GetIntval(), ((CcInt*)args[1].addr)->GetIntval(), ((CcInt*)args[2].addr)->GetIntval(), ((CcInt*)args[3].addr)->GetIntval(), ((CcInt*)args[4].addr)->GetIntval() ); return 0; } int TheInstantFun_Int6(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); ((DateTime*) result.addr)->Set(((CcInt*)args[0].addr)->GetIntval(), ((CcInt*)args[1].addr)->GetIntval(), ((CcInt*)args[2].addr)->GetIntval(), ((CcInt*)args[3].addr)->GetIntval(), ((CcInt*)args[4].addr)->GetIntval(), ((CcInt*)args[5].addr)->GetIntval() ); return 0; } int TheInstantFun_Int7(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); ((DateTime*) result.addr)->Set(((CcInt*)args[0].addr)->GetIntval(), ((CcInt*)args[1].addr)->GetIntval(), ((CcInt*)args[2].addr)->GetIntval(), ((CcInt*)args[3].addr)->GetIntval(), ((CcInt*)args[4].addr)->GetIntval(), ((CcInt*)args[5].addr)->GetIntval(), ((CcInt*)args[6].addr)->GetIntval() ); return 0; } int NowFun(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); ((DateTime*) result.addr)->Now(); return 0; } int TodayFun(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); ((DateTime*) result.addr)->Today(); return 0; } int DayFun(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); DateTime* T = (DateTime*) args[0].addr; ((CcInt*) result.addr)->Set(true,T->GetGregDay()); return 0; } int DurationDayFun(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); DateTime* T = (DateTime*) args[0].addr; ((CcInt*) result.addr)->Set(true,T->GetDay()); return 0; } int MonthFun(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); DateTime* T = (DateTime*) args[0].addr; ((CcInt*) result.addr)->Set(true,T->GetMonth()); return 0; } int YearFun(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); DateTime* T = (DateTime*) args[0].addr; ((CcInt*) result.addr)->Set(true,T->GetYear()); return 0; } int HourFun(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); DateTime* T = (DateTime*) args[0].addr; ((CcInt*) result.addr)->Set(true,T->GetHour()); return 0; } int MinuteFun(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); DateTime* T = (DateTime*) args[0].addr; ((CcInt*) result.addr)->Set(true,T->GetMinute()); return 0; } int SecondFun(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); DateTime* T = (DateTime*) args[0].addr; ((CcInt*) result.addr)->Set(true,T->GetSecond()); return 0; } int MillisecondFun(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); DateTime* T = (DateTime*) args[0].addr; ((CcInt*) result.addr)->Set(true,T->GetMillisecond()); return 0; } int DurationMillisecondFun(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); DateTime* T = (DateTime*) args[0].addr; ((CcInt*) result.addr)->Set(true,T->GetAllMilliSeconds()); return 0; } int AddFun(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); DateTime* T1 = (DateTime*) args[0].addr; DateTime* T2 = (DateTime*) args[1].addr; DateTime TRes = (*T1) + (*T2); ((DateTime*) result.addr)->Equalize(&TRes); return 0; } int MinusFun(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); DateTime* T1 = (DateTime*) args[0].addr; DateTime* T2 = (DateTime*) args[1].addr; DateTime TRes = (*T1)-(*T2); ((DateTime*) result.addr)->Equalize(&TRes); return 0; } int EqualsFun(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); DateTime* T1 = (DateTime*) args[0].addr; DateTime* T2 = (DateTime*) args[1].addr; bool res = (*T1) == (*T2); ((CcBool*) result.addr)->Set(true,res); return 0; } int BeforeFun(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); DateTime* T1 = (DateTime*) args[0].addr; DateTime* T2 = (DateTime*) args[1].addr; bool res = (*T1) < (*T2); ((CcBool*) result.addr)->Set(true,res); return 0; } int AfterFun(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); DateTime* T1 = (DateTime*) args[0].addr; DateTime* T2 = (DateTime*) args[1].addr; bool res = (*T1) > (*T2); ((CcBool*) result.addr)->Set(true,res); return 0; } template int MulFunDurNum(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); DateTime* dur = (DateTime*) args[0].addr; T* num = (T*) args[1].addr; if(!dur->IsDefined() || !num->IsDefined()){ ((DateTime*) result.addr)->SetDefined(false); return 0; } *((DateTime*) result.addr) = *dur * num->GetValue(); return 0; } template int MulFunNumDur(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); T* num = (T*) args[0].addr; DateTime* dur = (DateTime*) args[1].addr; if(!dur->IsDefined() || !num->IsDefined()){ ((DateTime*) result.addr)->SetDefined(false); return 0; } *((DateTime*) result.addr) = *dur * num->GetValue(); return 0; } ValueMapping MulVM[] = { MulFunNumDur, MulFunNumDur, MulFunDurNum, MulFunDurNum }; int MulSelect(ListExpr args){ ListExpr numArg; int offset = 0; if(Duration::checkType(nl->First(args))){ offset = 2; numArg = nl->Second(args); } else { numArg = nl->First(args); } int p = CcInt::checkType(numArg)?0:1; return offset + p; } int DivFun(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); DateTime* T1 = (DateTime*) args[0].addr; DateTime* T2 = (DateTime*) args[1].addr; CcInt* res = (CcInt*) result.addr; if(!T1->IsDefined() || !T2->IsDefined() || T2->IsZero()){ res->SetDefined(false); return 0; } DateTime Remainder(durationtype); int32_t ires = (int32_t) (T1->Div( (*T2),Remainder)); res->Set(true,ires); return 0; } int DivFun2(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); DateTime* res = (DateTime*) result.addr; DateTime* T1 = (DateTime*) args[0].addr; CcInt* T2 = (CcInt*) args[1].addr; if(!T1->IsDefined() || !T2->IsDefined()){ res->SetDefined(false); return 0; } int value = T2->GetValue(); if(value==0){ res->SetDefined(false); return 0; } (*res) = (*T1) / value; return 0; } int MinFun(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); ((DateTime*) result.addr)->ToMinimum(); return 0; } int MaxFun(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); ((DateTime*) result.addr)->ToMaximum(); return 0; } int WeekdayFun(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); DateTime* T = (DateTime*) args[0].addr; int day = T->GetWeekday(); STRING_T* WD; switch(day){ case 0 : WD = (STRING_T*) "Monday"; break; case 1 : WD = (STRING_T*) "Tuesday"; break; case 2 : WD = (STRING_T*) "Wednesday"; break; case 3 : WD = (STRING_T*) "Thursday"; break; case 4 : WD = (STRING_T*) "Friday"; break; case 5 : WD = (STRING_T*) "Saturday"; break; case 6 : WD = (STRING_T*) "Sunday"; break; default : WD = (STRING_T*)"Errorsday"; break; } ((CcString*)result.addr)->Set(true,WD); return 0; } int DateTime2RealFun(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); DateTime* T = (DateTime*) args[0].addr; if(T->IsDefined()) { double days = T->ToDouble(); ((CcReal*)result.addr)->Set(true,days); } else { ((CcReal*)result.addr)->Set(false,0.0); } return 0; } int CreateDurationFromRealFun(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); CcReal* R = (CcReal*) args[0].addr; DateTime* T = (DateTime*)result.addr; T->SetType(durationtype); if(R->IsDefined()) { double days = R->GetRealval(); T->ReadFrom(days); T->SetDefined(true); } else { T->ReadFrom(0.0); T->SetDefined(false); } return 0; } int CreateDurationFromIntIntFun(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); CcInt* Idays = (CcInt*) args[0].addr; CcInt* Imsec = (CcInt*) args[1].addr; DateTime* T = (DateTime*)result.addr; T->SetType(durationtype); if(Idays->IsDefined() && Imsec->IsDefined() && Imsec->GetIntval() >= 0.0) { *T = DateTime(Idays->GetIntval(),Imsec->GetIntval(),durationtype); T->SetDefined(true); } else { *T = DateTime(0,0,durationtype); T->SetDefined(false); } return 0; } template int CreateDurationFromIntStringFun(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); IT* value = (IT*) args[0].addr; CcString* unit = (CcString*) args[1].addr; DateTime* res = (DateTime*)result.addr; if(!value->IsDefined() || !unit->IsDefined()){ res->SetDefined(false); return 0; } string u = unit->GetValue(); int64_t factor = 1; int64_t v = value->GetValue(); if(u=="ms"){ factor = 1; } else if(u=="s"){ factor=1000; } else if(u=="min"){ factor=60000; } else if(u=="h"){ factor=3600000; } else if(u=="d"){ factor = 86400000; } else { res->SetDefined(false); return 0; } res->ReadFrom(v*factor); return 0; } int CreateInstantFromRealFun(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); CcReal* R = (CcReal*) args[0].addr; DateTime* T = (DateTime*)result.addr; T->SetType(instanttype); if(R->IsDefined()) { double days = R->GetRealval(); T->ReadFrom(days); T->SetDefined(true); } else { T->ReadFrom(0.0); T->SetDefined(false); } return 0; } int CreateInstantFromIntIntFun(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); CcInt* Idays = (CcInt*) args[0].addr; CcInt* Imsec = (CcInt*) args[1].addr; DateTime* T = (DateTime*)result.addr; T->SetType(instanttype); if(Idays->IsDefined() && Imsec->IsDefined() && Imsec->GetIntval() >= 0.0) { *T = DateTime(Idays->GetIntval(),Imsec->GetIntval(),instanttype); T->SetDefined(true); } else { *T = DateTime(0,0,instanttype); T->SetDefined(false); } return 0; } int DateTimeToStringFun(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); DateTime *T = static_cast(args[0].addr); string rs = T->ToString(); ( static_cast(result.addr))->Set(true,rs); return 0; } template int str2instantVM(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); DateTime* res = static_cast(result.addr); T* arg = static_cast(args[0].addr); if(qp->GetNoSons(s)==1){ if(!arg->IsDefined()){ res->SetDefined(false); } else { if(!res->ReadFrom(arg->GetValue())){ res->SetDefined(false); } } } else { // format string is given CcString* Format = (CcString*) args[1].addr; if(!arg->IsDefined() || !Format->IsDefined()){ res->SetDefined(false); } else { if(!res->readFrom(arg->GetValue(), Format->GetValue())){ res->SetDefined(false); } } } return 0; } int transformDateTimeVM(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); CcString* chain = (CcString*) args[0].addr; CcString *res = (CcString*) result.addr; if(!chain->IsDefined()){ res->SetDefined(false); } else { std::string val = chain->GetValue(); char* r = convertDate(val.c_str()); if(r){ res->Set(true,r); free(r); } else { res->SetDefined(false); } } return 0; } /* 4.3 Specifications */ const string LeapYearSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( \"int -> bool\"" " \" _ leapyear \" " " \"checks whether the given int is a leap year\" " " \" query 2000 leapyear\" ))"; const string TheInstantSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Remarks\" \"Example\" )" " ( \" int (x int){0-6} -> instant\"" " \" theInstant(_,_,_,_,_,_,_) \" " " \"creates an instant from the arguments\"" " \"arguments are from years down to milliseconds\"" " \" query theInstant(2004,7,17)\" ))"; const string NowSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( \" -> instant\"" " \" now \" " " \"creates an instant from the current systemtime\" " " \" query now()\" ))"; const string TodaySpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( \" -> instant\"" " \" today \" " " \"creates an instant from the current systemtime\" " " \" query today()\" ))"; const string DaySpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( \"instant -> int\nduration -> int\"" "\" day_of ( _ ) \" " "\"return the day of this instant/duration\" " "\"query day_of(T1) \" ))"; const string MonthSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( \"instant -> int\"" " \" month_of ( _ ) \" " " \"return the month of this instant\" " " \" query month_of(T1) \" ))"; const string YearSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( \"instant -> int\"" " \" year_of ( _ ) \" " " \"return the year of this instant\" " " \" query year_of(T1) \" ))"; const string HourSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( \"instant -> int\"" " \" hour_of(_)\" " " \"return the hour of this instant\" " " \" query hour_of(T1) \" ))"; const string MinuteSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( \"instant -> int\"" " \"minute_of(_) \" " " \"return the minute of this instant\" " " \" query minute_of(T1) \" ))"; const string SecondSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( \"instant -> int\"" " \" second_of ( _ )\" " " \"return the second of this instant\" " " \" query second_of(T1) \" ))"; const string MillisecondSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( \"instant -> int\nduration -> int\"" "\" millisecond_of(_) \" " "\"return the millisecond of this instant/duration\" " "\"query millisecond_of(T1) \" ))"; const string AddSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( \"DateTime x DateTime -> DateTime\"" " \" _ + _ \" " " \" DateTime stands for instant or duration\" " " \" query T1 + D2\" ))"; const string MinusSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( \"DateTime x DateTime -> DateTime\"" " \" _ - _ \" " " \"Computes the difference\" " " \" query T1 - T2\" ))"; const string EqualsSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( \"DateTime_i x DateTime_i -> bool\"" "\" _ = _ \" " " \"checks for equality\" " " \" query T1 = T2\" ))"; const string LessSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( \"DateTime_i x DateTime_i -> bool\"" " \" _ < _ \" " " \"returns true if T1 is before (shorter than) t2\" " " \" query T1 < T2\" ))"; const string GreaterSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( \"DateTime_i x DateTime_i -> bool\"" " \" _ > _ \" " " \"returns true if T1 is after (longer than) T2\" " " \" query T1 > T2\" ))"; const string MulSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( 'duration x {int,real} -> duration | " "{int,real} x duration -> duration'" " \" _ * _ \" " " \"computes the multiple of a duration\" " " \" query D * 7.0\" ))"; const string WeekdaySpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( \"instant -> string\"" " \" weekday_of ( _ ) \" " " \"returns the weekday in human readable format\" " " \"query weekday_of(today())\" ))"; const string DivSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( \"duration x duration -> int\"" " \" _ / _ \" " " 'Computes how often the second argument is part of the first one' " " \"query a / b \" ))"; const string DivSpec2 = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( \"duration x int -> duration\"" " \" _ div _ \" " " 'Divides a duration value by an integer' " " \"query a div b \" ))"; const string MinInstantSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( \" -> instant\"" " \" minInstant() \" " " \"returns the minimum possible instant \" " " \"query minInstant() \" ))"; const string MaxInstantSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( \" -> instant\"" " \" maxInstant() \" " " \"returns the maximum possible instant \" " " \"query maxInstant() \" ))"; const string MinDurationSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( \" -> duration \"" " \" minDuration() \" " " 'returns the minimum representable duration value ' " " \"query minDuration() \" ))"; const string MaxDurationSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( \" -> duration \"" " \" maxDuration() \" " " 'returns the maximum representable duration value' " " \"query maxDuration() \" ))"; const string Duration2RealSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( \"duration -> real\"" "\"duration2real( _ ) \" " "'Converts the duration to a real giving the duration in days.' " "'query duration2real([const duration value (-5 1000)])' ))"; const string Instant2RealSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( \"instant -> real\"" "\"instant2real( _ ) \" " "'Converts the instant to a real giving the distance to " "the NULL_DAY in days.' " "'query duration2real([const instant value (-5 1000)])' ))"; const string CreateDurationSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( '(real) -> duration\n(int int) -> duration\nint x string ->duration '" "\"create_duration( _ )\ncreate_duration( _ , _ )\" " "'Create a duration value from a real (days) or a pair of int." "(days, milliseconds). Parameter milliseconds must be >=0.\n " " For the" " int x string argument types, the string denotes the unit in " "{ms, s, min, h,d}. '" "\"query create_duration(10, 5) \" ))"; const string CreateInstantSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( \"(real) -> instant\n(int int) -> instant \"" "\"create_instant( _ )\ncreate_instant( _ , _ )\" " "'Create an instant value from a real (days) or a pair of int " "(days, milliseconds). Parameter milliseconds must be >=0' " "\"query create_instant(10, 5) \" ))"; const string ToStringSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( \"{instant, duration} -> string \"" "\" tostring(_)\" " "'returns a string representation of an instant' " "\"query tostring(now()) \" ))"; const string str2instantSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( \"{string,text} [ x string] -> instant \"" "\" str2instant(_ [,_])\" " "'reads a instant from a string. The second (optional)" " string specifies the format of the string. In fact, the format" " string only specifies the order of the components. ' " "\"query str2instant(tostring(now)) \" ))"; const string transformDateTimeSpec = "((\"Signature\" \"Syntax\" \"Meaning\" \"Example\" )" " ( \"string -> string \"" "\" transformDateTime(_)\" " "'transform a given string format like [11/Oct/2016:16:22:31 for example" " into the string format: 2016-10-11-16:22:31 ' " "'query transformDateTime(tostring([11/Oct/2016:16:22:31))' ))"; /* 4.3 ValueMappings of overloaded Operators */ ValueMapping TheInstantValueMap[] = { TheInstantFun_Int1,TheInstantFun_Int2,TheInstantFun_Int3, TheInstantFun_Int4,TheInstantFun_Int5,TheInstantFun_Int6, TheInstantFun_Int7 }; ValueMapping CreateDurationValueMap[] = { CreateDurationFromRealFun, CreateDurationFromIntIntFun, CreateDurationFromIntStringFun, CreateDurationFromIntStringFun}; ValueMapping CreateInstantValueMap[] = { CreateInstantFromRealFun, CreateInstantFromIntIntFun }; ValueMapping DayValueMap[] = { DayFun, DurationDayFun}; ValueMapping MillisecondValueMap[] = { MillisecondFun, DurationMillisecondFun}; ValueMapping str2instantvm[] = { str2instantVM, str2instantVM }; /* 4.4 SelectionFunctions */ static int TheInstantSelect(ListExpr args){ return nl->ListLength(args)-1; } static int create_durationSelect(ListExpr args){ if(nl->HasLength(args,1)){ return 0; // real } if(CcInt::checkType(nl->Second(args))){ return 1; // int x int } // int x string || longint x string return CcInt::checkType(nl->First(args))?2:3; } static int InstantOrDurationIntSelect(ListExpr args){ if(nl->IsEqual(nl->First(args),DateTime::BasicType())) return 0; if(nl->IsEqual(nl->First(args),Duration::BasicType())) return 1; return -1; // should not happen } static int str2instantSelect(ListExpr args){ if(listutils::isSymbol(nl->First(args),CcString::BasicType())){ return 0; } else { // text return 1; } } /* 4.4 Definition of Operators */ Operator dt_leapyear( "leapyear", // name LeapYearSpec, // specification LeapYearFun, Operator::SimpleSelect, IntBool); Operator dt_now( "now", // name NowSpec, // specification NowFun, Operator::SimpleSelect, VoidInstant); Operator dt_today( "today", // name TodaySpec, // specification TodayFun, Operator::SimpleSelect, VoidInstant); Operator dt_day( "day_of", // name DaySpec, // specification 2, // number of functions DayValueMap, InstantOrDurationIntSelect, InstantOrDurationIntTM); Operator dt_month( "month_of", // name MonthSpec, // specification MonthFun, Operator::SimpleSelect, InstantInt); Operator dt_year( "year_of", // name YearSpec, // specification YearFun, Operator::SimpleSelect, InstantInt); Operator dt_hour( "hour_of", // name HourSpec, // specification HourFun, Operator::SimpleSelect, InstantInt); Operator dt_minute( "minute_of", // name MinuteSpec, // specification MinuteFun, Operator::SimpleSelect, InstantInt); Operator dt_second( "second_of", // name SecondSpec, // specification SecondFun, Operator::SimpleSelect, InstantInt); Operator dt_millisecond( "millisecond_of", // name MillisecondSpec, // specification 2, // number of functions MillisecondValueMap, InstantOrDurationIntSelect, InstantOrDurationIntTM); Operator dt_add( "+", // name AddSpec, // specification AddFun, Operator::SimpleSelect, PlusCheck); Operator dt_minus( "-", // name MinusSpec, // specification MinusFun, Operator::SimpleSelect, MinusCheck); Operator dt_div( "/", // name DivSpec, // specification DivFun, Operator::SimpleSelect, DivTM); Operator dt_div2( "div", // name DivSpec2, // specification DivFun2, Operator::SimpleSelect, DivTM2); Operator dt_minInstant( "minInstant", // name MinInstantSpec, // specification MinFun, Operator::SimpleSelect, MinMaxInstantTM); Operator dt_maxInstant( "maxInstant", // name MaxInstantSpec, // specification MaxFun, Operator::SimpleSelect, MinMaxInstantTM); Operator dt_maxDuration( "maxDuration", // name MaxDurationSpec, // specification MaxFun, Operator::SimpleSelect, MinMaxDurationTM); Operator dt_minDuration( "minDuration", // name MinDurationSpec, // specification MinFun, Operator::SimpleSelect, MinMaxDurationTM); Operator dt_less( "<", // name LessSpec, // specification BeforeFun, Operator::SimpleSelect, CheckComparisons); Operator dt_greater( ">", // name GreaterSpec, // specification AfterFun, Operator::SimpleSelect, CheckComparisons); Operator dt_equals( "=", // name EqualsSpec, // specification EqualsFun, Operator::SimpleSelect, CheckComparisons); Operator dt_mul( "*", // name MulSpec, // specification 4, MulVM, MulSelect, MulTM); Operator dt_weekday( "weekday_of", // name WeekdaySpec, // specification WeekdayFun, Operator::SimpleSelect, InstantString); Operator dt_theInstant( "theInstant", // name TheInstantSpec, // specification 7, // number of functions TheInstantValueMap, TheInstantSelect, TheInstantTM); Operator dt_duration2real( "duration2real", // name Duration2RealSpec, // specification DateTime2RealFun, Operator::SimpleSelect, Duration2RealTM ); Operator dt_instant2real( "instant2real", // name Instant2RealSpec, // specification DateTime2RealFun, Operator::SimpleSelect, Instant2RealTM ); Operator dt_create_duration( "create_duration", // name CreateDurationSpec, // specification 4, // number of functions CreateDurationValueMap, create_durationSelect, CreateDurationTM); Operator dt_create_instant( "create_instant", // name CreateInstantSpec, // specification 2, // number of functions CreateInstantValueMap, TheInstantSelect, CreateInstantTM); Operator dt_tostring( "tostring", // name ToStringSpec, // specification DateTimeToStringFun, Operator::SimpleSelect, DateTimeString ); Operator str2instant( "str2instant", str2instantSpec, 2, str2instantvm, str2instantSelect, str2instantTM ); Operator transformDateTime( "transformDateTime", transformDateTimeSpec, transformDateTimeVM, Operator::SimpleSelect, transformDateTimeTM ); /* Operator abs */ ListExpr absTM(ListExpr args){ if(!nl->HasLength(args,1)){ return listutils::typeError("one argument expected"); } if(!Duration::checkType(nl->First(args))){ return listutils::typeError("expected duration"); } return nl->First(args); } int absVM(Word* args, Word& result, int message, Word& local, Supplier s){ result = qp->ResultStorage(s); DateTime* arg = (DateTime*) args[0].addr; DateTime* res = (DateTime*) result.addr; *res = *arg; res->Abs(); return 0; } OperatorSpec absSpec( "duration -> duration", "abs(_)", "Computes the absolute duration.", "query abs([const duration value -1]);" ); Operator absOp( "abs", absSpec.getStr(), absVM, Operator::SimpleSelect, absTM ); /* 5 Creating the Algebra */ class DateTimeAlgebra : public Algebra { public: DateTimeAlgebra() : Algebra() { // type constructors AddTypeConstructor( &instant ); instant.AssociateKind( Kind::DATA() ); instant.AssociateKind( Kind::INDEXABLE() ); instant.AssociateKind( Kind::CSVEXPORTABLE() ); instant.AssociateKind( Kind::CSVIMPORTABLE() ); AddTypeConstructor( &duration ); duration.AssociateKind( Kind::DATA() ); duration.AssociateKind( Kind::CSVEXPORTABLE() ); duration.AssociateKind( Kind::CSVIMPORTABLE() ); // operators AddOperator(&dt_add); AddOperator(&dt_minus); AddOperator(&dt_equals); AddOperator(&dt_less); AddOperator(&dt_greater); AddOperator(&dt_mul); AddOperator(&dt_weekday); AddOperator(&dt_leapyear); AddOperator(&dt_year); AddOperator(&dt_month); AddOperator(&dt_day); AddOperator(&dt_hour); AddOperator(&dt_minute); AddOperator(&dt_second); AddOperator(&dt_millisecond); AddOperator(&dt_now); AddOperator(&dt_today); AddOperator(&dt_theInstant); AddOperator(&dt_div); AddOperator(&dt_div2); AddOperator(&dt_minInstant); AddOperator(&dt_maxInstant); AddOperator(&dt_minDuration); AddOperator(&dt_maxDuration); AddOperator(&dt_create_duration); AddOperator(&dt_create_instant); AddOperator(&dt_duration2real); AddOperator(&dt_instant2real); AddOperator(&dt_tostring); AddOperator(&str2instant); AddOperator(&transformDateTime); AddOperator(&absOp); } ~DateTimeAlgebra() {}; }; /* 6 Initialization Each algebra module needs an initialization function. The algebra manager has a reference to this function if this algebra is included in the list of required algebras, thus forcing the linker to include this module. The algebra manager invokes this function to get a reference to the instance of the algebra class and to provide references to the global nested list container (used to store constructor, type, operator and object information) and to the query processor. The function has a C interface to make it possible to load the algebra dynamically at runtime. */ extern "C" Algebra* InitializeDateTimeAlgebra( NestedList* nlRef, QueryProcessor* qpRef, AlgebraManager* amRef ) { nl = nlRef; qp = qpRef; am = amRef; return (new DateTimeAlgebra()); } } // end of namespace ostream& operator<<(ostream& o, const datetime::DateTime& DT) { return DT.Print(o); }