1 /*
2 Qalculate (library)
3
4 Copyright (C) 2003-2007, 2008, 2016, 2018 Hanna Knutsson (hanna.knutsson@protonmail.com)
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 */
11
12 #include "support.h"
13
14 #include "BuiltinFunctions.h"
15 #include "util.h"
16 #include "MathStructure.h"
17 #include "Number.h"
18 #include "Calculator.h"
19 #include "Unit.h"
20 #include "QalculateDateTime.h"
21 #include "Variable.h"
22
23 #include <sstream>
24 #include <time.h>
25 #include <limits>
26 #include <algorithm>
27
28 using std::string;
29 using std::cout;
30 using std::vector;
31 using std::endl;
32
calender_to_id(const string & str)33 int calender_to_id(const string &str) {
34 if(str == "1" || equalsIgnoreCase(str, "gregorian") || equalsIgnoreCase(str, _("gregorian"))) return CALENDAR_GREGORIAN;
35 if(str == "8" || equalsIgnoreCase(str, "milankovic") || equalsIgnoreCase(str, "milanković") || equalsIgnoreCase(str, _("milankovic"))) return CALENDAR_MILANKOVIC;
36 if(str == "7" || equalsIgnoreCase(str, "julian") || equalsIgnoreCase(str, _("julian"))) return CALENDAR_JULIAN;
37 if(str == "3" || equalsIgnoreCase(str, "islamic") || equalsIgnoreCase(str, _("islamic"))) return CALENDAR_ISLAMIC;
38 if(str == "2" || equalsIgnoreCase(str, "hebrew") || equalsIgnoreCase(str, _("hebrew"))) return CALENDAR_HEBREW;
39 if(str == "11" || equalsIgnoreCase(str, "egyptian") || equalsIgnoreCase(str, _("egyptian"))) return CALENDAR_EGYPTIAN;
40 if(str == "4" || equalsIgnoreCase(str, "persian") || equalsIgnoreCase(str, _("persian"))) return CALENDAR_PERSIAN;
41 if(str == "9" || equalsIgnoreCase(str, "coptic") || equalsIgnoreCase(str, _("coptic"))) return CALENDAR_COPTIC;
42 if(str == "10" || equalsIgnoreCase(str, "ethiopian") || equalsIgnoreCase(str, _("ethiopian"))) return CALENDAR_ETHIOPIAN;
43 if(str == "5" || equalsIgnoreCase(str, "indian") || equalsIgnoreCase(str, _("indian"))) return CALENDAR_INDIAN;
44 if(str == "6" || equalsIgnoreCase(str, "chinese") || equalsIgnoreCase(str, _("chinese"))) return CALENDAR_CHINESE;
45 return -1;
46 }
47
DateFunction()48 DateFunction::DateFunction() : MathFunction("date", 1, 4) {
49 setArgumentDefinition(1, new IntegerArgument("", ARGUMENT_MIN_MAX_NONE, true, true, INTEGER_TYPE_SLONG));
50 IntegerArgument *iarg = new IntegerArgument();
51 iarg->setHandleVector(false);
52 Number fr(1, 1, 0);
53 iarg->setMin(&fr);
54 fr.set(24, 1, 0);
55 iarg->setMax(&fr);
56 setArgumentDefinition(2, iarg);
57 setDefaultValue(2, "1");
58 iarg = new IntegerArgument();
59 iarg->setHandleVector(false);
60 fr.set(1, 1, 0);
61 iarg->setMin(&fr);
62 fr.set(31, 1, 0);
63 iarg->setMax(&fr);
64 setDefaultValue(3, "1");
65 setArgumentDefinition(3, iarg);
66 TextArgument *targ = new TextArgument();
67 setArgumentDefinition(4, targ);
68 setDefaultValue(4, _("gregorian"));
69 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)70 int DateFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
71 int ct = calender_to_id(vargs[3].symbol());
72 if(ct < 0) {
73 CALCULATOR->error(true, "Unrecognized calendar.", NULL);
74 return 0;
75 }
76 QalculateDateTime dt;
77 if(!calendarToDate(dt, vargs[0].number().lintValue(), vargs[1].number().lintValue(), vargs[2].number().lintValue(), (CalendarSystem) ct)) return 0;
78 mstruct.set(dt);
79 return 1;
80 }
DateTimeFunction()81 DateTimeFunction::DateTimeFunction() : MathFunction("datetime", 1, 6) {
82 setArgumentDefinition(1, new IntegerArgument("", ARGUMENT_MIN_MAX_NONE, true, true, INTEGER_TYPE_SLONG));
83 IntegerArgument *iarg = new IntegerArgument();
84 iarg->setHandleVector(false);
85 Number fr(1, 1, 0);
86 iarg->setMin(&fr);
87 fr.set(12, 1, 0);
88 iarg->setMax(&fr);
89 setArgumentDefinition(2, iarg);
90 setDefaultValue(2, "1");
91 iarg = new IntegerArgument();
92 iarg->setHandleVector(false);
93 fr.set(1, 1, 0);
94 iarg->setMin(&fr);
95 fr.set(31, 1, 0);
96 iarg->setMax(&fr);
97 setDefaultValue(3, "1");
98 setArgumentDefinition(3, iarg);
99 iarg = new IntegerArgument();
100 iarg->setHandleVector(false);
101 iarg->setMin(&nr_zero);
102 fr.set(23, 1, 0);
103 iarg->setMax(&fr);
104 setArgumentDefinition(4, iarg);
105 setDefaultValue(4, "0");
106 iarg = new IntegerArgument();
107 iarg->setHandleVector(false);
108 iarg->setMin(&nr_zero);
109 fr.set(59, 1, 0);
110 iarg->setMax(&fr);
111 setArgumentDefinition(5, iarg);
112 setDefaultValue(5, "0");
113 NumberArgument *narg = new NumberArgument();
114 narg->setHandleVector(false);
115 narg->setMin(&nr_zero);
116 fr.set(61, 1, 0);
117 narg->setMax(&fr);
118 narg->setIncludeEqualsMax(false);
119 setArgumentDefinition(6, narg);
120 setDefaultValue(6, "0");
121 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)122 int DateTimeFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
123 QalculateDateTime dt;
124 if(!dt.set(vargs[0].number().lintValue(), vargs[1].number().lintValue(), vargs[2].number().lintValue())) return 0;
125 if(!vargs[3].isZero() || !vargs[4].isZero() || !vargs[5].isZero()) {
126 if(!dt.setTime(vargs[3].number().lintValue(), vargs[4].number().lintValue(), vargs[5].number())) return 0;
127 }
128 mstruct.set(dt);
129 return 1;
130 }
TimeValueFunction()131 TimeValueFunction::TimeValueFunction() : MathFunction("timevalue", 0, 1) {
132 setArgumentDefinition(1, new DateArgument());
133 setDefaultValue(1, "now");
134 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)135 int TimeValueFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
136 Number nr(vargs[0].datetime()->second());
137 nr /= 60;
138 nr += vargs[0].datetime()->minute();
139 nr /= 60;
140 nr += vargs[0].datetime()->hour();
141 mstruct.set(nr);
142 return 1;
143 }
TimestampFunction()144 TimestampFunction::TimestampFunction() : MathFunction("timestamp", 0, 1) {
145 setArgumentDefinition(1, new DateArgument());
146 setDefaultValue(1, "now");
147 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)148 int TimestampFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
149 QalculateDateTime date(*vargs[0].datetime());
150 Number nr(date.timestamp());
151 if(nr.isInfinite()) return 0;
152 mstruct.set(nr);
153 return 1;
154 }
TimestampToDateFunction()155 TimestampToDateFunction::TimestampToDateFunction() : MathFunction("stamptodate", 1) {
156 //setArgumentDefinition(1, new IntegerArgument("", ARGUMENT_MIN_MAX_NONE, true, true, INTEGER_TYPE_SLONG));
157 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)158 int TimestampToDateFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions &eo) {
159 mstruct = vargs[0];
160 mstruct.eval(eo);
161 if((mstruct.isUnit() && mstruct.unit()->baseUnit() == CALCULATOR->getUnitById(UNIT_ID_SECOND)) || (mstruct.isMultiplication() && mstruct.size() >= 2 && mstruct.last().isUnit() && mstruct.last().unit()->baseUnit() == CALCULATOR->getUnitById(UNIT_ID_SECOND))) {
162 Unit *u = NULL;
163 if(mstruct.isUnit()) {
164 u = mstruct.unit();
165 mstruct.set(1, 1, 0, true);
166 } else {
167 u = mstruct.last().unit();
168 mstruct.delChild(mstruct.size(), true);
169 }
170 if(u != CALCULATOR->getUnitById(UNIT_ID_SECOND)) {
171 u->convertToBaseUnit(mstruct);
172 mstruct.eval(eo);
173 }
174 }
175 if(!mstruct.isNumber() || !mstruct.number().isReal() || mstruct.number().isInterval()) return -1;
176 QalculateDateTime date;
177 if(!date.set(mstruct.number())) return -1;
178 mstruct.set(date, true);
179 return 1;
180 }
181
AddDaysFunction()182 AddDaysFunction::AddDaysFunction() : MathFunction("addDays", 2) {
183 setArgumentDefinition(1, new DateArgument());
184 setArgumentDefinition(2, new NumberArgument());
185 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)186 int AddDaysFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
187 mstruct = vargs[0];
188 if(!mstruct.datetime()->addDays(vargs[1].number())) return 0;
189 return 1;
190 }
AddMonthsFunction()191 AddMonthsFunction::AddMonthsFunction() : MathFunction("addMonths", 2) {
192 setArgumentDefinition(1, new DateArgument());
193 setArgumentDefinition(2, new NumberArgument());
194 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)195 int AddMonthsFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
196 mstruct = vargs[0];
197 if(!mstruct.datetime()->addMonths(vargs[1].number())) return 0;
198 return 1;
199 }
AddYearsFunction()200 AddYearsFunction::AddYearsFunction() : MathFunction("addYears", 2) {
201 setArgumentDefinition(1, new DateArgument());
202 setArgumentDefinition(2, new NumberArgument());
203 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)204 int AddYearsFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
205 mstruct = vargs[0];
206 if(!mstruct.datetime()->addYears(vargs[1].number())) return 0;
207 return 1;
208 }
209
DaysFunction()210 DaysFunction::DaysFunction() : MathFunction("days", 2, 4) {
211 setArgumentDefinition(1, new DateArgument());
212 setArgumentDefinition(2, new DateArgument());
213 IntegerArgument *arg = new IntegerArgument();
214 Number integ;
215 arg->setMin(&integ);
216 integ.set(4, 1, 0);
217 arg->setMax(&integ);
218 setArgumentDefinition(3, arg);
219 setArgumentDefinition(4, new BooleanArgument());
220 setDefaultValue(3, "1");
221 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)222 int DaysFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
223 QalculateDateTime date1(*vargs[0].datetime()), date2(*vargs[1].datetime());
224 Number days(date1.daysTo(date2, vargs[2].number().intValue(), vargs[3].number().isZero()));
225 if(days.isInfinite()) return 0;
226 days.abs();
227 mstruct.set(days);
228 return 1;
229 }
YearFracFunction()230 YearFracFunction::YearFracFunction() : MathFunction("yearfrac", 2, 4) {
231 setArgumentDefinition(1, new DateArgument());
232 setArgumentDefinition(2, new DateArgument());
233 IntegerArgument *arg = new IntegerArgument();
234 Number integ;
235 arg->setMin(&integ);
236 integ.set(4, 1, 0);
237 arg->setMax(&integ);
238 setArgumentDefinition(3, arg);
239 setArgumentDefinition(4, new BooleanArgument());
240 setDefaultValue(3, "1");
241 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)242 int YearFracFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
243 QalculateDateTime date1(*vargs[0].datetime()), date2(*vargs[1].datetime());
244 Number years(date1.yearsTo(date2, vargs[2].number().intValue(), vargs[3].number().isZero()));
245 if(years.isInfinite()) return 0;
246 years.abs();
247 mstruct.set(years);
248 return 1;
249 }
WeekFunction()250 WeekFunction::WeekFunction() : MathFunction("week", 0, 2) {
251 setArgumentDefinition(1, new DateArgument());
252 setArgumentDefinition(2, new BooleanArgument());
253 setDefaultValue(1, "today");
254 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)255 int WeekFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
256 QalculateDateTime date(*vargs[0].datetime());
257 int w = date.week(vargs[1].number().getBoolean());
258 if(w < 0) return 0;
259 mstruct.set(w, 1, 0);
260 return 1;
261 }
WeekdayFunction()262 WeekdayFunction::WeekdayFunction() : MathFunction("weekday", 0, 2) {
263 setArgumentDefinition(1, new DateArgument());
264 setArgumentDefinition(2, new BooleanArgument());
265 setDefaultValue(1, "today");
266 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)267 int WeekdayFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
268 QalculateDateTime date(*vargs[0].datetime());
269 int w = date.weekday();
270 if(w < 0) return 0;
271 if(vargs[1].number().getBoolean()) {
272 if(w == 7) w = 1;
273 else w++;
274 }
275 mstruct.set(w, 1, 0);
276 return 1;
277 }
YeardayFunction()278 YeardayFunction::YeardayFunction() : MathFunction("yearday", 0, 1) {
279 setArgumentDefinition(1, new DateArgument());
280 setDefaultValue(1, "today");
281 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)282 int YeardayFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
283 QalculateDateTime date(*vargs[0].datetime());
284 int yd = date.yearday();
285 if(yd < 0) return 0;
286 mstruct.set(yd, 1, 0);
287 return 1;
288 }
MonthFunction()289 MonthFunction::MonthFunction() : MathFunction("month", 0, 1) {
290 setArgumentDefinition(1, new DateArgument());
291 setDefaultValue(1, "today");
292 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)293 int MonthFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
294 QalculateDateTime date(*vargs[0].datetime());
295 mstruct.set(date.month(), 1L, 0L);
296 return 1;
297 }
DayFunction()298 DayFunction::DayFunction() : MathFunction("day", 0, 1) {
299 setArgumentDefinition(1, new DateArgument());
300 setDefaultValue(1, "today");
301 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)302 int DayFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
303 QalculateDateTime date(*vargs[0].datetime());
304 mstruct.set(date.day(), 1L, 0L);
305 return 1;
306 }
YearFunction()307 YearFunction::YearFunction() : MathFunction("year", 0, 1) {
308 setArgumentDefinition(1, new DateArgument());
309 setDefaultValue(1, "today");
310 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)311 int YearFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
312 QalculateDateTime date(*vargs[0].datetime());
313 mstruct.set(date.year(), 1L, 0L);
314 return 1;
315 }
TimeFunction()316 TimeFunction::TimeFunction() : MathFunction("time", 0) {
317 }
calculate(MathStructure & mstruct,const MathStructure &,const EvaluationOptions &)318 int TimeFunction::calculate(MathStructure &mstruct, const MathStructure&, const EvaluationOptions&) {
319 int hour, min, sec;
320 now(hour, min, sec);
321 Number tnr(sec, 1, 0);
322 tnr /= 60;
323 tnr += min;
324 tnr /= 60;
325 tnr += hour;
326 mstruct = tnr;
327 return 1;
328 }
LunarPhaseFunction()329 LunarPhaseFunction::LunarPhaseFunction() : MathFunction("lunarphase", 0, 1) {
330 setArgumentDefinition(1, new DateArgument());
331 setDefaultValue(1, "now");
332 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions &)333 int LunarPhaseFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&) {
334 mstruct = lunarPhase(*vargs[0].datetime());
335 if(CALCULATOR->aborted()) return 0;
336 return 1;
337 }
NextLunarPhaseFunction()338 NextLunarPhaseFunction::NextLunarPhaseFunction() : MathFunction("nextlunarphase", 1, 2) {
339 NumberArgument *arg = new NumberArgument("", ARGUMENT_MIN_MAX_NONE, false, true);
340 Number fr;
341 arg->setMin(&fr);
342 fr.set(1, 1, 0);
343 arg->setMax(&fr);
344 arg->setIncludeEqualsMin(true);
345 arg->setIncludeEqualsMax(false);
346 arg->setHandleVector(true);
347 setArgumentDefinition(1, arg);
348 setArgumentDefinition(2, new DateArgument());
349 setDefaultValue(2, "now");
350 }
calculate(MathStructure & mstruct,const MathStructure & vargs,const EvaluationOptions & eo)351 int NextLunarPhaseFunction::calculate(MathStructure &mstruct, const MathStructure &vargs, const EvaluationOptions&eo) {
352 mstruct = vargs[0];
353 mstruct.eval(eo);
354 if(!mstruct.isNumber()) {
355 mstruct /= CALCULATOR->getRadUnit();
356 mstruct /= CALCULATOR->getVariableById(VARIABLE_ID_PI);
357 mstruct /= nr_two;
358 mstruct.eval(eo);
359 } else if(mstruct.number() > 1) {
360 mstruct.calculateDivide(MathStructure(360, 1, 0), eo);
361 }
362 if(!mstruct.isNumber() || mstruct.number().isNegative() || !mstruct.number().isFraction()) {
363 Argument *arg = getArgumentDefinition(1);
364 if(arg) {
365 arg->setTests(true);
366 arg->test(mstruct, 1, this, eo);
367 arg->setTests(false);
368 }
369 return 0;
370 }
371 mstruct = findNextLunarPhase(*vargs[1].datetime(), mstruct.number());
372 if(CALCULATOR->aborted()) return -1;
373 return 1;
374 }
375
376