Files
secondo/Algebras/DateTime/DateTimeAlgebra.cpp
2026-01-23 17:03:45 +08:00

3606 lines
91 KiB
C++

/*
----
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 <string>
#include <iostream>
#include <sstream>
#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 <math.h>
#include <time.h>
#include <sys/timeb.h>
#include "LogMsg.h"
#include "ListUtils.h"
#include "StringUtils.h"
#include "Symbols.h"
#include <limits>
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<int64_t>::min();
static int64_t max_VALUE = numeric_limits<int64_t>::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 ("<<day<<") or month ("<<month<<") outside"
<< " of the valid range\n";
cmsg.send();
}
// ensure to write at least 4 digits for a year
if(year < 1000 && year>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<DATETIMECOMPONENT> 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;i<f.size();i++){
DATETIMECOMPONENT comp = f[i];
switch(comp){
case YEAR : { if(year) return false;
year = true;
break;
}
case MONTH : { if(month) return false;
month = true;
break;
}
case DAY : { if(day) return false;
day = true;
break;
}
case HOUR : { if(hour) return false;
hour = true;
break;
}
case MINUTE : { if(minute) return false;
minute = true;
break;
}
case SECOND : { if(second) return false;
second = true;
break;
}
case MILLI : { if(milli) return false;
milli = true;
break;
}
default : return false;
}
}
if(!year || !month || !day){
return false;
}
if(minute != hour) {
return false;
}
if(second && !minute){
return false;
}
if(milli && !second){
return false;
}
// format seem to be correct, analyse value
int Year = 0;
int Month = 0;
int Day = 0;
int Hour = 0;
int Minute = 0;
int Second = 0;
int Milli = 0;
size_t vpos = value.find_first_of("0123456789");
for(unsigned int i=0;i<f.size() && vpos !=string::npos;i++){
size_t nextPos = value.find_first_not_of("0123456789", vpos);
string ints = value.substr(vpos,
(nextPos==string::npos?value.size():nextPos) -vpos);
if(nextPos == string::npos){
vpos = string::npos;
} else {
vpos = value.find_first_of("0123456789", nextPos +1);
}
int v = atoi(ints.c_str());
switch(f[i]){
case YEAR : Year = v; break;
case MONTH : Month = v; break;
case DAY : Day = v; break;
case HOUR : Hour = v; break;
case MINUTE : Minute = v; break;
case SECOND : Second = v; break;
case MILLI : Milli = v; break;
default : return false;
}
}
Set(Year, Month, Day, Hour, Minute, Second, Milli);
return true;
}
/*
~ReadFrom~
This functions reads the value of this instance from the given double.
*/
bool DateTime::ReadFrom(const double Time){
SetDefined(true);
value = (int64_t) (Time*MILLISECONDS + 0.5);
return true;
}
/*
~ReadFrom~
This functions reads the value of this instance from the given int64\_t.
*/
bool DateTime::ReadFrom(const int64_t Time){
SetDefined(true);
value = Time;
return true;
}
/*
~IsValid~
This functions checks if the given arguments represent a valid gregorian
date. E.g. this function will return false if month is greater than twelve,
or the day is not included in the given month/year.
*/
bool DateTime::IsValid(const int32_t year,
const int32_t month,
const int32_t day)const {
int64_t jday = ToJulian(year,month,day);
int m=0,d=0;
int64_t y = 0;
ToGregorian(jday,y,m,d);
return year==y && month==m && day==d;
}
/*
~ReadFrom~
This function reads the time value from the given nested list.
If the format is not correct, this function will return false and this
instance remains unchanged. Otherwise this instance will take the value
represented by this list and the result will be true.
*/
bool DateTime::ReadFrom(const ListExpr LE, const bool typeincluded){
ListExpr ValueList;
if(typeincluded){
if(nl->ListLength(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<double>(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->value<MIN_REPRESENTABLE || this->value>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<int32_t>::min();
} else {
day2 = numeric_limits<int32_t>::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<Duration>();
}
if(CcInt::checkType(first) && CcString::checkType(second)){
return listutils::basicSymbol<Duration>();
}
if(LongInt::checkType(first) && CcString::checkType(second)){
return listutils::basicSymbol<Duration>();
}
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<class T>
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<class T>
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<CcInt>,
MulFunNumDur<CcReal>,
MulFunDurNum<CcInt>,
MulFunDurNum<CcReal>
};
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<class IT>
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<DateTime*>(args[0].addr);
string rs = T->ToString();
( static_cast<CcString*>(result.addr))->Set(true,rs);
return 0;
}
template<class T>
int str2instantVM(Word* args, Word& result, int message,
Word& local, Supplier s){
result = qp->ResultStorage(s);
DateTime* res = static_cast<DateTime*>(result.addr);
T* arg = static_cast<T*>(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<CcInt>,
CreateDurationFromIntStringFun<LongInt>};
ValueMapping CreateInstantValueMap[] = {
CreateInstantFromRealFun,
CreateInstantFromIntIntFun };
ValueMapping DayValueMap[] = {
DayFun,
DurationDayFun};
ValueMapping MillisecondValueMap[] = {
MillisecondFun,
DurationMillisecondFun};
ValueMapping str2instantvm[] = {
str2instantVM<CcString>,
str2instantVM<FText>
};
/*
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);
}