1 /*
2 Qalculate
3
4 Copyright (C) 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 Many of the calendar conversion algorithms used here are adapted from
12 CALENDRICA 4.0 -- Common Lisp
13 Copyright (C) E. M. Reingold and N. Dershowitz
14
15 */
16
17 #include "QalculateDateTime.h"
18 #include "support.h"
19 #include "util.h"
20 #include "Calculator.h"
21 #include <limits.h>
22 #include <stdlib.h>
23 #include <sys/time.h>
24
25 using std::string;
26 using std::vector;
27
28 static const char *HEBREW_MONTHS[] = {"Nisan", "Iyar", "Sivan", "Tammuz", "Av", "Elul", "Tishrei", "Marcheshvan", "Kislev", "Tevet", "Shevat", "Adar", "Adar II"};
29 static const char *STANDARD_MONTHS[] = {N_("January"), N_("February"), N_("March"), N_("April"), N_("May"), N_("June"), N_("July"), N_("August"), N_("September"), N_("October"), N_("November"), N_("December")};
30 static const char *COPTIC_MONTHS[] = {N_("Thout"), N_("Paopi"), N_("Hathor"), N_("Koiak"), N_("Tobi"), N_("Meshir"), N_("Paremhat"), N_("Parmouti"), N_("Pashons"), N_("Paoni"), N_("Epip"), N_("Mesori"), N_("Pi Kogi Enavot")};
31 static const char *ETHIOPIAN_MONTHS[] = {N_("Mäskäräm"), N_("Ṭəqəmt"), N_("Ḫədar"), N_("Taḫśaś"), N_("Ṭərr"), N_("Yäkatit"), N_("Mägabit"), N_("Miyazya"), N_("Gənbo"), N_("Säne"), N_("Ḥamle"), N_("Nähase"), N_("Ṗagume")};
32 static const char *ISLAMIC_MONTHS[] = {N_("Muḥarram"), N_("Ṣafar"), N_("Rabī‘ al-awwal"), N_("Rabī‘ ath-thānī"), N_("Jumādá al-ūlá"), N_("Jumādá al-ākhirah"), N_("Rajab"), N_("Sha‘bān"), N_("Ramaḍān"), N_("Shawwāl"), N_("Dhū al-Qa‘dah"), N_("Dhū al-Ḥijjah")};
33 static const char *PERSIAN_MONTHS[] = {N_("Farvardin"), N_("Ordibehesht"), N_("Khordad"), N_("Tir"), N_("Mordad"), N_("Shahrivar"), N_("Mehr"), N_("Aban"), N_("Azar"), N_("Dey"), N_("Bahman"), N_("Esfand")};
34 static const char *INDIAN_MONTHS[] = {N_("Chaitra"), N_("Vaishākha"), N_("Jyēshtha"), N_("Āshādha"), N_("Shrāvana"), N_("Bhaadra"), N_("Āshwin"), N_("Kārtika"), N_("Agrahayana"), N_("Pausha"), N_("Māgha"), N_("Phalguna")};
35 static const char *CHINESE_ELEMENTS[] = {N_("Wood"), N_("Fire"), N_("Earth"), N_("Metal"), N_("Water")};
36 static const char *CHINESE_ANIMALS[] = {N_("Rat"), N_("Ox"), N_("Tiger"), N_("Rabbit"), N_("Dragon"), N_("Snake"), N_("Horse"), N_("Goat"), N_("Monkey"), N_("Rooster"), N_("Dog"), N_("Pig")};
37
38 static const bool has_leap_second[] = {
39 // 30/6, 31/12
40 true, true, //1972
41 false, true,
42 false, true,
43 false, true,
44 false, true,
45 false, true,
46 false, true,
47 false, true,
48 false, false, //1980
49 true, false,
50 true, false,
51 true, false,
52 false, false,
53 true, false,
54 false, false,
55 false, true,
56 false, false,
57 false, true,
58 false, true, //1990
59 false, false,
60 true, false,
61 true, false,
62 true, false,
63 false, true,
64 false, false,
65 true, false,
66 false, true,
67 false, false,
68 false, false, //2000
69 false, false,
70 false, false,
71 false, false,
72 false, false,
73 false, true,
74 false, false,
75 false, false,
76 false, true,
77 false, false,
78 false, false, //2010
79 false, false,
80 true, false,
81 false, false,
82 false, false,
83 true, false,
84 false, true //2016
85 };
86
87 #define LS_FIRST_YEAR 1972
88 #define LS_LAST_YEAR 2016
89 #define INITIAL_LS 10
90
91 #define SECONDS_PER_DAY 86400
92
isLeapYear(long int year)93 bool isLeapYear(long int year) {
94 return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
95 }
daysPerYear(long int year,int basis=1)96 int daysPerYear(long int year, int basis = 1) {
97 switch(basis) {
98 case 0: {
99 return 360;
100 }
101 case 1: {
102 if(isLeapYear(year)) {
103 return 366;
104 } else {
105 return 365;
106 }
107 }
108 case 2: {
109 return 360;
110 }
111 case 3: {
112 return 365;
113 }
114 case 4: {
115 return 360;
116 }
117 }
118 return -1;
119 }
120
daysPerMonth(int month,long int year)121 int daysPerMonth(int month, long int year) {
122 switch(month) {
123 case 1: {} case 3: {} case 5: {} case 7: {} case 8: {} case 10: {} case 12: {
124 return 31;
125 }
126 case 2: {
127 if(isLeapYear(year)) return 29;
128 else return 28;
129 }
130 default: {
131 return 30;
132 }
133 }
134 }
135
countLeapSeconds(const QalculateDateTime & date1,const QalculateDateTime & date2)136 int countLeapSeconds(const QalculateDateTime &date1, const QalculateDateTime &date2) {
137 if(date1 > date2) return -countLeapSeconds(date2, date1);
138 if(date1.year() > LS_LAST_YEAR) return 0;
139 if(date2.year() < LS_FIRST_YEAR) return 0;
140 size_t halfyear1 = 0;
141 if(date1.year() >= LS_FIRST_YEAR) {
142 halfyear1 = (date1.year() - LS_FIRST_YEAR) * 2;
143 if(date1.month() > 6) halfyear1++;
144 }
145 size_t halfyear2 = 0;
146 if(date2.year() >= LS_FIRST_YEAR) {
147 halfyear2 = (date2.year() - LS_FIRST_YEAR) * 2;
148 if(date2.month() <= 6) {
149 if(halfyear2 == 0) return 0;
150 halfyear2--;
151 }
152 }
153 if(date1.second().isGreaterThanOrEqualTo(60) && date1.minute() == 59 && date1.hour() == 23 && ((date1.month() == 12 && date1.day() == 31) || (date1.month() == 6 && date1.day() == 30))) halfyear1++;
154 int i_ls = 0;
155 for(size_t i = halfyear1; i <= halfyear2 && i < sizeof(has_leap_second); i++) {
156 if(has_leap_second[i]) {
157 i_ls++;
158 }
159 }
160 return i_ls;
161 }
nextLeapSecond(const QalculateDateTime & date)162 QalculateDateTime nextLeapSecond(const QalculateDateTime &date) {
163 if(date.year() > LS_LAST_YEAR) return QalculateDateTime();
164 size_t halfyear = 0;
165 if(date.year() >= LS_FIRST_YEAR) {
166 halfyear = (date.year() - LS_FIRST_YEAR) * 2;
167 if(date.month() > 6) halfyear++;
168 }
169 if(date.second().isGreaterThanOrEqualTo(60) && date.minute() == 59 && date.hour() == 23 && ((date.month() == 12 && date.day() == 31) || (date.month() == 6 && date.day() == 30))) halfyear++;
170 for(size_t i = halfyear; i < sizeof(has_leap_second); i++) {
171 if(has_leap_second[i]) {
172 QalculateDateTime dt;
173 if(i % 2 == 1) dt.set(LS_FIRST_YEAR + i / 2, 12, 31);
174 else dt.set(LS_FIRST_YEAR + i / 2, 6, 30);
175 dt.setTime(23, 59, 60);
176 return dt;
177 }
178 }
179 return QalculateDateTime();
180 }
prevLeapSecond(const QalculateDateTime & date)181 QalculateDateTime prevLeapSecond(const QalculateDateTime &date) {
182 if(date.year() < LS_FIRST_YEAR) return QalculateDateTime();
183 size_t halfyear = sizeof(has_leap_second);
184 if(date.year() <= LS_LAST_YEAR) {
185 halfyear = (date.year() - LS_FIRST_YEAR) * 2;
186 if(date.month() <= 6) {
187 if(halfyear == 0) return QalculateDateTime();
188 halfyear--;
189 }
190 }
191 for(int i = halfyear; i >= 0; i--) {
192 if(has_leap_second[(size_t) i]) {
193 QalculateDateTime dt;
194 if(i % 2 == 1) dt.set(LS_FIRST_YEAR + i / 2, 12, 31);
195 else dt.set(LS_FIRST_YEAR + i / 2, 6, 30);
196 dt.setTime(23, 59, 60);
197 return dt;
198 }
199 }
200 return QalculateDateTime();
201 }
202
dateTimeZone(time_t rawtime)203 int dateTimeZone(time_t rawtime) {
204 struct tm tmdate = *localtime(&rawtime);
205 #ifdef _WIN32
206 TIME_ZONE_INFORMATION TimeZoneInfo;
207 GetTimeZoneInformation(&TimeZoneInfo);
208 return -(TimeZoneInfo.Bias + (tmdate.tm_isdst ? TimeZoneInfo.DaylightBias : TimeZoneInfo.StandardBias));
209 #else
210 char buffer[10];
211 if(!strftime(buffer, 10, "%z", &tmdate)) {
212 return 0;
213 }
214 string s = buffer;
215 int h = s2i(s.substr(0, 3));
216 int m = s2i(s.substr(3));
217 return h * 60 + m;
218 #endif
219 }
dateTimeZone(const QalculateDateTime & dt,bool b_utc)220 int dateTimeZone(const QalculateDateTime &dt, bool b_utc) {
221 struct tm tmdate;
222 time_t rawtime;
223 if(dt.year() > 2038) {
224 if(isLeapYear(dt.year())) tmdate.tm_year = 136;
225 else tmdate.tm_year = 137;
226 } else if(dt.year() < 0) {
227 if(isLeapYear(dt.year())) tmdate.tm_year = -1900;
228 else tmdate.tm_year = 1 - 1900;
229 } else {
230 tmdate.tm_year = dt.year() - 1900;
231 }
232 tmdate.tm_mon = dt.month() - 1;
233 tmdate.tm_mday = dt.day();
234 tmdate.tm_hour = dt.hour();
235 tmdate.tm_min = dt.minute();
236 Number nsect(dt.second());
237 nsect.trunc();
238 tmdate.tm_sec = nsect.intValue();
239 rawtime = mktime(&tmdate);
240 if(rawtime == (time_t) -1 && (dt.year() != 1969 || dt.month() != 12 || dt.day() != 31)) {
241 if(isLeapYear(dt.year())) tmdate.tm_year = 72;
242 else tmdate.tm_year = 71;
243 rawtime = mktime(&tmdate);
244 }
245 if(b_utc && (rawtime >= 0 || localtime(&rawtime))) rawtime += dateTimeZone(rawtime) * 60;
246 if(rawtime < 0 && !localtime(&rawtime)) {
247 if(isLeapYear(dt.year())) tmdate.tm_year = 72;
248 else tmdate.tm_year = 71;
249 rawtime = mktime(&tmdate);
250 if(b_utc) rawtime += dateTimeZone(rawtime) * 60;
251 }
252 return dateTimeZone(rawtime);
253 }
254
QalculateDateTime()255 QalculateDateTime::QalculateDateTime() : i_year(0), i_month(1), i_day(1), i_hour(0), i_min(0), b_time(false) {}
QalculateDateTime(long int initialyear,int initialmonth,int initialday)256 QalculateDateTime::QalculateDateTime(long int initialyear, int initialmonth, int initialday) : i_year(0), i_month(1), i_day(1), i_hour(0), i_min(0), b_time(false) {set(initialyear, initialmonth, initialday);}
QalculateDateTime(const Number & initialtimestamp)257 QalculateDateTime::QalculateDateTime(const Number &initialtimestamp) : i_year(0), i_month(1), i_day(1), i_hour(0), i_min(0), b_time(false) {set(initialtimestamp);}
QalculateDateTime(string date_string)258 QalculateDateTime::QalculateDateTime(string date_string) : i_year(0), i_month(1), i_day(1), i_hour(0), i_min(0), b_time(false) {set(date_string);}
QalculateDateTime(const QalculateDateTime & date)259 QalculateDateTime::QalculateDateTime(const QalculateDateTime &date) : i_year(date.year()), i_month(date.month()), i_day(date.day()), i_hour(date.hour()), i_min(date.minute()), n_sec(date.second()), b_time(date.timeIsSet()), parsed_string(date.parsed_string) {}
setToCurrentDate()260 void QalculateDateTime::setToCurrentDate() {
261 parsed_string.clear();
262 struct tm tmdate;
263 time_t rawtime;
264 ::time(&rawtime);
265 tmdate = *localtime(&rawtime);
266 set(tmdate.tm_year + 1900, tmdate.tm_mon + 1, tmdate.tm_mday);
267 }
setToCurrentTime()268 void QalculateDateTime::setToCurrentTime() {
269 parsed_string.clear();
270 struct timeval tv;
271 gettimeofday(&tv, NULL);
272 Number nr(tv.tv_usec, 0, -6);
273 nr += tv.tv_sec;
274 set(nr);
275 }
operator >(const QalculateDateTime & date2) const276 bool QalculateDateTime::operator > (const QalculateDateTime &date2) const {
277 if(i_year != date2.year()) return i_year > date2.year();
278 if(i_month != date2.month()) return i_month > date2.month();
279 if(i_day != date2.day()) return i_day > date2.day();
280 if(i_hour != date2.hour()) return i_hour > date2.hour();
281 if(i_min != date2.minute()) return i_min > date2.minute();
282 return n_sec.isGreaterThan(date2.second());
283 }
operator <(const QalculateDateTime & date2) const284 bool QalculateDateTime::operator < (const QalculateDateTime &date2) const {
285 if(i_year != date2.year()) return i_year < date2.year();
286 if(i_month != date2.month()) return i_month < date2.month();
287 if(i_day != date2.day()) return i_day < date2.day();
288 if(i_hour != date2.hour()) return i_hour < date2.hour();
289 if(i_min != date2.minute()) return i_min < date2.minute();
290 return n_sec.isLessThan(date2.second());
291 }
operator >=(const QalculateDateTime & date2) const292 bool QalculateDateTime::operator >= (const QalculateDateTime &date2) const {
293 return !(*this < date2);
294 }
operator <=(const QalculateDateTime & date2) const295 bool QalculateDateTime::operator <= (const QalculateDateTime &date2) const {
296 return !(*this > date2);
297 }
operator !=(const QalculateDateTime & date2) const298 bool QalculateDateTime::operator != (const QalculateDateTime &date2) const {
299 return i_year != date2.year() || i_month != date2.month() || i_day > date2.day() || i_hour != date2.hour() || i_min != date2.minute() || !n_sec.equals(date2.second());
300 }
operator ==(const QalculateDateTime & date2) const301 bool QalculateDateTime::operator == (const QalculateDateTime &date2) const {
302 return i_year == date2.year() && i_month == date2.month() && i_day == date2.day() && i_hour == date2.hour() && i_min == date2.minute() && n_sec.equals(date2.second());
303 }
isFutureDate() const304 bool QalculateDateTime::isFutureDate() const {
305 QalculateDateTime current_date;
306 if(!b_time && i_hour == 0 && i_min == 0 && n_sec.isZero()) {
307 current_date.setToCurrentDate();
308 } else {
309 current_date.setToCurrentTime();
310 }
311 return *this > current_date;
312 }
isPastDate() const313 bool QalculateDateTime::isPastDate() const {
314 QalculateDateTime current_date;
315 if(!b_time && i_hour == 0 && i_min == 0 && n_sec.isZero()) {
316 current_date.setToCurrentDate();
317 } else {
318 current_date.setToCurrentTime();
319 }
320 return *this < current_date;
321 }
set(long int newyear,int newmonth,int newday)322 bool QalculateDateTime::set(long int newyear, int newmonth, int newday) {
323 parsed_string.clear();
324 if(newmonth < 1 || newmonth > 12) return false;
325 if(newday < 1 || newday > daysPerMonth(newmonth, newyear)) return false;
326 i_year = newyear;
327 i_month = newmonth;
328 i_day = newday;
329 i_hour = 0;
330 i_min = 0;
331 n_sec.clear();
332 b_time = false;
333 return true;
334 }
set(const Number & newtimestamp)335 bool QalculateDateTime::set(const Number &newtimestamp) {
336 parsed_string.clear();
337 if(!newtimestamp.isReal() || newtimestamp.isInterval()) return false;
338 QalculateDateTime tmbak(*this);
339 i_year = 1970;
340 i_month = 1;
341 i_day = 1;
342 i_hour = 0;
343 i_min = 0;
344 n_sec.clear();
345 b_time = true;
346 if(!addSeconds(newtimestamp, false, false) || !addMinutes(dateTimeZone(*this, true), false, false)) {
347 set(tmbak);
348 return false;
349 }
350 return true;
351 }
set(string str)352 bool QalculateDateTime::set(string str) {
353
354 long int newyear = 0, newmonth = 0, newday = 0;
355
356 string str_bak(str);
357
358 remove_blank_ends(str);
359 remove_duplicate_blanks(str);
360 if(equalsIgnoreCase(str, _("now")) || equalsIgnoreCase(str, "now")) {
361 setToCurrentTime();
362 parsed_string = str_bak;
363 return true;
364 } else if(equalsIgnoreCase(str, _("today")) || equalsIgnoreCase(str, "today")) {
365 setToCurrentDate();
366 parsed_string = str_bak;
367 return true;
368 } else if(equalsIgnoreCase(str, _("tomorrow")) || equalsIgnoreCase(str, "tomorrow")) {
369 setToCurrentDate();
370 addDays(1);
371 parsed_string = str_bak;
372 return true;
373 } else if(equalsIgnoreCase(str, _("yesterday")) || equalsIgnoreCase(str, "yesterday")) {
374 setToCurrentDate();
375 addDays(-1);
376 parsed_string = str_bak;
377 return true;
378 }
379 bool b_t = false, b_tz = false;
380 size_t i_t = str.find("T");
381 if(i_t == string::npos && str.find(":") != string::npos) i_t = str.rfind(' ');
382 int newhour = 0, newmin = 0, newsec = 0;
383 int itz = 0;
384 if(i_t != string::npos && i_t < str.length() - 1 && is_in(NUMBERS, str[i_t + 1])) {
385 b_t = true;
386 string time_str = str.substr(i_t + 1);
387 str.resize(i_t);
388 char tzstr[10] = "";
389 if(sscanf(time_str.c_str(), "%2u:%2u:%2u%9s", &newhour, &newmin, &newsec, tzstr) < 3) {
390 if(sscanf(time_str.c_str(), "%2u:%2u%9s", &newhour, &newmin, tzstr) < 2) {
391 if(sscanf(time_str.c_str(), "%2u%2u%2u%9s", &newhour, &newmin, &newsec, tzstr) < 2) {
392 #ifndef _WIN32
393 struct tm tmdate;
394 if(strptime(time_str.c_str(), "%X", &tmdate) || strptime(time_str.c_str(), "%EX", &tmdate)) {
395 newhour = tmdate.tm_hour;
396 newmin = tmdate.tm_min;
397 newsec = tmdate.tm_sec;
398 } else {
399 return false;
400 }
401 #else
402 return false;
403 #endif
404 }
405 }
406 }
407 string stz = tzstr;
408 remove_blanks(stz);
409 if(stz == "Z" || stz == "GMT" || stz == "UTC" || stz == "WET") {
410 b_tz = true;
411 } else if(stz == "CET" || stz == "WEST") {
412 itz = 1 * 60;
413 b_tz = true;
414 } else if(stz == "CEST" || stz == "EET") {
415 itz = 2 * 60;
416 b_tz = true;
417 } else if(stz == "EEST") {
418 itz = 3 * 60;
419 b_tz = true;
420 } else if(stz == "CT" || stz == "CST") {
421 itz = 8 * 60;
422 b_tz = true;
423 } else if(stz == "JST") {
424 itz = 9 * 60;
425 b_tz = true;
426 } else if(stz == "EDT") {
427 itz = -4 * 60;
428 b_tz = true;
429 } else if(stz == "EST") {
430 itz = -5 * 60;
431 b_tz = true;
432 } else if(stz == "PDT" || stz == "MST") {
433 itz = -7 * 60;
434 b_tz = true;
435 } else if(stz == "PST") {
436 itz = -8 * 60;
437 b_tz = true;
438 } else if(stz.length() > 1 && (stz[0] == '-' || stz[0] == '+')) {
439 unsigned int tzh = 0, tzm = 0;
440 if(sscanf(stz.c_str() + sizeof(char), "%2u:%2u", &tzh, &tzm) > 0) {
441 itz = tzh * 60 + tzm;
442 if(str[0] == '-') itz = -itz;
443 b_tz = true;
444 }
445 }
446 }
447 if(newhour >= 24 || newmin >= 60 || newsec > 60 || (newsec == 60 && (newhour != 23 || newmin != 59))) return false;
448 gsub(SIGN_MINUS, MINUS, str);
449 if(sscanf(str.c_str(), "%ld-%lu-%lu", &newyear, &newmonth, &newday) != 3) {
450 if(sscanf(str.c_str(), "%4ld%2lu%2lu", &newyear, &newmonth, &newday) != 3) {
451 #ifndef _WIN32
452 struct tm tmdate;
453 if(strptime(str.c_str(), "%x", &tmdate) || strptime(str.c_str(), "%Ex", &tmdate)) {
454 newyear = tmdate.tm_year + 1900;
455 newmonth = tmdate.tm_mon + 1;
456 newday = tmdate.tm_mday;
457 } else {
458 #endif
459 if(sscanf(str.c_str(), "%ld/%ld/%ld", &newmonth, &newday, &newyear) != 3) {
460 if(sscanf(str.c_str(), "%2ld%2lu%2lu", &newyear, &newmonth, &newday) != 3) {
461 char c1, c2;
462 if(sscanf(str.c_str(), "%ld%1c%ld%1c%ld", &newday, &c1, &newmonth, &c2, &newyear) != 5) {
463 return false;
464 }
465 }
466 if(newday > 31) {
467 long int i = newday;
468 newday = newyear;
469 newyear = i;
470 }
471 if(newmonth > 12) {
472 long int i = newday;
473 newday = newmonth;
474 newmonth = i;
475 }
476 }
477 if(newmonth > 12) {
478 long int i = newday;
479 newday = newmonth;
480 newmonth = i;
481 }
482 if(newday > 31) {
483 long int i = newday;
484 newday = newyear;
485 newyear = i;
486 }
487 time_t rawtime;
488 ::time(&rawtime);
489 if(newyear >= 0 && newyear < 100) {
490 if(newyear + 70 > localtime(&rawtime)->tm_year) newyear += 1900;
491 else newyear += 2000;
492 }
493 }
494 #ifndef _WIN32
495 }
496 #endif
497 }
498 if(!set(newyear, newmonth, newday)) return false;
499 if(b_t) {
500 b_time = true;
501 i_hour = newhour;
502 i_min = newmin;
503 n_sec = newsec;
504 if(b_tz) {
505 addMinutes(dateTimeZone(*this, true) - itz, false, false);
506 }
507 }
508 parsed_string = str_bak;
509 return true;
510 }
set(const QalculateDateTime & date)511 void QalculateDateTime::set(const QalculateDateTime &date) {
512 parsed_string = date.parsed_string;
513 i_year = date.year();
514 i_month = date.month();
515 i_day = date.day();
516 i_hour = date.hour();
517 i_min = date.minute();
518 n_sec = date.second();
519 b_time = date.timeIsSet();
520 }
toISOString() const521 string QalculateDateTime::toISOString() const {
522 string str = i2s(i_year);
523 str += "-";
524 if(i_month < 10) {
525 str += "0";
526 }
527 str += i2s(i_month);
528 str += "-";
529 if(i_day < 10) {
530 str += "0";
531 }
532 str += i2s(i_day);
533 if(b_time || !n_sec.isZero() || i_hour != 0 || i_min != 0) {
534 str += "T";
535 if(i_hour < 10) str += "0";
536 str += i2s(i_hour);
537 str += ":";
538 if(i_min < 10) str += "0";
539 str += i2s(i_min);
540 str += ":";
541 Number nsect(n_sec);
542 nsect.trunc();
543 if(nsect.isLessThan(10)) str += "0";
544 nsect.setApproximate(false);
545 str += nsect.print();
546 }
547 return str;
548 }
toLocalString() const549 string QalculateDateTime::toLocalString() const {
550 if(i_year > INT_MAX || i_year < INT_MIN + 1900) return toISOString();
551 struct tm tmdate;
552 tmdate.tm_year = i_year - 1900;
553 tmdate.tm_mon = i_month - 1;
554 tmdate.tm_mday = i_day;
555 if(b_time || !n_sec.isZero() || i_hour != 0 || i_min != 0) {
556 tmdate.tm_hour = i_hour;
557 tmdate.tm_min = i_min;
558 Number nsect(n_sec);
559 nsect.trunc();
560 tmdate.tm_sec = nsect.intValue();
561 } else {
562 tmdate.tm_hour = 0;
563 tmdate.tm_min = 0;
564 tmdate.tm_sec = 0;
565 }
566 char buffer[100];
567 if(!strftime(buffer, 100, "%xT%X", &tmdate)) {
568 return toISOString();
569 }
570 return buffer;
571 }
print(const PrintOptions & po) const572 string QalculateDateTime::print(const PrintOptions &po) const {
573 if(po.is_approximate && (!n_sec.isInteger() || n_sec.isApproximate())) *po.is_approximate = true;
574 string str;
575 if(po.time_zone == TIME_ZONE_LOCAL) {
576 if(po.date_time_format == DATE_TIME_FORMAT_LOCALE) str = toLocalString();
577 else str = toISOString();
578 } else {
579 QalculateDateTime dtz(*this);
580 if(po.time_zone == TIME_ZONE_UTC) {
581 dtz.addMinutes(-dateTimeZone(*this, false), false, false);
582 } else {
583 dtz.addMinutes(-dateTimeZone(*this, false) + po.custom_time_zone, false, false);
584 }
585 if(po.date_time_format == DATE_TIME_FORMAT_LOCALE) str = dtz.toLocalString();
586 else str = dtz.toISOString();
587 if(po.time_zone == TIME_ZONE_UTC) {
588 str += "Z";
589 } else {
590 if(po.custom_time_zone < 0) str += '-';
591 else str += '+';
592 if(::abs(po.custom_time_zone) / 60 < 10) str += "0";
593 str += i2s(::abs(po.custom_time_zone) / 60);
594 str += ":";
595 if(::abs(po.custom_time_zone) % 60 < 10) str += "0";
596 str += i2s(::abs(po.custom_time_zone) % 60);
597 }
598 }
599 if(po.use_unicode_signs && i_year < 0 && str.length() > 0 && str[0] == MINUS_CH && (!po.can_display_unicode_string_function || (*po.can_display_unicode_string_function) (SIGN_MINUS, po.can_display_unicode_string_arg))) {
600 str.replace(0, 1, SIGN_MINUS);
601 }
602 return str;
603 }
year() const604 long int QalculateDateTime::year() const {
605 return i_year;
606 }
month() const607 long int QalculateDateTime::month() const {
608 return i_month;
609 }
day() const610 long int QalculateDateTime::day() const {
611 return i_day;
612 }
hour() const613 long int QalculateDateTime::hour() const {
614 return i_hour;
615 }
minute() const616 long int QalculateDateTime::minute() const {
617 return i_min;
618 }
second() const619 const Number &QalculateDateTime::second() const {
620 return n_sec;
621 }
setYear(long int newyear)622 void QalculateDateTime::setYear(long int newyear) {i_year = newyear;}
timeIsSet() const623 bool QalculateDateTime::timeIsSet() const {return b_time;}
setTime(long int ihour,long int imin,const Number & nsec)624 bool QalculateDateTime::setTime(long int ihour, long int imin, const Number &nsec) {
625 parsed_string.clear();
626 i_hour = ihour;
627 i_min = imin;
628 n_sec = nsec;
629 b_time = true;
630 return true;
631 }
addHours(const Number & nhours)632 bool QalculateDateTime::addHours(const Number &nhours) {
633 Number nmins(nhours);
634 nmins *= 60;
635 return addMinutes(nmins, true, true);
636 }
addMinutes(const Number & nminutes,bool remove_leap_second,bool convert_to_utc)637 bool QalculateDateTime::addMinutes(const Number &nminutes, bool remove_leap_second, bool convert_to_utc) {
638 parsed_string.clear();
639 if(!nminutes.isReal() || nminutes.isInterval()) return false;
640 b_time = true;
641 if(!nminutes.isInteger()) {
642 Number newmins(nminutes);
643 newmins.trunc();
644 QalculateDateTime dtbak(*this);
645 if(!addMinutes(newmins, remove_leap_second, convert_to_utc)) return false;
646 Number nsec(nminutes);
647 nsec.frac();
648 nsec *= 60;
649 if(!addSeconds(nsec, false, false)) {
650 set(dtbak);
651 return false;
652 }
653 return true;
654 }
655 QalculateDateTime dtbak(*this);
656 if(convert_to_utc) {
657 if(!addMinutes(-dateTimeZone(*this, false), false, false)) return false;
658 }
659 if(remove_leap_second && n_sec.isGreaterThanOrEqualTo(60)) {
660 n_sec--;
661 }
662 Number nmins(nminutes);
663 nmins /= 60;
664 Number nhours(nmins);
665 nhours.trunc();
666 nmins.frac();
667 nmins *= 60;
668 i_min += nmins.lintValue();
669 if(i_min >= 60) {
670 i_min -= 60;
671 nhours++;
672 } else if(i_min < 0) {
673 i_min += 60;
674 nhours--;
675 }
676 nhours /= 24;
677 Number ndays(nhours);
678 ndays.trunc();
679 nhours.frac();
680 nhours *= 24;
681 i_hour = i_hour + nhours.lintValue();
682 if(i_hour >= 24) {
683 i_hour -= 24;
684 ndays++;
685 } else if(i_hour < 0) {
686 i_hour += 24;
687 ndays--;
688 }
689 if(!addDays(ndays)) {
690 set(dtbak);
691 return false;
692 }
693 if(convert_to_utc) {
694 if(!addMinutes(dateTimeZone(*this, true), false, false)) {set(dtbak); return false;}
695 }
696 return true;
697 }
addDays(const Number & ndays)698 bool QalculateDateTime::addDays(const Number &ndays) {
699 parsed_string.clear();
700 if(!ndays.isReal() || ndays.isInterval()) return false;
701 if(ndays.isZero()) return true;
702 if(!ndays.isInteger()) {
703 Number newdays(ndays);
704 newdays.trunc();
705 QalculateDateTime dtbak(*this);
706 if(!addDays(newdays)) return false;
707 Number nmin(ndays);
708 nmin.frac();
709 nmin *= 1440;
710 if(!addMinutes(nmin, true, true)) {
711 set(dtbak);
712 return false;
713 }
714 return true;
715 }
716
717 long int newmonth = i_month, newyear = i_year;
718 Number newnday(ndays);
719 newnday += i_day;
720 if(ndays.isNegative()) {
721 bool check_aborted = newnday.isLessThan(-1000000L);
722 while(newnday.isLessThanOrEqualTo(-14609700L)) {
723 newnday += 14609700L;
724 newyear -= 40000L;
725 if(check_aborted && CALCULATOR && CALCULATOR->aborted()) return false;
726 }
727 while(newnday.isLessThanOrEqualTo(-146097L)) {
728 newnday += 146097L;
729 newyear -= 400;
730 if(check_aborted && CALCULATOR && CALCULATOR->aborted()) return false;
731 }
732 while(newnday.isLessThanOrEqualTo(-daysPerYear(newmonth <= 2 ? newyear - 1 : newyear))) {
733 newnday += daysPerYear(newmonth <= 2 ? newyear - 1 : newyear);
734 newyear--;
735 if(check_aborted && CALCULATOR && CALCULATOR->aborted()) return false;
736 }
737 while(newnday.isLessThan(1)) {
738 newmonth--;
739 if(newmonth < 1) {
740 newyear--;
741 newmonth = 12;
742 }
743 newnday += daysPerMonth(newmonth, newyear);
744 }
745 } else {
746 bool check_aborted = newnday.isGreaterThan(1000000L);
747 while(newnday.isGreaterThan(14609700L)) {
748 newnday -= 14609700L;
749 newyear += 40000;
750 if(check_aborted && CALCULATOR && CALCULATOR->aborted()) return false;
751 }
752 while(newnday.isGreaterThan(146097L)) {
753 newnday -= 146097L;
754 newyear += 400;
755 if(check_aborted && CALCULATOR && CALCULATOR->aborted()) return false;
756 }
757 while(newnday.isGreaterThan(daysPerYear(newmonth <= 2 ? newyear : newyear + 1))) {
758 newnday -= daysPerYear(newmonth <= 2 ? newyear : newyear + 1);
759 newyear++;
760 if(check_aborted && CALCULATOR && CALCULATOR->aborted()) return false;
761 }
762 while(newnday.isGreaterThan(daysPerMonth(newmonth, newyear))) {
763 newnday -= daysPerMonth(newmonth, newyear);
764 newmonth++;
765 if(newmonth > 12) {
766 newyear++;
767 newmonth = 1;
768 }
769 }
770 }
771 bool overflow = false;
772 long int newday = newnday.lintValue(&overflow);
773 if(overflow) return false;
774 i_day = newday;
775 i_month = newmonth;
776 i_year = newyear;
777 return true;
778 }
addMonths(const Number & nmonths)779 bool QalculateDateTime::addMonths(const Number &nmonths) {
780 parsed_string.clear();
781 if(!nmonths.isReal() || nmonths.isInterval()) return false;
782 if(!nmonths.isInteger()) {
783 Number newmonths(nmonths);
784 newmonths.trunc();
785 QalculateDateTime dtbak(*this);
786 if(!addMonths(newmonths)) return false;
787 Number nday(nmonths);
788 nday.frac();
789 if(nday.isNegative()) {
790 nday.negate();
791 nday *= daysPerMonth(i_month, i_year);
792 if(nday.isGreaterThanOrEqualTo(i_day - 1)) {
793 nday /= daysPerMonth(i_month, i_year);
794 Number idayfrac(i_day - 1);
795 Number secfrac(i_hour * 3600 + i_min * 60);
796 secfrac += n_sec;
797 secfrac /= 86400;
798 idayfrac += secfrac;
799 idayfrac /= daysPerMonth(i_month, i_year);
800 nday -= idayfrac;
801 nday *= daysPerMonth(i_month == 1 ? 12 : i_month - 1, i_year);
802 idayfrac *= daysPerMonth(i_month, i_year);
803 nday += idayfrac;
804 }
805 nday.negate();
806 } else {
807 nday *= daysPerMonth(i_month, i_year);
808 if(nday.isGreaterThanOrEqualTo(daysPerMonth(i_month, i_year) - i_day)) {
809 nday /= daysPerMonth(i_month, i_year);
810 Number idayfrac(daysPerMonth(i_month, i_year) - i_day);
811 Number secfrac(i_hour * 3600 + i_min * 60);
812 secfrac += n_sec;
813 secfrac /= 86400;
814 idayfrac -= secfrac;
815 idayfrac /= daysPerMonth(i_month, i_year);
816 nday -= idayfrac;
817 nday *= daysPerMonth(i_month == 12 ? 1 : i_month + 1, i_year);
818 idayfrac *= daysPerMonth(i_month, i_year);
819 nday += idayfrac;
820 }
821 }
822 if(!addDays(nday)) {
823 set(dtbak);
824 return false;
825 }
826 return true;
827 }
828 bool overflow = false;
829 long int months = nmonths.lintValue(&overflow);
830 if(overflow) return false;
831 if(i_year > 0 && months > 0 && (unsigned long int) months / 12 + i_year > (unsigned long int) LONG_MAX) return false;
832 if(i_year < 0 && months < 0 && (unsigned long int) (-months / 12) - i_year > (unsigned long int) LONG_MAX) return false;
833 i_year += months / 12;
834 i_month += months % 12;
835 if(i_month > 12) {
836 i_month -= 12;
837 i_year += 1;
838 } else if(i_month < 1) {
839 i_month += 12;
840 i_year -= 1;
841 }
842 if(i_day > daysPerMonth(i_month, i_year)) {
843 i_day -= daysPerMonth(i_month, i_year);
844 i_month++;
845 if(i_month > 12) {
846 i_month -= 12;
847 i_year += 1;
848 }
849 }
850 return true;
851 }
addYears(const Number & nyears)852 bool QalculateDateTime::addYears(const Number &nyears) {
853 parsed_string.clear();
854 if(!nyears.isReal() || nyears.isInterval()) return false;
855 if(!nyears.isInteger()) {
856 Number newyears(nyears);
857 newyears.trunc();
858 QalculateDateTime dtbak(*this);
859 if(!addYears(newyears)) return false;
860 Number nday(nyears);
861 nday.frac();
862 if(nday.isZero()) return true;
863 long int idoy = yearday();
864 if(nday.isNegative()) {
865 nday.negate();
866 nday *= daysPerYear(i_year);
867 if(nday.isGreaterThanOrEqualTo(idoy - 1)) {
868 nday /= daysPerYear(i_year);
869 Number idayfrac(idoy - 1);
870 Number secfrac(i_hour * 3600 + i_min * 60);
871 secfrac += n_sec;
872 secfrac /= 86400;
873 idayfrac += secfrac;
874 idayfrac /= daysPerYear(i_year);
875 nday -= idayfrac;
876 nday *= daysPerYear(i_year - 1);
877 idayfrac *= daysPerYear(i_year);
878 nday += idayfrac;
879 }
880 nday.negate();
881 } else {
882 nday *= daysPerYear(i_year);
883 if(nday.isGreaterThanOrEqualTo(daysPerYear(i_year) - idoy)) {
884 nday /= daysPerYear(i_year);
885 Number idayfrac(idoy - 1);
886 Number secfrac(i_hour * 3600 + i_min * 60);
887 secfrac += n_sec;
888 secfrac /= 86400;
889 idayfrac -= secfrac;
890 idayfrac /= daysPerYear(i_year);
891 nday -= idayfrac;
892 nday *= daysPerYear(i_year + 1);
893 idayfrac *= daysPerYear(i_year);
894 nday += idayfrac;
895 }
896 }
897 if(!addDays(nday)) {
898 set(dtbak);
899 return false;
900 }
901 return true;
902 }
903 bool overflow = false;
904 long int years = nyears.lintValue(&overflow);
905 if(overflow) return false;
906 if(i_year > 0 && years > 0 && (unsigned long int) years + i_year > (unsigned long int) LONG_MAX) return false;
907 if(i_year < 0 && years < 0 && (unsigned long int) (-years) - i_year > (unsigned long int) LONG_MAX) return false;
908 i_year += years;
909 if(i_day > daysPerMonth(i_month, i_year)) {
910 i_day -= daysPerMonth(i_month, i_year);
911 i_month++;
912 if(i_month > 12) {
913 i_month -= 12;
914 i_year += 1;
915 }
916 }
917 return true;
918 }
addSeconds(const Number & seconds,bool count_leap_seconds,bool convert_to_utc)919 bool QalculateDateTime::addSeconds(const Number &seconds, bool count_leap_seconds, bool convert_to_utc) {
920 parsed_string.clear();
921 if(!seconds.isReal() || seconds.isInterval()) return false;
922 if(seconds.isZero()) return true;
923 QalculateDateTime dtbak(*this);
924 if(convert_to_utc) {
925 if(!addMinutes(-dateTimeZone(*this, false), false, false)) return false;
926 }
927 b_time = true;
928 if(count_leap_seconds) {
929 if(seconds.isPositive()) {
930 Number nsum(i_hour * 3600 + i_min * 60);
931 nsum += n_sec;
932 nsum += seconds;
933 if(nsum.isLessThan(SECONDS_PER_DAY)) {
934 if(!addSeconds(seconds, false, false)) {set(dtbak); return false;}
935 if(convert_to_utc) {
936 if(!addMinutes(dateTimeZone(*this, true), false, false)) {set(dtbak); return false;}
937 }
938 return true;
939 }
940 } else {
941 Number nsum(i_hour * 3600 + i_min * 60);
942 nsum += n_sec;
943 nsum += seconds;
944 if(nsum.isZero()) {
945 i_hour = 0;
946 i_min = 0;
947 n_sec.clear(true);
948 if(convert_to_utc) {
949 if(!addMinutes(dateTimeZone(*this, true), false, false)) {set(dtbak); return false;}
950 }
951 } else if(nsum.isPositive()) {
952 if(!addSeconds(seconds, false, false)) {set(dtbak); return false;}
953 if(convert_to_utc) {
954 if(!addMinutes(dateTimeZone(*this, true), false, false)) {set(dtbak); return false;}
955 }
956 return true;
957 }
958 }
959 Number nr_frac(n_sec);
960 nr_frac.frac();
961 n_sec.trunc();
962 Number secnew(seconds);
963 secnew += nr_frac;
964 nr_frac = secnew;
965 nr_frac.frac();
966 secnew.trunc();
967 if(secnew.isZero()) {
968 n_sec += nr_frac;
969 if(convert_to_utc) {
970 if(!addMinutes(dateTimeZone(*this, true), false, false)) {set(dtbak); return false;}
971 }
972 return true;
973 }
974 if(secnew.isNegative() || nr_frac.isNegative()) {
975 if(nr_frac.isNegative()) {
976 nr_frac++;
977 secnew--;
978 }
979 QalculateDateTime dt_nls = prevLeapSecond(*this);
980 while(dt_nls.year() != 0) {
981 Number n_sto = secondsTo(dt_nls, true, false);
982 n_sto--;
983 if(n_sto.isLessThan(secnew)) {
984 break;
985 } else if(n_sto.equals(secnew)) {
986 set(dt_nls);
987 n_sec += nr_frac;
988 if(convert_to_utc) {
989 if(!addMinutes(dateTimeZone(*this, true), false, false)) {set(dtbak); return false;}
990 }
991 return true;
992 }
993 set(dt_nls);
994 n_sec--;
995 secnew -= n_sto;
996 secnew++;
997 dt_nls = prevLeapSecond(*this);
998 }
999 secnew += nr_frac;
1000 if(!addSeconds(secnew, false, false)) {set(dtbak); return false;}
1001 if(convert_to_utc) {
1002 if(!addMinutes(dateTimeZone(*this, true), false, false)) {set(dtbak); return false;}
1003 }
1004 return true;
1005 } else {
1006 if(i_hour == 23 && i_min == 59 && n_sec == 60) {
1007 secnew--;
1008 }
1009 QalculateDateTime dt_nls = nextLeapSecond(*this);
1010 while(dt_nls.year() != 0) {
1011 Number n_sto = secondsTo(dt_nls, true, false);
1012 if(n_sto.isGreaterThan(secnew)) {
1013 break;
1014 } else if(n_sto.equals(secnew)) {
1015 set(dt_nls);
1016 n_sec += nr_frac;
1017 if(convert_to_utc) {
1018 if(!addMinutes(dateTimeZone(*this, true), false, false)) {set(dtbak); return false;}
1019 }
1020 return true;
1021 }
1022 set(dt_nls);
1023 addDays(1);
1024 i_hour = 0;
1025 i_min = 0;
1026 n_sec.clear();
1027 secnew -= n_sto;
1028 secnew--;
1029 dt_nls = nextLeapSecond(*this);
1030 }
1031 secnew += nr_frac;
1032 if(!addSeconds(secnew, false, false)) {set(dtbak); return false;}
1033 if(convert_to_utc) {
1034 if(!addMinutes(dateTimeZone(*this, true), false, false)) {set(dtbak); return false;}
1035 }
1036 return true;
1037 }
1038 }
1039 if(!n_sec.add(seconds)) {set(dtbak); return false;}
1040 if(n_sec.isNegative()) {
1041 if(n_sec.isLessThan(-60)) {
1042 n_sec /= 60;
1043 Number nmins(n_sec);
1044 nmins.trunc();
1045 n_sec.frac();
1046 n_sec *= 60;
1047 if(n_sec.isNegative()) {
1048 n_sec += 60;
1049 nmins--;
1050 }
1051 if(!addMinutes(nmins, false, false)) {set(dtbak); return false;}
1052 } else {
1053 n_sec += 60;
1054 if(!addMinutes(-1, false, false)) {set(dtbak); return false;}
1055 }
1056 } else if(n_sec.isGreaterThanOrEqualTo(60)) {
1057 n_sec /= 60;
1058 Number nmins(n_sec);
1059 nmins.trunc();
1060 n_sec.frac();
1061 n_sec *= 60;
1062 if(!addMinutes(nmins, false, false)) {set(dtbak); return false;}
1063 }
1064 if(convert_to_utc) {
1065 if(!addMinutes(dateTimeZone(*this, true), false, false)) {set(dtbak); return false;}
1066 }
1067 return true;
1068 }
add(const QalculateDateTime & date)1069 bool QalculateDateTime::add(const QalculateDateTime &date) {
1070 parsed_string.clear();
1071 QalculateDateTime dtbak(*this);
1072 if(date.timeIsSet()) b_time = true;
1073 if(!addYears(date.year()) || !addMonths(date.month()) || !addDays(date.day())) {
1074 set(dtbak);
1075 return false;
1076 }
1077 if(!date.second().isZero() || date.hour() != 0 || date.minute() != 0) {
1078 Number nsec(date.hour() * 3600 + date.minute() * 60);
1079 nsec += date.second();
1080 if(!addSeconds(nsec, true, true)) {
1081 set(dtbak);
1082 return false;
1083 }
1084 }
1085 return true;
1086 }
weekday() const1087 int QalculateDateTime::weekday() const {
1088 Number nr(daysTo(QalculateDateTime(2017, 7, 31)));
1089 if(nr.isInfinite()) return -1;
1090 nr.negate();
1091 nr.trunc();
1092 nr.rem(Number(7, 1));
1093 if(nr.isNegative()) return 8 + nr.intValue();
1094 return nr.intValue() + 1;
1095 }
week(bool start_sunday) const1096 int QalculateDateTime::week(bool start_sunday) const {
1097 if(start_sunday) {
1098 int yday = yearday();
1099 QalculateDateTime date1(i_year, 1, 1);
1100 int wday = date1.weekday() + 1;
1101 if(wday < 0) return -1;
1102 if(wday == 8) wday = 1;
1103 yday += (wday - 2);
1104 int week = yday / 7 + 1;
1105 if(week > 52) week = 1;
1106 return week;
1107 }
1108 if(i_month == 12 && i_day >= 29 && weekday() <= i_day - 28) {
1109 return 1;
1110 } else {
1111 QalculateDateTime date(i_year, i_month, i_day);
1112 week_rerun:
1113 int week1;
1114 int day1 = date.yearday();
1115 QalculateDateTime date1(date.year(), 1, 1);
1116 int wday = date1.weekday();
1117 if(wday < 0) return -1;
1118 day1 -= (8 - wday);
1119 if(wday <= 4) {
1120 week1 = 1;
1121 } else {
1122 week1 = 0;
1123 }
1124 if(day1 > 0) {
1125 day1--;
1126 week1 += day1 / 7 + 1;
1127 }
1128 if(week1 == 0) {
1129 date.set(date.year() - 1, 12, 31);
1130 goto week_rerun;
1131 }
1132 return week1;
1133 }
1134 }
yearday() const1135 int QalculateDateTime::yearday() const {
1136 int yday = 0;
1137 for(long int i = 1; i < i_month; i++) {
1138 yday += daysPerMonth(i, i_year);
1139 }
1140 return yday + i_day;
1141 }
timestamp(bool reverse_utc) const1142 Number QalculateDateTime::timestamp(bool reverse_utc) const {
1143 QalculateDateTime date(nr_zero);
1144 return date.secondsTo(*this, false, !reverse_utc);
1145 }
secondsTo(const QalculateDateTime & date,bool count_leap_seconds,bool convert_to_utc) const1146 Number QalculateDateTime::secondsTo(const QalculateDateTime &date, bool count_leap_seconds, bool convert_to_utc) const {
1147 if(convert_to_utc) {
1148 QalculateDateTime dt1(*this), dt2(date);
1149 dt1.addMinutes(-dateTimeZone(dt1, false), false, false);
1150 dt2.addMinutes(-dateTimeZone(dt2, false), false, false);
1151 return dt1.secondsTo(dt2, count_leap_seconds, false);
1152 }
1153 Number nr = daysTo(date, 1, true, !count_leap_seconds);
1154 nr *= SECONDS_PER_DAY;
1155 if(count_leap_seconds) {
1156 nr += countLeapSeconds(*this, date);
1157 }
1158 return nr;
1159 }
daysTo(const QalculateDateTime & date,int basis,bool date_func,bool remove_leap_seconds) const1160 Number QalculateDateTime::daysTo(const QalculateDateTime &date, int basis, bool date_func, bool remove_leap_seconds) const {
1161
1162 Number nr;
1163
1164 if(basis < 0 || basis > 4) basis = 1;
1165
1166 bool neg = false;
1167 bool isleap = false;
1168 long int days, years;
1169
1170 long int day1 = i_day, month1 = i_month, year1 = i_year;
1171 long int day2 = date.day(), month2 = date.month(), year2 = date.year();
1172 Number t1(n_sec), t2(date.second());
1173 if(remove_leap_seconds) {
1174 if(t1.isGreaterThanOrEqualTo(60)) t1--;
1175 if(t2.isGreaterThanOrEqualTo(60)) t2--;
1176 }
1177 t1 += i_hour * 3600 + i_min * 60;
1178 t2 += date.hour() * 3600 + date.minute() * 60;
1179
1180 if(year1 > year2 || (year1 == year2 && month1 > month2) || (year1 == year2 && month1 == month2 && day1 > day2) || (basis == 1 && date_func && year1 == year2 && month1 == month2 && day1 == day2 && t1.isGreaterThan(t2))) {
1181 int year3 = year1, month3 = month1, day3 = day1;
1182 year1 = year2; month1 = month2; day1 = day2;
1183 year2 = year3; month2 = month3; day2 = day3;
1184 Number t3(t1);
1185 t1 = t2; t2 = t3;
1186 neg = true;
1187 }
1188
1189 years = year2 - year1;
1190 days = day2 - day1;
1191
1192 isleap = isLeapYear(year1);
1193
1194 switch(basis) {
1195 case 0: {
1196 nr.set(years, 1, 0);
1197 nr *= 12;
1198 nr += (month2 - month1);
1199 nr *= 30;
1200 nr += days;
1201 if(date_func) {
1202 if(month1 == 2 && ((day1 == 28 && !isleap) || (day1 == 29 && isleap)) && !(month2 == month1 && day1 == day2 && year1 == year2)) {
1203 if(isleap) nr -= 1;
1204 else nr -= 2;
1205 } else if(day1 == 31 && day2 < 31) {
1206 nr++;
1207 }
1208 } else {
1209 if(month1 == 2 && month2 != 2 && year1 == year2) {
1210 if(isleap) nr -= 1;
1211 else nr -= 2;
1212 }
1213 }
1214 break;
1215 }
1216 case 1: {}
1217 case 2: {}
1218 case 3: {
1219 int month4 = month2;
1220 bool b;
1221 if(years > 0) {
1222 month4 = 12;
1223 b = true;
1224 } else {
1225 b = false;
1226 }
1227 nr.set(days, 1, 0);
1228 for(; month1 < month4 || b; month1++) {
1229 if(month1 > month4 && b) {
1230 b = false;
1231 month1 = 1;
1232 month4 = month2;
1233 if(month1 == month2) break;
1234 }
1235 if(!b) {
1236 nr += daysPerMonth(month1, year2);
1237 } else {
1238 nr += daysPerMonth(month1, year1);
1239 }
1240 }
1241 if(basis == 1 && !t1.equals(t2)) {
1242 t2 -= t1;
1243 t2 /= 86400;
1244 nr += t2;
1245 }
1246 if(years == 0) break;
1247 bool check_aborted = years > 10000L;
1248 for(year1 += 1; year1 < year2; year1++) {
1249 if(check_aborted && CALCULATOR && CALCULATOR->aborted()) {
1250 nr.setPlusInfinity();
1251 return nr;
1252 }
1253 if(isLeapYear(year1)) nr += 366;
1254 else nr += 365;
1255 }
1256 break;
1257 }
1258 case 4: {
1259 nr.set(years, 1, 0);
1260 nr *= 12;
1261 nr += (month2 - month1);
1262 if(date_func) {
1263 if(day2 == 31 && day1 < 31) days--;
1264 if(day1 == 31 && day2 < 31) days++;
1265 }
1266 nr *= 30;
1267 nr += days;
1268 break;
1269 }
1270 }
1271 if(neg) nr.negate();
1272 return nr;
1273 }
yearsTo(const QalculateDateTime & date,int basis,bool date_func,bool remove_leap_seconds) const1274 Number QalculateDateTime::yearsTo(const QalculateDateTime &date, int basis, bool date_func, bool remove_leap_seconds) const {
1275 Number nr;
1276 if(basis < 0 || basis > 4) basis = 1;
1277 if(basis == 1) {
1278 if(date.year() == i_year) {
1279 nr.set(daysTo(date, basis, date_func));
1280 nr.divide(daysPerYear(i_year, basis));
1281 } else {
1282 bool neg = false;
1283 long int day1 = i_day, month1 = i_month, year1 = i_year;
1284 long int day2 = date.day(), month2 = date.month(), year2 = date.year();
1285 Number t1(n_sec), t2(date.second());
1286 if(remove_leap_seconds) {
1287 if(t1.isGreaterThanOrEqualTo(60)) t1--;
1288 if(t2.isGreaterThanOrEqualTo(60)) t2--;
1289 }
1290 t1 += i_hour * 3600 + i_min * 60;
1291 t2 += date.hour() * 3600 + date.minute() * 60;
1292 if(year1 > year2) {
1293 int year3 = year1, month3 = month1, day3 = day1;
1294 year1 = year2; month1 = month2; day1 = day2;
1295 year2 = year3; month2 = month3; day2 = day3;
1296 Number t3(t1);
1297 t1 = t2; t2 = t3;
1298 neg = true;
1299 }
1300 t1 /= 86400;
1301 t2 /= 86400;
1302 for(int month = 12; month > month1; month--) {
1303 nr += daysPerMonth(month, year1);
1304 }
1305 nr += daysPerMonth(month1, year1) - day1 + 1;
1306 nr -= t1;
1307 for(int month = 1; month < month2; month++) {
1308 nr += daysPerMonth(month, year2);
1309 }
1310 nr += day2 - 1;
1311 nr += t2;
1312 bool check_aborted = (year2 - year1) > 10000L;
1313 Number days_of_years;
1314 for(int year = year1; year <= year2; year++) {
1315 if(check_aborted && CALCULATOR && CALCULATOR->aborted()) {
1316 nr.setPlusInfinity();
1317 return nr;
1318 }
1319 days_of_years += daysPerYear(year, basis);
1320 if(year != year1 && year != year2) {
1321 nr += daysPerYear(year, basis);
1322 }
1323 }
1324 days_of_years /= year2 + 1 - year1;
1325 nr /= days_of_years;
1326 if(neg) nr.negate();
1327 }
1328 } else {
1329 nr.set(daysTo(date, basis, date_func));
1330 nr.divide(daysPerYear(0, basis));
1331 }
1332 return nr;
1333 }
1334
1335
1336
1337
quotient(long int i,long int d)1338 long int quotient(long int i, long int d) {
1339 i /= d;
1340 if((i < 0) != (d < 0)) i--;
1341 return i;
1342 }
quotient(Number nr,long int d)1343 Number quotient(Number nr, long int d) {
1344 nr /= d;
1345 nr.floor();
1346 return nr;
1347 }
1348
cal_div(const Number & nr_n,long int nr_d,Number & nr_q,Number & nr_r)1349 void cal_div(const Number &nr_n, long int nr_d, Number &nr_q, Number &nr_r) {
1350 nr_q = nr_n; nr_q /= nr_d; nr_q.floor();
1351 nr_r = nr_n; nr_r.mod(nr_d);
1352 }
cal_div(const Number & nr_n,long int nr_d,Number & nr_q)1353 void cal_div(const Number &nr_n, long int nr_d, Number &nr_q) {
1354 nr_q = nr_n; nr_q /= nr_d; nr_q.floor();
1355 }
cal_div(Number & nr_n,long int nr_d)1356 void cal_div(Number &nr_n, long int nr_d) {
1357 nr_n /= nr_d; nr_n.floor();
1358 }
1359
1360 #define GREGORIAN_EPOCH 1
1361 #define JULIAN_EPOCH -1 // (date_to_fixed(0, 12, 30, CALENDAR_GREGORIAN))
1362 #define ISLAMIC_EPOCH 227015 // date_to_fixed(622, 7, 16, CALENDAR_JULIAN)
1363 #define PERSIAN_EPOCH 226896 // date_to_fixed(622, 3, 19, CALENDAR_JULIAN)
1364 #define JD_EPOCH (Number("-1721424.5"))
1365 #define EGYPTIAN_EPOCH -272787L //jd_to_fixed(1448638))
1366 #define HEBREW_EPOCH -1373427 //date_to_fixed(-3761, 10, 7, CALENDAR_JULIAN)
1367 #define COPTIC_EPOCH 103605
1368 #define ETHIOPIAN_EPOCH 2796
1369 #define CHINESE_EPOCH -963099L //date_to_fixed(-2636, 2, 15, CALENDAR_GREGORIAN)
1370 #define MEAN_TROPICAL_YEAR (Number("365.242189"))
1371 #define MEAN_SIDEREAL_YEAR (Number("365.25636"))
1372 #define MEAN_SYNODIC_MONTH (Number("29.530588861"))
1373
jd_to_fixed(Number jd)1374 Number jd_to_fixed(Number jd) {
1375 jd += JD_EPOCH;
1376 jd.floor();
1377 return jd;
1378 }
1379
1380 bool cjdn_to_date(Number J, long int &y, long int &m, long int &d, CalendarSystem ct);
1381 Number date_to_cjdn(long int j, long int m, long int d, CalendarSystem ct);
1382 bool fixed_to_date(Number date, long int &y, long int &m, long int &d, CalendarSystem ct);
1383 Number date_to_fixed(long int y, long int m, long int d, CalendarSystem ct);
1384
gregorian_year_from_fixed(Number date)1385 long int gregorian_year_from_fixed(Number date) {
1386 Number d0, n400, d1, n100, d2, n4, d3, n1, year;
1387 d0 = date; d0 -= 1;
1388 cal_div(d0, 146097, n400, d1);
1389 cal_div(d1, 36524, n100, d2);
1390 cal_div(d2, 1461, n4, d3);
1391 cal_div(d3, 365, n1);
1392 if(!n100.equals(4) && !n1.equals(4)) year = 1;
1393 else year = 0;
1394 n400 *= 400; n100 *= 100; n4 *= 4; year += n400; year += n100; year += n4; year += n1;
1395 return year.lintValue();
1396 }
1397
gregorian_date_difference(long int y1,long int m1,long int d1,long int y2,long int m2,long int d2)1398 Number gregorian_date_difference(long int y1, long int m1, long int d1, long int y2, long int m2, long int d2) {
1399 Number f1 = date_to_fixed(y2, m2, d2, CALENDAR_GREGORIAN);
1400 f1 -= date_to_fixed(y1, m1, d1, CALENDAR_GREGORIAN);
1401 return f1;
1402 }
1403
ephemeris_correction(Number tee)1404 Number ephemeris_correction(Number tee) {
1405 tee.floor();
1406 Number year = gregorian_year_from_fixed(tee);
1407 if(year > 2150 || year < -500) {
1408 year -= 1820; year /= 100;
1409 Number x(year);
1410 Number t, a;
1411 t = -20; a += t;
1412 x *= year; t = 32; t *= x; a += t;
1413 a /= 86400;
1414 return a;
1415 } else if(year < 500) {
1416 year /= 100;
1417 Number x(year);
1418 Number t, a;
1419 t.setFloat(10583.6L); a += t;
1420 t.setFloat(-1014.41L); t *= x; a += t;
1421 x *= year; t.setFloat(33.78311L); t *= x; a += t;
1422 x *= year; t.setFloat(-5.952053L); t *= x; a += t;
1423 x *= year; t.setFloat(-0.1798452L); t *= x; a += t;
1424 x *= year; t.setFloat(0.022174192L); t *= x; a += t;
1425 x *= year; t.setFloat(0.0090316521L); t *= x; a += t;
1426 a /= 86400;
1427 return a;
1428 } else if(year < 1600) {
1429 year -= 1000; year /= 100;
1430 Number x(year);
1431 Number t, a;
1432 t.setFloat(1574.2L); a += t;
1433 t.setFloat(-556.01L); t *= x; a += t;
1434 x *= year; t.setFloat(71.23472L); t *= x; a += t;
1435 x *= year; t.setFloat(0.319781L); t *= x; a += t;
1436 x *= year; t.setFloat(-0.8503463L); t *= x; a += t;
1437 x *= year; t.setFloat(-0.005050998L); t *= x; a += t;
1438 x *= year; t.setFloat(0.0083572073L); t *= x; a += t;
1439 a /= 86400;
1440 return a;
1441 } else if(year < 1700) {
1442 year -= 1600;
1443 Number x(year);
1444 Number t, a;
1445 t = 120; a += t;
1446 t.setFloat(-0.9808L); t *= x; a += t;
1447 x *= year; t.setFloat(-0.01532L); t *= x; a += t;
1448 x *= year; t.setFloat(0.000140272128L); t *= x; a += t;
1449 a /= 86400;
1450 return a;
1451 } else if(year < 1800) {
1452 year -= 1700;
1453 Number x(year);
1454 Number t, a;
1455 t.setFloat(8.118780842L); a += t;
1456 t.setFloat(-0.005092142L); t *= x; a += t;
1457 x *= year; t.setFloat(0.003336121L); t *= x; a += t;
1458 x *= year; t.setFloat(-0.0000266484L); t *= x; a += t;
1459 a /= 86400;
1460 return a;
1461 } else if(year < 1900) {
1462 Number c = gregorian_date_difference(1900, 1, 1, year.lintValue(), 7, 1); c /= 36525;
1463 year = c;
1464 Number x(year);
1465 Number t, a;
1466 t.setFloat(-0.000009L); a += t;
1467 t.setFloat(0.003844L); t *= x; a += t;
1468 x *= year; t.setFloat(0.083563L); t *= x; a += t;
1469 x *= year; t.setFloat(0.865736L); t *= x; a += t;
1470 x *= year; t.setFloat(4.867575L); t *= x; a += t;
1471 x *= year; t.setFloat(15.845535L); t *= x; a += t;
1472 x *= year; t.setFloat(31.332267L); t *= x; a += t;
1473 x *= year; t.setFloat(38.291999L); t *= x; a += t;
1474 x *= year; t.setFloat(28.316289L); t *= x; a += t;
1475 x *= year; t.setFloat(11.636204L); t *= x; a += t;
1476 x *= year; t.setFloat(2.043794L); t *= x; a += t;
1477 return a;
1478 } else if(year < 1987) {
1479 Number c = gregorian_date_difference(1900, 1, 1, year.lintValue(), 7, 1); c /= 36525;
1480 year = c;
1481 Number x(year);
1482 Number t, a;
1483 t.setFloat(-0.00002L); a += t;
1484 t.setFloat(0.000297L); t *= x; a += t;
1485 x *= year; t.setFloat(0.025184L); t *= x; a += t;
1486 x *= year; t.setFloat(-0.181133L); t *= x; a += t;
1487 x *= year; t.setFloat(0.553040L); t *= x; a += t;
1488 x *= year; t.setFloat(-0.861938L); t *= x; a += t;
1489 x *= year; t.setFloat(0.677066L); t *= x; a += t;
1490 x *= year; t.setFloat(-0.212591L); t *= x; a += t;
1491 return a;
1492 } else if(year < 2006) {
1493 year -= 2000;
1494 Number x(year);
1495 Number t, a;
1496 t.setFloat(63.86L); a += t;
1497 t.setFloat(0.3345L); t *= x; a += t;
1498 x *= year; t.setFloat(-0.060374L); t *= x; a += t;
1499 x *= year; t.setFloat(0.0017275L); t *= x; a += t;
1500 x *= year; t.setFloat(0.000651814L); t *= x; a += t;
1501 x *= year; t.setFloat(0.00002373599L); t *= x; a += t;
1502 a /= 86400;
1503 return a;
1504 } else if(year <= 2050) {
1505 year -= 2000;
1506 Number x(year);
1507 Number t, a;
1508 t.setFloat(62.92L); a += t;
1509 t.setFloat(0.32217L); t *= x; a += t;
1510 x *= year; t.setFloat(0.005589L); t *= x; a += t;
1511 a /= 86400;
1512 return a;
1513 } else {
1514 Number year2(year); year2 -= 1820; year2 /= 100; year2.square(); year2 *= 32; year2 -= 20;
1515 year.negate(); year += 2150; year *= Number(5628, 10000); year += year2; year /= 86400;
1516 return year;
1517 }
1518 }
1519
dynamical_from_universal(Number tee_rom_u)1520 Number dynamical_from_universal(Number tee_rom_u) {
1521 tee_rom_u += ephemeris_correction(tee_rom_u);
1522 return tee_rom_u;
1523 }
1524
1525 #define J2000 Number("730120.5")
1526
1527
julian_centuries(Number tee)1528 Number julian_centuries(Number tee) {
1529 tee = dynamical_from_universal(tee);
1530 tee -= J2000;
1531 tee /= 36525;
1532 return tee;
1533 }
1534
nutation(Number tee)1535 Number nutation(Number tee) {
1536 Number c = julian_centuries(tee);
1537 Number cap_a;
1538 Number t, x(c);
1539 t.setFloat(124.90L); cap_a += t;
1540 t.setFloat(-1934.134L); t *= x; cap_a += t;
1541 x *= c; t.setFloat(0.002063L); t *= x; cap_a += t;
1542 Number cap_b;
1543 x = c;
1544 t.setFloat(201.11L); cap_b += t;
1545 t.setFloat(72001.5377L); t *= x; cap_b += t;
1546 x *= c; t.setFloat(0.00057L); t *= x; cap_b += t;
1547 Number nr_pi; nr_pi.pi();
1548 t.setFloat(-0.004778L);
1549 cap_a *= nr_pi; cap_a /= 180; cap_a.sin(); cap_a *= t;
1550 t.setFloat(-0.0003667L);
1551 cap_b *= nr_pi; cap_b /= 180; cap_b.sin(); cap_b *= t;
1552 cap_a += cap_b;
1553 return cap_a;
1554 }
1555
aberration(Number tee)1556 Number aberration(Number tee) {
1557 Number c = julian_centuries(tee);
1558 Number t;
1559 t.setFloat(35999.01848L);
1560 c *= t;
1561 t.setFloat(177.63L);
1562 c += t;
1563 Number nr_pi; nr_pi.pi();
1564 c *= nr_pi; c /= 180;
1565 c.cos();
1566 t.setFloat(0.0000974L);
1567 c *= t;
1568 t.setFloat(0.005575L);
1569 c -= t;
1570 return c;
1571 }
1572
solar_longitude(Number tee)1573 Number solar_longitude(Number tee) {
1574 Number c = julian_centuries(tee);
1575 Number lam; lam.setFloat(282.7771834L);
1576 Number t2; t2.setFloat(36000.76953744L); t2 *= c;
1577 Number t3;
1578 long int coefficients[] = {
1579 403406L, 195207L, 119433L, 112392L, 3891L, 2819L, 1721L,
1580 660L, 350L, 334L, 314L, 268L, 242L, 234L, 158L, 132L, 129L, 114L,
1581 99L, 93L, 86L, 78L, 72L, 68L, 64L, 46L, 38L, 37L, 32L, 29L, 28L, 27L, 27L,
1582 25L, 24L, 21L, 21L, 20L, 18L, 17L, 14L, 13L, 13L, 13L, 12L, 10L, 10L, 10L,
1583 10L, -1L
1584 };
1585 long double multipliers[] = {
1586 0.9287892L, 35999.1376958L, 35999.4089666L,
1587 35998.7287385L, 71998.20261L, 71998.4403L,
1588 36000.35726L, 71997.4812L, 32964.4678L,
1589 -19.4410L, 445267.1117L, 45036.8840L, 3.1008L,
1590 22518.4434L, -19.9739L, 65928.9345L,
1591 9038.0293L, 3034.7684L, 33718.148L, 3034.448L,
1592 -2280.773L, 29929.992L, 31556.493L, 149.588L,
1593 9037.750L, 107997.405L, -4444.176L, 151.771L,
1594 67555.316L, 31556.080L, -4561.540L,
1595 107996.706L, 1221.655L, 62894.167L,
1596 31437.369L, 14578.298L, -31931.757L,
1597 34777.243L, 1221.999L, 62894.511L,
1598 -4442.039L, 107997.909L, 119.066L, 16859.071L,
1599 -4.578L, 26895.292L, -39.127L, 12297.536L,
1600 90073.778L
1601 };
1602 long double addends[] = {
1603 270.54861L, 340.19128L, 63.91854L, 331.26220L,
1604 317.843L, 86.631L, 240.052L, 310.26L, 247.23L,
1605 260.87L, 297.82L, 343.14L, 166.79L, 81.53L,
1606 3.50L, 132.75L, 182.95L, 162.03L, 29.8L,
1607 266.4L, 249.2L, 157.6L, 257.8L, 185.1L, 69.9L,
1608 8.0L, 197.1L, 250.4L, 65.3L, 162.7L, 341.5L,
1609 291.6L, 98.5L, 146.7L, 110.0L, 5.2L, 342.6L,
1610 230.9L, 256.1L, 45.3L, 242.9L, 115.2L, 151.8L,
1611 285.3L, 53.3L, 126.6L, 205.7L, 85.9L,
1612 146.1L
1613 };
1614 Number x, y, z, nr_pi; nr_pi.pi();
1615 for(size_t i = 0; coefficients[i] >= 0; i++) {
1616 x = coefficients[i];
1617 y.setFloat(addends[i]);
1618 z.setFloat(multipliers[i]);
1619 z *= c;
1620 z += y;
1621 z *= nr_pi;
1622 z /= 180;
1623 z.sin();
1624 z *= x;
1625 t3 += z;
1626 }
1627 Number t; t.setFloat(0.000005729577951308232L);
1628 t3 *= t;
1629 lam += t2; lam += t3;
1630 lam += aberration(tee);
1631 lam += nutation(tee);
1632 lam.mod(360);
1633 return lam;
1634 }
1635
solar_longitude_after(Number longitude,Number tee)1636 Number solar_longitude_after(Number longitude, Number tee) {
1637 Number rate = MEAN_TROPICAL_YEAR; rate /= 360;
1638 Number tau(longitude); tau -= solar_longitude(tee); tau.mod(360); tau *= rate; tau += tee;
1639 Number a(tau); a -= 5; if(tee > a) a = tee;
1640 Number b(tau); b += 5;
1641 Number along = solar_longitude(a);
1642 Number blong = solar_longitude(b);
1643 Number precexp(1, 1, -5);
1644 Number long_low(longitude); long_low -= precexp;
1645 Number long_high(longitude); long_high += precexp;
1646 if(long_low < 0) long_low += 360;
1647 if(long_high > 360) long_high -= 360;
1648 Number newlong;
1649 Number test(a);
1650 while(true) {
1651 if(CALCULATOR->aborted()) return nr_zero;
1652 test = b; test -= a; test /= 2; test += a;
1653 newlong = solar_longitude(test);
1654 if(long_high < long_low) {
1655 if(newlong >= long_low || newlong <= long_high) return test;
1656 } else {
1657 if(newlong >= long_low && newlong <= long_high) return test;
1658 }
1659 if(along > blong) {
1660 if((newlong > longitude && newlong < along) || (newlong < longitude && newlong < along)) b = test;
1661 else a = test;
1662 } else {
1663 if(newlong > longitude) b = test;
1664 else a = test;
1665 }
1666 }
1667 }
obliquity(Number tee)1668 Number obliquity(Number tee) {
1669 Number c = julian_centuries(tee);
1670 tee.setFloat(21.448L); tee /= 60; tee += 26; tee /= 60; tee += 23;
1671 Number t, x(c);
1672 t.setFloat(-46.8150L); t /= 3600; t *= x; tee += t;
1673 x *= c; t.setFloat(-0.00059L); t /= 3600; t *= x; tee += t;
1674 x *= c; t.setFloat(0.001813L); t /= 3600; t *= x; tee += t;
1675 return tee;
1676 }
1677
cal_poly(Number c,size_t n,...)1678 Number cal_poly(Number c, size_t n, ...) {
1679 va_list ap;
1680 va_start(ap, n);
1681 Number x(1, 1, 0), t, poly;
1682 for(size_t i = 0; i < n; i++) {
1683 t.setFloat(va_arg(ap, long double));
1684 t *= x;
1685 poly += t;
1686 x *= c;
1687 }
1688 va_end(ap);
1689 return poly;
1690 }
1691
equation_of_time(Number tee)1692 Number equation_of_time(Number tee) {
1693 Number c = julian_centuries(tee);
1694 vector<long double> a;
1695 Number lam, anomaly, eccentricity;
1696 Number t, x(c);
1697 t.setFloat(280.46645L); lam += t;
1698 t.setFloat(36000.76983L); t *= x; lam += t;
1699 x *= c; t.setFloat(0.0003032L); t *= x; lam += t;
1700 x = c;
1701 t.setFloat(357.52910L); anomaly += t;
1702 t.setFloat(35999.05030L); t *= x; anomaly += t;
1703 x *= c; t.setFloat(-0.0001559L); t *= x; anomaly += t;
1704 x *= c; t.setFloat(-0.00000048L); t *= x; anomaly += t;
1705 x = c;
1706 t.setFloat(0.016708617L); eccentricity += t;
1707 t.setFloat(-0.000042037L); t *= x; eccentricity += t;
1708 x *= c; t.setFloat(-0.0000001236L); t *= x; eccentricity += t;
1709 Number varepsilon = obliquity(tee);
1710 Number nr_pi; nr_pi.pi();
1711 Number y(varepsilon); y /= 2; y *= nr_pi; y /= 180; y.tan(); y.square();
1712 Number equation(1, 2); equation /= nr_pi;
1713 Number e1(lam); e1 *= 2; e1 *= nr_pi; e1 /= 180; e1.sin(); e1 *= y;
1714 Number e2(anomaly); e2 *= nr_pi; e2 /= 180; e2.sin(); e2 *= eccentricity;
1715 Number e3(lam); e3 *= 2; e3 *= nr_pi; e3 /= 180; e3.cos(); e3 *= e2; e3 *= y; e3 *= 4; e2 *= -2;
1716 Number e4(lam); e4 *= 4; e4 *= nr_pi; e4 /= 180; e4.sin(); e4 *= y; e4 *= y; e4 /= -2;
1717 Number e5(anomaly); e5 *= 2; e5 *= nr_pi; e5 /= 180; e5.sin(); e5 *= eccentricity; e5 *= eccentricity; e5 *= -5; e5 /= 4;
1718 e1 += e2; e1 += e3; e1 += e4; e1 += e5; equation *= e1;
1719 bool b_neg = equation.isNegative();
1720 equation.abs();
1721 if(equation < nr_half) {
1722 if(b_neg) equation.negate();
1723 return equation;
1724 } else {
1725 if(b_neg) return nr_minus_half;
1726 return nr_half;
1727 }
1728 }
zone_from_longitude(Number phi)1729 Number zone_from_longitude(Number phi) {
1730 phi /= 360;
1731 return phi;
1732 }
universal_from_local(Number tee_ell,Number longitude)1733 Number universal_from_local(Number tee_ell, Number longitude) {
1734 tee_ell -= zone_from_longitude(longitude);
1735 return tee_ell;
1736 }
local_from_apparent(Number tee,Number longitude)1737 Number local_from_apparent(Number tee, Number longitude) {
1738 tee -= equation_of_time(universal_from_local(tee, longitude));
1739 return tee;
1740 }
universal_from_apparent(Number tee,Number longitude)1741 Number universal_from_apparent(Number tee, Number longitude) {
1742 return universal_from_local(local_from_apparent(tee, longitude), longitude);
1743 }
universal_from_standard(Number tee_rom_s,Number zone)1744 Number universal_from_standard(Number tee_rom_s, Number zone) {
1745 tee_rom_s -= zone;
1746 return tee_rom_s;
1747 }
standard_from_universal(Number tee_rom_u,Number zone)1748 Number standard_from_universal(Number tee_rom_u, Number zone) {
1749 tee_rom_u += zone;
1750 return tee_rom_u;
1751 }
standard_from_local(Number tee_ell,Number longitude,Number zone)1752 Number standard_from_local(Number tee_ell, Number longitude, Number zone) {
1753 return standard_from_universal(universal_from_local(tee_ell, longitude), zone);
1754 }
midday2(Number date,Number longitude,Number zone)1755 Number midday2(Number date, Number longitude, Number zone) {
1756 date += nr_half;
1757 return standard_from_local(local_from_apparent(date, longitude), longitude, zone);
1758 }
midday(Number date,Number longitude)1759 Number midday(Number date, Number longitude) {
1760 date += nr_half;
1761 return universal_from_apparent(date, longitude);
1762 }
1763
1764 #define TEHRAN_LONGITUDE Number("51.42")
1765 #define TEHRAN_ZONE Number(7, 48)
1766
midday_in_tehran(Number date)1767 Number midday_in_tehran(Number date) {
1768 return midday(date, TEHRAN_LONGITUDE);
1769 }
1770
chinese_zone(Number tee)1771 Number chinese_zone(Number tee) {
1772 tee.floor();
1773 if(gregorian_year_from_fixed(tee) < 1929) return Number(1397, 4320);
1774 return Number(1, 3);
1775 }
1776
midnight_in_china(Number date)1777 Number midnight_in_china(Number date) {
1778 return universal_from_standard(date, chinese_zone(date));
1779 }
1780
estimate_prior_solar_longitude(Number lam,Number tee)1781 Number estimate_prior_solar_longitude(Number lam, Number tee) {
1782 Number rate = MEAN_TROPICAL_YEAR; rate /= 360;
1783 Number tau = solar_longitude(tee); tau -= lam; tau.mod(360); tau *= rate;
1784 tau.negate();
1785 tau += tee;
1786 Number cap_delta = solar_longitude(tau); cap_delta -= lam; cap_delta += 180; cap_delta.mod(360); cap_delta -= 180;
1787 cap_delta *= rate;
1788 tau -= cap_delta;
1789 if(tau < tee) return tau;
1790 return tee;
1791 }
1792
persian_new_year_on_or_before(Number date)1793 Number persian_new_year_on_or_before(Number date) {
1794 Number approx = estimate_prior_solar_longitude(nr_zero, midday_in_tehran(date));
1795 approx.floor(); approx -= 1;
1796 Number day(approx);
1797 while(solar_longitude(midday_in_tehran(day)).isGreaterThan(2)) {
1798 if(CALCULATOR->aborted()) break;
1799 day++;
1800 }
1801 return day;
1802 }
1803
universal_from_dynamical(Number tee)1804 Number universal_from_dynamical(Number tee) {
1805 tee -= ephemeris_correction(tee);
1806 return tee;
1807 }
1808
mean_lunar_longitude(Number c)1809 Number mean_lunar_longitude(Number c) {
1810 c = cal_poly(c, 5, 218.3164477L, 481267.88123421L, -0.0015786L, 1.0L/538841.0L, -1.0L/65194000.0L);
1811 c.mod(360);
1812 return c;
1813 }
lunar_elongation(Number c)1814 Number lunar_elongation(Number c) {
1815 c = cal_poly(c, 5, 297.8501921L, 445267.1114034L, -0.0018819L, 1.0L/545868.0L, -1.0L/113065000.0L);
1816 c.mod(360);
1817 return c;
1818 }
solar_anomaly(Number c)1819 Number solar_anomaly(Number c) {
1820 c = cal_poly(c, 4, 357.5291092L, 35999.0502909L, -0.0001536L, 1.0L/24490000.0L);
1821 c.mod(360);
1822 return c;
1823 }
lunar_anomaly(Number c)1824 Number lunar_anomaly(Number c) {
1825 c = cal_poly(c, 5, 134.9633964L, 477198.8675055L, 0.0087414L, 1.0L/69699.0L, -1.0L/14712000.0L);
1826 c.mod(360);
1827 return c;
1828 }
moon_node(Number c)1829 Number moon_node(Number c) {
1830 c = cal_poly(c, 5, 93.2720950L, 483202.0175233L, -0.0036539L, -1.0L/3526000.0L, 1.0L/863310000.0L);
1831 c.mod(360);
1832 return c;
1833 }
1834
lunar_longitude(Number tee)1835 Number lunar_longitude(Number tee) {
1836 Number c = julian_centuries(tee);
1837 Number cap_L_prime = mean_lunar_longitude(c);
1838 Number cap_D = lunar_elongation(c);
1839 Number cap_M = solar_anomaly(c);
1840 Number cap_M_prime = lunar_anomaly(c);
1841 Number cap_F = moon_node(c);
1842 Number cap_E = cal_poly(c, 3, 1.0L, -0.002516L, -0.0000074L);
1843 Number correction;
1844 int args_lunar_elongation[] = {
1845 0, 2, 2, 0, 0, 0, 2, 2, 2, 2, 0, 1, 0, 2, 0, 0, 4, 0, 4, 2, 2, 1,
1846 1, 2, 2, 4, 2, 0, 2, 2, 1, 2, 0, 0, 2, 2, 2, 4, 0, 3, 2, 4, 0, 2,
1847 2, 2, 4, 0, 4, 1, 2, 0, 1, 3, 4, 2, 0, 1, 2, -1
1848 };
1849 int args_solar_anomaly[] = {
1850 0, 0, 0, 0, 1, 0, 0, -1, 0, -1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1,
1851 0, 1, -1, 0, 0, 0, 1, 0, -1, 0, -2, 1, 2, -2, 0, 0, -1, 0, 0, 1,
1852 -1, 2, 2, 1, -1, 0, 0, -1, 0, 1, 0, 1, 0, 0, -1, 2, 1, 0
1853 };
1854 int args_lunar_anomaly[] = {
1855 1, -1, 0, 2, 0, 0, -2, -1, 1, 0, -1, 0, 1, 0, 1, 1, -1, 3, -2,
1856 -1, 0, -1, 0, 1, 2, 0, -3, -2, -1, -2, 1, 0, 2, 0, -1, 1, 0,
1857 -1, 2, -1, 1, -2, -1, -1, -2, 0, 1, 4, 0, -2, 0, 2, 1, -2, -3,
1858 2, 1, -1, 3
1859 };
1860 int args_moon_node[] = {
1861 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, -2, 2, -2, 0, 0, 0, 0, 0,
1862 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, -2, 2, 0, 2, 0, 0, 0, 0,
1863 0, 0, -2, 0, 0, 0, 0, -2, -2, 0, 0, 0, 0, 0, 0, 0
1864 };
1865 long int sine_coeff[] = {
1866 6288774L, 1274027L, 658314L, 213618L, -185116L, -114332L,
1867 58793L, 57066L, 53322L, 45758L, -40923L, -34720L, -30383L,
1868 15327L, -12528L, 10980L, 10675L, 10034L, 8548L, -7888L,
1869 -6766L, -5163L, 4987L, 4036L, 3994L, 3861L, 3665L, -2689L,
1870 -2602L, 2390L, -2348L, 2236L, -2120L, -2069L, 2048L, -1773L,
1871 -1595L, 1215L, -1110L, -892L, -810L, 759L, -713L, -700L, 691L,
1872 596L, 549L, 537L, 520L, -487L, -399L, -381L, 351L, -340L, 330L,
1873 327L, -323L, 299L, 294L
1874 };
1875 Number v, w, x, x2, x3, y, z, nr_pi; nr_pi.pi();
1876 for(size_t i = 0; args_lunar_elongation[i] >= 0; i++) {
1877 v = sine_coeff[i];
1878 w = args_lunar_elongation[i];
1879 x = args_solar_anomaly[i];
1880 y = args_lunar_anomaly[i];
1881 z = args_moon_node[i];
1882 x2 = x;
1883 x2.abs();
1884 x3 = cap_E;
1885 x3 ^= x2;
1886 v *= x3;
1887 w *= cap_D;
1888 x *= cap_M;
1889 y *= cap_M_prime;
1890 z *= cap_F;
1891 w += x; w += y; w += z;
1892 w *= nr_pi;
1893 w /= 180;
1894 w.sin();
1895 v *= w;
1896 correction += v;
1897 }
1898 correction *= Number(1, 1, -6);
1899 Number venus; venus.setFloat(131.849L); venus *= c; v.setFloat(119.75L); venus += v; venus *= nr_pi; venus /= 180; venus.sin(); venus *= Number(3958, 1000000L);
1900 Number jupiter; jupiter.setFloat(479264.29L); jupiter *= c; v.setFloat(53.09L); jupiter += v; jupiter *= nr_pi; jupiter /= 180; jupiter.sin(); jupiter *= Number(318, 1000000L);
1901 Number flat_earth(cap_L_prime); flat_earth -= cap_F; flat_earth *= nr_pi; flat_earth /= 180; flat_earth.sin(); flat_earth *= Number(1962, 1000000L);
1902 Number ret(cap_L_prime); ret += correction; ret += venus; ret += jupiter; ret += flat_earth; ret += nutation(tee); ret.mod(360);
1903 return ret;
1904 }
1905
nth_new_moon(Number n)1906 Number nth_new_moon(Number n) {
1907 Number n0(24724);
1908 Number k(n); k -= n0;
1909 Number c; c.setFloat(1236.85L); c.recip(); c *= k;
1910 Number approx = J2000; approx += cal_poly(c, 5, 5.09766L, 29.530588861L * 1236.85L, 0.00015437L, -0.000000150L, 0.00000000073L);
1911 Number cap_E = cal_poly(c, 3, 1.0L, -0.002516L, -0.0000074L);
1912 Number solar_anomaly_n = cal_poly(c, 4, 2.5534L, 1236.85L * 29.10535670L, -0.0000014L, -0.00000011L);
1913 Number lunar_anomaly_n = cal_poly(c, 5, 201.5643L, 385.81693528L * 1236.85L, 0.0107582L, 0.00001238L, -0.000000058L);
1914 Number moon_argument = cal_poly(c, 5, 160.7108L, 390.67050284L * 1236.85L, -0.0016118L, -0.00000227L, 0.000000011L);
1915 Number cap_omega = cal_poly(c, 4, 124.7746L, -1.56375588L * 1236.85L, 0.0020672L, 0.00000215L);
1916 int e_factor[] = {0, 1, 0, 0, 1, 1, 2, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1};
1917 int solar_coeff[] = {0, 1, 0, 0, -1, 1, 2, 0, 0, 1, 0, 1, 1, -1, 2, 0, 3, 1, 0, 1, -1, -1, 1, 0};
1918 int lunar_coeff[] = {1, 0, 2, 0, 1, 1, 0, 1, 1, 2, 3, 0, 0, 2, 1, 2, 0, 1, 2, 1, 1, 1, 3, 4};
1919 int moon_coeff[] = {0, 0, 0, 2, 0, 0, 0, -2, 2, 0, 0, 2, -2, 0, 0, -2, 0, -2, 2, 2, 2, -2, 0, 0};
1920 long double sine_coeff[] = { -0.40720L, 0.17241L, 0.01608L, 0.01039L, 0.00739L, -0.00514L, 0.00208L, -0.00111L, -0.00057L, 0.00056L, -0.00042L, 0.00042L, 0.00038L, -0.00024L, -0.00007L, 0.00004L, 0.00004L, 0.00003L, 0.00003L, -0.00003L, 0.00003L, -0.00002L, -0.00002L, 0.00002L};
1921 Number v, w, x, x2, y, z, nr_pi; nr_pi.pi();
1922 Number correction; correction.setFloat(-0.00017L); cap_omega *= nr_pi; cap_omega /= 180; cap_omega.sin(); correction *= cap_omega;
1923 for(size_t i = 0; e_factor[i] >= 0; i++) {
1924 v.setFloat(sine_coeff[i]);
1925 w = e_factor[i];
1926 x = solar_coeff[i];
1927 y = lunar_coeff[i];
1928 z = moon_coeff[i];
1929 x *= solar_anomaly_n;
1930 y *= lunar_anomaly_n;
1931 z *= moon_argument;
1932 x += y; x += z;
1933 x *= nr_pi;
1934 x /= 180;
1935 x.sin();
1936 x2 = cap_E; x2 ^= w;
1937 v *= x2; v *= x;
1938 correction += v;
1939 }
1940 long double add_const[] = {251.88L, 251.83L, 349.42L, 84.66L, 141.74L, 207.14L, 154.84L, 34.52L, 207.19L, 291.34L, 161.72L, 239.56L, 331.55L, -1.0L};
1941 long double add_coeff[] = {0.016321L, 26.651886L, 36.412478L, 18.206239L, 53.303771L, 2.453732L, 7.306860L, 27.261239L, 0.121824L, 1.844379L, 24.198154L, 25.513099L, 3.592518L};
1942 long double add_factor[] = {0.000165L, 0.000164L, 0.000126L, 0.000110L, 0.000062L, 0.000060L, 0.000056L, 0.000047L, 0.000042L, 0.000040L, 0.000037L, 0.000035L, 0.000023L};
1943 Number extra = cal_poly(c, 3, 299.77L, 132.8475848L, -0.009173L); extra *= nr_pi; extra /= 180; extra.sin(); v.setFloat(0.000325L); extra *= v;
1944 Number additional;
1945 for(size_t i = 0; add_const[i] >= 0; i++) {
1946 x.setFloat(add_const[i]);
1947 y.setFloat(add_coeff[i]);
1948 z.setFloat(add_factor[i]);
1949 y *= k; y += x; y *= nr_pi; y /= 180; y.sin(); y *= z;
1950 additional += y;
1951 }
1952 approx += correction; approx += extra; approx += additional;
1953 return universal_from_dynamical(approx);
1954 }
1955
lunar_phase(Number tee)1956 Number lunar_phase(Number tee) {
1957 Number phi = lunar_longitude(tee); phi -= solar_longitude(tee); phi.mod(360);
1958 Number t0 = nth_new_moon(0);
1959 Number n(tee); n -= t0; n /= MEAN_SYNODIC_MONTH; n.round();
1960 Number phi_prime(tee); phi_prime -= nth_new_moon(n); phi_prime /= MEAN_SYNODIC_MONTH; phi_prime.mod(1); phi_prime *= 360;
1961 Number test(phi); test -= phi_prime; test.abs();
1962 if(test > 180) return phi_prime;
1963 return phi;
1964 }
1965
lunar_phase_at_or_after(Number phase,Number tee)1966 Number lunar_phase_at_or_after(Number phase, Number tee) {
1967 Number rate = MEAN_SYNODIC_MONTH; rate /= 360;
1968 Number tau(phase); tau -= lunar_phase(tee); tau.mod(360); tau *= rate; tau += tee;
1969 Number a(tau); a -= 5; if(tee > a) a = tee;
1970 Number b(tau); b += 5;
1971 Number precexp(1, 1, -5);
1972 Number phase_low(phase); phase_low -= precexp;
1973 Number phase_high(phase); phase_high += precexp;
1974 if(phase_low < 0) phase_low += 360;
1975 if(phase_high > 360) phase_high -= 360;
1976 Number newphase;
1977 Number test(a);
1978 while(true) {
1979 if(CALCULATOR->aborted()) return nr_zero;
1980 test = b; test -= a; test /= 2; test += a;
1981 newphase = lunar_phase(test);
1982 if(phase_high < phase_low) {
1983 if(newphase >= phase_low || newphase <= phase_high) return test;
1984 } else {
1985 if(newphase >= phase_low && newphase <= phase_high) return test;
1986 }
1987 newphase -= phase; newphase.mod(360);
1988 if(newphase < 180) b = test;
1989 else a = test;
1990 }
1991 }
1992
new_moon_at_or_after(Number tee)1993 Number new_moon_at_or_after(Number tee) {
1994 Number t0 = nth_new_moon(0);
1995 Number phi = lunar_phase(tee); phi /= 360;
1996 Number n(tee); n -= t0; n /= MEAN_SYNODIC_MONTH; n -= phi; n.round();
1997 while(nth_new_moon(n) < tee) {
1998 if(CALCULATOR->aborted()) break;
1999 n++;
2000 }
2001 return nth_new_moon(n);
2002 }
new_moon_before(Number tee)2003 Number new_moon_before(Number tee) {
2004 Number t0 = nth_new_moon(0);
2005 Number phi = lunar_phase(tee); phi /= 360;
2006 Number n(tee); n -= t0; n /= MEAN_SYNODIC_MONTH; n -= phi; n.round();
2007 n--;
2008 while(nth_new_moon(n) < tee) {
2009 if(CALCULATOR->aborted()) break;
2010 n++;
2011 }
2012 n--;
2013 return nth_new_moon(n);
2014 }
2015
chinese_new_moon_on_or_after(Number date)2016 Number chinese_new_moon_on_or_after(Number date) {
2017 Number tee = new_moon_at_or_after(midnight_in_china(date));
2018 Number ret = standard_from_universal(tee, chinese_zone(tee));
2019 ret.floor();
2020 return ret;
2021 }
chinese_new_moon_before(Number date)2022 Number chinese_new_moon_before(Number date) {
2023 Number tee = new_moon_before(midnight_in_china(date));
2024 Number ret = standard_from_universal(tee, chinese_zone(tee));
2025 ret.floor();
2026 return ret;
2027 }
chinese_solar_longitude_on_or_after(Number lam,Number tee)2028 Number chinese_solar_longitude_on_or_after(Number lam, Number tee) {
2029 Number sun = solar_longitude_after(lam, universal_from_standard(tee, chinese_zone(tee)));
2030 return standard_from_universal(sun, chinese_zone(sun));
2031 }
current_major_solar_term(Number date)2032 Number current_major_solar_term(Number date) {
2033 Number s = solar_longitude(universal_from_standard(date, chinese_zone(date)));
2034 cal_div(s, 30); s += 2; s.mod(-12); s += 12;
2035 return s;
2036 }
major_solar_term_on_or_after(Number date)2037 Number major_solar_term_on_or_after(Number date) {
2038 Number s = solar_longitude(midnight_in_china(date));
2039 Number l(s); l /= 30; l.ceil(); l *= 30; l.mod(360);
2040 return chinese_solar_longitude_on_or_after(l, date);
2041 }
current_minor_solar_term(Number date)2042 Number current_minor_solar_term(Number date) {
2043 Number s = solar_longitude(universal_from_standard(date, chinese_zone(date)));
2044 s -= 15; cal_div(s, 30); s += 3; s.mod(-12); s += 12;
2045 return s;
2046 }
minor_solar_term_on_or_after(Number date)2047 Number minor_solar_term_on_or_after(Number date) {
2048 Number s = solar_longitude(midnight_in_china(date));
2049 Number l(s); l -= 15; l /= 30; l.ceil(); l *= 30; l += 15; l.mod(360);
2050 return chinese_solar_longitude_on_or_after(l, date);
2051 }
chinese_no_major_solar_term(Number date)2052 bool chinese_no_major_solar_term(Number date) {
2053 return current_major_solar_term(date) == current_major_solar_term(chinese_new_moon_on_or_after(date + 1));
2054 }
chinese_prior_leap_month(Number m_prime,Number m)2055 bool chinese_prior_leap_month(Number m_prime, Number m) {
2056 if(CALCULATOR->aborted()) return false;
2057 return m >= m_prime && (chinese_no_major_solar_term(m) || chinese_prior_leap_month(m_prime, chinese_new_moon_before(m)));
2058 }
chinese_winter_solstice_on_or_before(Number date)2059 Number chinese_winter_solstice_on_or_before(Number date) {
2060 date++;
2061 Number approx = estimate_prior_solar_longitude(270, midnight_in_china(date));
2062 approx.floor(); approx--;
2063 while(solar_longitude(midnight_in_china(approx + 1)) <= 270) {
2064 if(CALCULATOR->aborted()) break;
2065 approx++;
2066 }
2067 return approx;
2068 }
chinese_new_year_in_sui(Number date)2069 Number chinese_new_year_in_sui(Number date) {
2070 Number s1 = chinese_winter_solstice_on_or_before(date);
2071 Number s2 = chinese_winter_solstice_on_or_before(s1 + 370);
2072 Number m12 = chinese_new_moon_on_or_after(s1 + 1);
2073 Number m13 = chinese_new_moon_on_or_after(m12 + 1);
2074 Number next_m11 = chinese_new_moon_before(s2 + 1);
2075 next_m11 -= m12; next_m11 /= MEAN_SYNODIC_MONTH; next_m11.round();
2076 if(next_m11 == 12 && (chinese_no_major_solar_term(m12) || chinese_no_major_solar_term(m13))) {
2077 m13++;
2078 return chinese_new_moon_on_or_after(m13);
2079 }
2080 return m13;
2081 }
chinese_new_year_on_or_before(Number date)2082 Number chinese_new_year_on_or_before(Number date) {
2083 Number new_year = chinese_new_year_in_sui(date);
2084 if(date >= new_year) return new_year;
2085 date -= 180;
2086 return chinese_new_year_in_sui(date);
2087 }
2088
gregorian_leap_year(long int year)2089 bool gregorian_leap_year(long int year) {
2090 return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
2091 }
julian_leap_year(long int year)2092 bool julian_leap_year(long int year) {
2093 if(year < 0) return year % 4 == -1;
2094 return year % 4 == 0;
2095 }
coptic_leap_year(long int year)2096 bool coptic_leap_year(long int year) {
2097 if(year < 0) return year % 4 == -1;
2098 return year % 4 == 2;
2099 }
hebrew_leap_year(Number y)2100 bool hebrew_leap_year(Number y) {
2101 y *= 7; y++; y.mod(19);
2102 return y.isLessThan(7);
2103 }
last_month_of_hebrew_year(Number year)2104 long int last_month_of_hebrew_year(Number year) {
2105 if(hebrew_leap_year(year)) return 13;
2106 return 12;
2107 }
hebrew_sabbatical_year(Number year)2108 bool hebrew_sabbatical_year(Number year) {
2109 year.mod(7);
2110 return year.isZero();
2111 }
hebrew_calendar_elapsed_days(Number year)2112 Number hebrew_calendar_elapsed_days(Number year) {
2113 Number months_elapsed(year); months_elapsed *= 235; months_elapsed -= 234; cal_div(months_elapsed, 19);
2114 Number parts_elapsed(months_elapsed); parts_elapsed *= 13753; parts_elapsed += 12084;
2115 months_elapsed *= 29;
2116 cal_div(parts_elapsed, 25920);
2117 Number days(months_elapsed); days += parts_elapsed;
2118 Number days2(days); days2++; days2 *= 3; days2.mod(7);
2119 if(days2.isLessThan(3)) days++;
2120 return days;
2121 }
hebrew_year_length_correction(Number year)2122 long int hebrew_year_length_correction(Number year) {
2123 Number ny0, ny1, ny2;
2124 year--;
2125 ny0 = hebrew_calendar_elapsed_days(year);
2126 year++;
2127 ny1 = hebrew_calendar_elapsed_days(year);
2128 year++;
2129 ny2 = hebrew_calendar_elapsed_days(year);
2130 ny2 -= ny1;
2131 if(ny2 == 356) return 2;
2132 ny1 -= ny0;
2133 if(ny1 == 382) return 1;
2134 return 0;
2135 }
hebrew_new_year(Number year)2136 Number hebrew_new_year(Number year) {
2137 Number d(HEBREW_EPOCH); d += hebrew_calendar_elapsed_days(year); d += hebrew_year_length_correction(year); return d;
2138 }
2139
days_in_hebrew_year(Number year)2140 long int days_in_hebrew_year(Number year) {
2141 Number d1(hebrew_new_year(year));
2142 d1.negate();
2143 year++;
2144 d1 += hebrew_new_year(year);
2145 return d1.lintValue();
2146 }
long_marheshvan(Number year)2147 bool long_marheshvan(Number year) {
2148 long int d = days_in_hebrew_year(year);
2149 return d == 355 || d == 385;
2150 }
short_kislev(Number year)2151 bool short_kislev(Number year) {
2152 long int d = days_in_hebrew_year(year);
2153 return d == 353 || d == 383;
2154 }
2155
last_day_of_hebrew_month(Number year,Number month)2156 long int last_day_of_hebrew_month(Number year, Number month) {
2157 if(month == 2 || month == 4 || month == 6 || month == 10 || month == 13) return 29;
2158 if(month == 12 && !hebrew_leap_year(year)) return 29;
2159 if(month == 8 && !long_marheshvan(year)) return 29;
2160 if(month == 9 && short_kislev(year)) return 29;
2161 return 30;
2162 }
2163
date_to_fixed(long int y,long int m,long int d,CalendarSystem ct)2164 Number date_to_fixed(long int y, long int m, long int d, CalendarSystem ct) {
2165 Number fixed;
2166 if(ct == CALENDAR_GREGORIAN) {
2167 Number year(y); year--;
2168 fixed = year; fixed *= 365; fixed += quotient(year, 4); fixed -= quotient(year, 100); fixed += quotient(year, 400);
2169 fixed += quotient((367 * m) - 362, 12);
2170 if(m > 2) fixed -= (gregorian_leap_year(y) ? 1 : 2);
2171 fixed += d;
2172 } else if(ct == CALENDAR_HEBREW) {
2173 fixed = hebrew_new_year(y);
2174 fixed += d - 1;
2175 if(m < 7) {
2176 long int l = last_month_of_hebrew_year(y);
2177 for(long int i = 7; i <= l; i++) fixed += last_day_of_hebrew_month(y, i);
2178 for(long int i = 1; i < m; i++) fixed += last_day_of_hebrew_month(y, i);
2179 } else {
2180 for(long int i = 7; i < m; i++) fixed += last_day_of_hebrew_month(y, i);
2181 }
2182 } else if(ct == CALENDAR_JULIAN) {
2183 Number y2(y); if(!y2.isNegative()) y2--;
2184 fixed = JULIAN_EPOCH; fixed--;
2185 fixed += y2 * 365;
2186 fixed += quotient(y2, 4);
2187 fixed += quotient((367 * m) - 362, 12);
2188 if(m > 2) fixed -= (julian_leap_year(y) ? 1 : 2);
2189 fixed += d;
2190 } else if(ct == CALENDAR_ISLAMIC) {
2191 Number year(y);
2192 fixed = ISLAMIC_EPOCH; fixed--;
2193 fixed += (year - 1) * 354;
2194 year *= 11; year += 3; cal_div(year, 30); fixed += year;
2195 fixed += (m - 1) * 29;
2196 fixed += quotient(m, 2);
2197 fixed += d;
2198 } else if(ct == CALENDAR_PERSIAN) {
2199 Number year(y);
2200 if(year.isPositive()) year--;
2201 year *= MEAN_TROPICAL_YEAR;
2202 year.floor();
2203 year += 180;
2204 year += PERSIAN_EPOCH;
2205 fixed = persian_new_year_on_or_before(year); fixed--;
2206 if(m <= 7) fixed += 31 * (m - 1);
2207 else fixed += (30 * (m - 1)) + 6;
2208 fixed += d;
2209 } else if(ct == CALENDAR_CHINESE) {
2210 bool leap = (m > 12);
2211 if(leap) m -= 12;
2212 Number mid_year(y); mid_year -= 61; mid_year += nr_half; mid_year *= MEAN_TROPICAL_YEAR; mid_year += CHINESE_EPOCH;
2213 Number new_year = chinese_new_year_on_or_before(mid_year);
2214 new_year += (m - 1) * 29;
2215 Number p = chinese_new_moon_on_or_after(new_year);
2216 long int dy, dm, dd;
2217 fixed_to_date(p, dy, dm, dd, ct);
2218 bool dleap = (dm > 12); if(dleap) dm -= 12;
2219 if(m != dm || leap != dleap) {p++; p = chinese_new_moon_on_or_after(p);}
2220 fixed = d; fixed--; fixed += p;
2221 } else if(ct == CALENDAR_EGYPTIAN) {
2222 Number year(y);
2223 fixed = EGYPTIAN_EPOCH;
2224 fixed += (year - 1) * 365;
2225 fixed += 30 * (m - 1);
2226 fixed += d - 1;
2227 } else if(ct == CALENDAR_COPTIC) {
2228 Number year(y);
2229 fixed = COPTIC_EPOCH; fixed--;
2230 fixed += (year - 1) * 365;
2231 fixed += quotient(year, 4);
2232 fixed += 30 * (m - 1);
2233 fixed += d;
2234 } else if(ct == CALENDAR_ETHIOPIAN) {
2235 Number year(y);
2236 fixed = ETHIOPIAN_EPOCH;
2237 fixed += date_to_fixed(y, m, d, CALENDAR_COPTIC);
2238 fixed -= COPTIC_EPOCH;
2239 } else {
2240 return date_to_cjdn(y, m, d, ct) - 1721425L;
2241 }
2242 return fixed;
2243 }
2244
fixed_to_date(Number date,long int & y,long int & m,long int & d,CalendarSystem ct)2245 bool fixed_to_date(Number date, long int &y, long int &m, long int &d, CalendarSystem ct) {
2246 if(ct == CALENDAR_GREGORIAN) {
2247 Number d0, n400, d1, n100, d2, n4, d3, n1, year;
2248 d0 = date; d0 -= 1;
2249 cal_div(d0, 146097, n400, d1);
2250 cal_div(d1, 36524, n100, d2);
2251 cal_div(d2, 1461, n4, d3);
2252 cal_div(d3, 365, n1);
2253 if(!n100.equals(4) && !n1.equals(4)) year = 1;
2254 else year = 0;
2255 n400 *= 400; n100 *= 100; n4 *= 4; year += n400; year += n100; year += n4; year += n1;
2256 bool overflow = false;
2257 y = year.lintValue(&overflow);
2258 if(overflow) return false;
2259 Number prior_days(date); prior_days -= date_to_fixed(y, 1, 1, ct);
2260 if(date.isGreaterThanOrEqualTo(date_to_fixed(y, 3, 1, ct))) prior_days += gregorian_leap_year(y) ? 1 : 2;
2261 prior_days *= 12; prior_days += 373;
2262 cal_div(prior_days, 367);
2263 m = prior_days.lintValue();
2264 date -= date_to_fixed(y, m, 1, ct); date++;
2265 d = date.lintValue();
2266 return true;
2267 } else if(ct == CALENDAR_HEBREW) {
2268 Number approx(date); approx -= HEBREW_EPOCH; approx /= 35975351L; approx *= 98496; approx.floor(); approx++;
2269 Number year(approx); year--;
2270 while(hebrew_new_year(year).isLessThanOrEqualTo(date)) {
2271 if(CALCULATOR->aborted()) return false;
2272 year++;
2273 }
2274 year--;
2275 bool overflow = false;
2276 y = year.lintValue(&overflow);
2277 if(overflow) return false;
2278 m = 1;
2279 if(date.isLessThan(date_to_fixed(y, 1, 1, ct))) m = 7;
2280 while(date.isGreaterThan(date_to_fixed(y, m, last_day_of_hebrew_month(y, m), ct))) {
2281 if(CALCULATOR->aborted()) return false;
2282 m++;
2283 }
2284 date -= date_to_fixed(y, m, 1, ct); date++;
2285 d = date.lintValue();
2286 return true;
2287 } else if(ct == CALENDAR_JULIAN) {
2288 Number approx(date); approx -= JULIAN_EPOCH; approx *= 4; approx += 1464; cal_div(approx, 1461);
2289 if(!approx.isPositive()) approx--;
2290 bool overflow = false;
2291 y = approx.lintValue(&overflow);
2292 if(overflow) return false;
2293 Number prior_days(date); prior_days -= date_to_fixed(y, 1, 1, ct);
2294 if(date.isGreaterThanOrEqualTo(date_to_fixed(y, 3, 1, ct))) prior_days += julian_leap_year(y) ? 1 : 2;
2295 prior_days *= 12; prior_days += 373;
2296 cal_div(prior_days, 367);
2297 m = prior_days.lintValue();
2298 date -= date_to_fixed(y, m, 1, ct); date++;
2299 d = date.lintValue();
2300 return true;
2301 } else if(ct == CALENDAR_ISLAMIC) {
2302 Number year(date); year -= ISLAMIC_EPOCH; year *= 30; year += 10646; cal_div(year, 10631);
2303 bool overflow = false;
2304 y = year.lintValue(&overflow);
2305 if(overflow) return false;
2306 Number prior_days(date); prior_days -= date_to_fixed(y, 1, 1, ct);
2307 prior_days *= 11; prior_days += 330; cal_div(prior_days, 325);
2308 m = prior_days.lintValue();
2309 date -= date_to_fixed(y, m, 1, ct); date++;
2310 d = date.lintValue();
2311 return true;
2312 } else if(ct == CALENDAR_PERSIAN) {
2313 Number new_year = persian_new_year_on_or_before(date);
2314 Number y2 = new_year; y2 -= PERSIAN_EPOCH; y2 /= MEAN_TROPICAL_YEAR; y2.round(); y2++;
2315 Number year = y2;
2316 if(y2.isNonPositive()) year--;
2317 bool overflow = false;
2318 y = year.lintValue(&overflow);
2319 if(overflow) return false;
2320 Number day_of_year(date); day_of_year -= date_to_fixed(y, 1, 1, CALENDAR_PERSIAN); day_of_year++;
2321 Number month = day_of_year;
2322 if(day_of_year <= 186) {month /= 31; month.ceil();}
2323 else {month -= 6; month /= 30; month.ceil();}
2324 m = month.lintValue();
2325 date++; date -= date_to_fixed(y, m, 1, CALENDAR_PERSIAN);
2326 d = date.lintValue();
2327 return true;
2328 } else if(ct == CALENDAR_CHINESE) {
2329 if(date > Number(1, 1, 8) || date < Number(-1, 1, 8)) return false;
2330 Number s1 = chinese_winter_solstice_on_or_before(date);
2331 Number s2 = chinese_winter_solstice_on_or_before(s1 + 370);
2332 Number m12 = chinese_new_moon_on_or_after(s1 + 1);
2333 Number next_m11 = chinese_new_moon_before(s2 + 1);
2334 Number m1 = chinese_new_moon_before(date + 1);
2335 Number test(next_m11); test -= m12; test /= MEAN_SYNODIC_MONTH; test.round();
2336 bool leap_year = (test == 12);
2337 Number month(m1); month -= m12; month /= MEAN_SYNODIC_MONTH; month.round();
2338 if(leap_year && chinese_prior_leap_month(m12, m1)) month--;
2339 month.mod(-12); month += 12;
2340 m = month.lintValue();
2341 bool leap_month = (leap_year && chinese_no_major_solar_term(m1) && !chinese_prior_leap_month(m12, chinese_new_moon_before(m1)));
2342 if(leap_month) m += 12;
2343 Number elapsed_years(date); elapsed_years -= CHINESE_EPOCH; elapsed_years /= MEAN_TROPICAL_YEAR; elapsed_years += Number(3, 2); month /= 12; elapsed_years -= month; elapsed_years.floor();
2344 elapsed_years += 60; //epoch of 2697 BCE
2345 Number day(date); day -= m1; day++;
2346 if(day <= 0) return false;
2347 d = day.lintValue();
2348 bool overflow = false;
2349 y = elapsed_years.lintValue(&overflow);
2350 if(overflow) return false;
2351 return true;
2352 } else if(ct == CALENDAR_EGYPTIAN) {
2353 date -= EGYPTIAN_EPOCH;
2354 Number year(date); cal_div(year, 365); year++;
2355 bool overflow = false;
2356 y = year.lintValue(&overflow);
2357 if(overflow) return false;
2358 Number month(date); month.mod(365); cal_div(month, 30); month++;
2359 m = month.lintValue();
2360 year--; year *= 365; month--; month *= 30; date -= year; date -= month; date++;
2361 d = date.lintValue();
2362 return true;
2363 } else if(ct == CALENDAR_COPTIC) {
2364 Number year(date); year -= COPTIC_EPOCH; year *= 4; year += 1463; cal_div(year, 1461);
2365 bool overflow = false;
2366 y = year.lintValue(&overflow);
2367 if(overflow) return false;
2368 Number month(date); month -= date_to_fixed(y, 1, 1, ct); cal_div(month, 30); month++;
2369 m = month.lintValue();
2370 Number day(date); day -= date_to_fixed(y, m, 1, ct); day++;
2371 d = day.lintValue();
2372 return true;
2373 } else if(ct == CALENDAR_ETHIOPIAN) {
2374 date -= ETHIOPIAN_EPOCH;
2375 date += COPTIC_EPOCH;
2376 return fixed_to_date(date, y, m, d, CALENDAR_COPTIC);
2377 } else if(ct == CALENDAR_MILANKOVIC || ct == CALENDAR_INDIAN) {
2378 date += 1721425L;
2379 return cjdn_to_date(date, y, m, d, ct);
2380 }
2381 return false;
2382 }
date_to_cjdn(long int j,long int m,long int d,CalendarSystem ct)2383 Number date_to_cjdn(long int j, long int m, long int d, CalendarSystem ct) {
2384 Number J;
2385 if(ct == CALENDAR_GREGORIAN) {
2386 Number c0(m); c0 -= 3; c0 /= 12; c0.floor();
2387 Number x4(j); x4 += c0;
2388 Number x2, x3; cal_div(x4, 100, x3, x2);
2389 Number x1(m); c0 *= 12; x1 -= c0; x1 -= 3;
2390 x3 *= 146097; x3 /= 4; x3.floor();
2391 x2 *= 36525; x2 /= 100; x2.floor();
2392 x1 *= 153; x1 += 2; x1 /= 5; x1.floor();
2393 J = x3; J += x2; J += x1; J += d; J += 1721119;
2394 } else if(ct == CALENDAR_MILANKOVIC) {
2395 Number c0(m); c0 -= 3; c0 /= 12; c0.floor();
2396 Number x4(j); x4 += c0;
2397 Number x2, x3; cal_div(x4, 100, x3, x2);
2398 Number x1(m); c0 *= 12; x1 -= c0; x1 -= 3;
2399 x3 *= 328718; x3 += 6; x3 /= 9; x3.floor();
2400 x2 *= 36525; x2 /= 100; x2.floor();
2401 x1 *= 153; x1 += 2; x1 /= 5; x1.floor();
2402 J = x3; J += x2; J += x1; J += d; J += 1721119;
2403 } else if(ct == CALENDAR_JULIAN) {
2404 Number c0(m); c0 -= 3; c0 /= 12; c0.floor();
2405 Number j1(j); j1 += c0; j1 *= 1461; j1 /= 4; j1.floor();
2406 Number j2(m); j2 *= 153; c0 *= 1836; j2 -= c0; j2 -= 457; j2 /= 5; j2.floor();
2407 J = 1721117L; J += j1; J += j2; J += d;
2408 } else if(ct == CALENDAR_ISLAMIC) {
2409 Number x1(j); x1 *= 10631; x1 -= 10617; x1 /= 30; x1.floor();
2410 Number x2(m); x2 *= 325; x2 -= 320; x2 /= 11; x2.floor();
2411 J = x1; J += x2; J += d; J += 1948439L;
2412 return J;
2413 } else if(ct == CALENDAR_HEBREW) {
2414 Number c0, x1, x3, z4;
2415 c0 = 13; c0 -= m; c0 /= 7; c0.floor();
2416 x1 = j; x1--; x1 += c0;
2417 x3 = m; x3--;
2418 z4 = d; z4--;
2419 Number c1x1, qx1, rx1, v1x1, v2x1;
2420 c1x1 = x1; c1x1 *= 235; c1x1++; c1x1 /= 19; c1x1.floor();
2421 qx1 = c1x1; qx1 /= 1095; qx1.floor();
2422 rx1 = c1x1; rx1.mod(1095);
2423 v1x1 = qx1; v1x1 *= 15; rx1 *= 765433L; v1x1 += rx1; v1x1 += 12084; v1x1 /= 25920; v1x1.floor(); qx1 *= 32336; v1x1 += qx1;
2424 v2x1 = v1x1; v2x1.mod(7); v2x1 *= 6; v2x1 /= 7; v2x1.floor(); v2x1.mod(2); v2x1 += v1x1;
2425 Number x1p1, c1x1p1, qx1p1, rx1p1, v1x1p1, v2x1p1;
2426 x1p1 = x1; x1p1++;
2427 c1x1p1 = x1p1; c1x1p1 *= 235; c1x1p1++; c1x1p1 /= 19; c1x1p1.floor();
2428 qx1p1 = c1x1p1; qx1p1 /= 1095; qx1p1.floor();
2429 rx1p1 = c1x1p1; rx1p1.mod(1095);
2430 v1x1p1 = qx1p1; v1x1p1 *= 15; rx1p1 *= 765433L; v1x1p1 += rx1p1; v1x1p1 += 12084; v1x1p1 /= 25920; v1x1p1.floor(); qx1p1 *= 32336; v1x1p1 += qx1p1;
2431 v2x1p1 = v1x1p1; v2x1p1.mod(7); v2x1p1 *= 6; v2x1p1 /= 7; v2x1p1.floor(); v2x1p1.mod(2); v2x1p1 += v1x1p1;
2432 Number x1m1, c1x1m1, qx1m1, rx1m1, v1x1m1, v2x1m1;
2433 x1m1 = x1; x1m1--;
2434 c1x1m1 = x1m1; c1x1m1 *= 235; c1x1m1++; c1x1m1 /= 19; c1x1m1.floor();
2435 qx1m1 = c1x1m1; qx1m1 /= 1095; qx1m1.floor();
2436 rx1m1 = c1x1m1; rx1m1.mod(1095);
2437 v1x1m1 = qx1m1; v1x1m1 *= 15; rx1m1 *= 765433L; v1x1m1 += rx1m1; v1x1m1 += 12084; v1x1m1 /= 25920; v1x1m1.floor(); qx1m1 *= 32336; v1x1m1 += qx1m1;
2438 v2x1m1 = v1x1m1; v2x1m1.mod(7); v2x1m1 *= 6; v2x1m1 /= 7; v2x1m1.floor(); v2x1m1.mod(2); v2x1m1 += v1x1m1;
2439 Number x1p2, c1x1p2, qx1p2, rx1p2, v1x1p2, v2x1p2;
2440 x1p2 = x1; x1p2 += 2;
2441 c1x1p2 = x1p2; c1x1p2 *= 235; c1x1p2++; c1x1p2 /= 19; c1x1p2.floor();
2442 qx1p2 = c1x1p2; qx1p2 /= 1095; qx1p2.floor();
2443 rx1p2 = c1x1p2; rx1p2.mod(1095);
2444 v1x1p2 = qx1p2; v1x1p2 *= 15; rx1p2 *= 765433L; v1x1p2 += rx1p2; v1x1p2 += 12084; v1x1p2 /= 25920; v1x1p2.floor(); qx1p2 *= 32336; v1x1p2 += qx1p2;
2445 v2x1p2 = v1x1p2; v2x1p2.mod(7); v2x1p2 *= 6; v2x1p2 /= 7; v2x1p2.floor(); v2x1p2.mod(2); v2x1p2 += v1x1p2;
2446 Number L2x1, L2x1m1, v3x1, v4x1, c2x1;
2447 L2x1 = v2x1p1; L2x1 -= v2x1;
2448 L2x1m1 = v2x1; L2x1m1 -= v2x1m1;
2449 v3x1 = L2x1; v3x1 += 19; v3x1 /= 15; v3x1.floor(); v3x1.mod(2); v3x1 *= 2;
2450 v4x1 = L2x1m1; v4x1 += 7; v4x1 /= 15; v4x1.floor(); v4x1.mod(2);
2451 c2x1 = v2x1; c2x1 += v3x1; c2x1 += v4x1;
2452 Number L2x1p1, v3x1p1, v4x1p1, c2x1p1;
2453 L2x1p1 = v2x1p2; L2x1p1 -= v2x1p1;
2454 v3x1p1 = L2x1p1; v3x1p1 += 19; v3x1p1 /= 15; v3x1p1.floor(); v3x1p1.mod(2); v3x1p1 *= 2;
2455 v4x1p1 = L2x1; v4x1p1 += 7; v4x1p1 /= 15; v4x1p1.floor(); v4x1p1.mod(2);
2456 c2x1p1 = v2x1p1; c2x1p1 += v3x1p1; c2x1p1 += v4x1p1;
2457 Number L, c8, c9, c3, c4;
2458 L = c2x1p1; L -= c2x1;
2459 c8 = L; c8 += 7; c8 /= 2; c8.floor(); c8.mod(15);
2460 c9 = 385; c9 -= L; c9 /= 2; c9.floor(); c9.mod(15); c9.negate();
2461 Number x3a(x3), x3b(x3), x3c(x3);
2462 x3a *= 384; x3a += 7; x3a /= 13; x3a.floor(); x3b += 4; x3b /= 12; x3b.floor(); x3c += 3; x3c /= 12; x3c.floor();
2463 c3 = x3a; c8 *= x3b; c3 += c8; c9 *= x3c; c3 += c9;
2464 J = 347821L; J += c2x1; J += c3; J += z4;
2465 } else if(ct == CALENDAR_EGYPTIAN) {
2466 j *= 365; m *= 30;
2467 J = j; J += m; J += d; J+= 1448242L;
2468 } else if(ct == CALENDAR_INDIAN) {
2469 j += 78;
2470 bool leap = gregorian_leap_year(j);
2471 J = date_to_cjdn(j, 3, leap ? 21 : 22, CALENDAR_GREGORIAN);
2472 if(m != 1) {
2473 J += leap ? 31 : 30;
2474 long int m2 = m - 2;
2475 if(m2 > 5) m2 = 5;
2476 J += m2 * 31;
2477 if(m >= 8) J += (m - 7) * 30;
2478 }
2479 J += d;
2480 J--;
2481 } else {
2482 return date_to_fixed(j, m, d, ct) + 1721425L;
2483 }
2484 return J;
2485 }
cjdn_to_date(Number J,long int & y,long int & m,long int & d,CalendarSystem ct)2486 bool cjdn_to_date(Number J, long int &y, long int &m, long int &d, CalendarSystem ct) {
2487 if(ct == CALENDAR_GREGORIAN) {
2488 Number x3, r3, x2, r2, x1, r1, j;
2489 J *= 4; J -= 6884477L;
2490 cal_div(J, 146097, x3, r3);
2491 r3 /= 4; r3.floor(); r3 *= 100; r3 += 99;
2492 cal_div(r3, 36525, x2, r2);
2493 r2 /= 100; r2.floor(); r2 *= 5; r2 += 2;
2494 cal_div(r2, 153, x1, r1);
2495 r1 /= 5; r1.floor(); r1++; d = r1.lintValue();
2496 Number c0(x1); c0 += 2; c0 /= 12; c0.floor();
2497 j = x3; j *= 100; j += x2; j += c0;
2498 bool overflow = false; y = j.lintValue(&overflow); if(overflow) return false;
2499 c0 *= -12; c0 += x1; c0 += 3; m = c0.lintValue();
2500 return true;
2501 } else if(ct == CALENDAR_MILANKOVIC) {
2502 Number x3, r3, x2, r2, x1, r1, c0, j;
2503 J -= 1721120L; J *= 9; J += 2;
2504 cal_div(J, 328718L, x3, r3);
2505 r3 /= 9; r3.floor(); r3 *= 100; r3 += 99;
2506 cal_div(r3, 36525, x2, r2);
2507 r2 /= 100; r2.floor(); r2 *= 5; r2 += 2;
2508 cal_div(r2, 153, x1, r1);
2509 c0 = x1; c0 += 2; c0 /= 12; c0.floor();
2510 j = x3; j *= 100; j += x2; j += c0;
2511 bool overflow = false; y = j.lintValue(&overflow); if(overflow) return false;
2512 c0 *= 12; x1 -= c0; x1 += 3; m = x1.lintValue();
2513 r1.mod(153); r1 /= 5; r1.floor(); r1++; d = r1.lintValue();
2514 return true;
2515 } else if(ct == CALENDAR_JULIAN) {
2516 Number y2, k2, k1, x2, x1, c0, j;
2517 y2 = J; y2 -= 1721118L;
2518 k2 = y2; k2 *= 4; k2 += 3;
2519 k1 = k2; k1.mod(1461); k1 /= 4; k1.floor(); k1 *= 5; k1 += 2;
2520 x1 = k1; x1 /= 153; x1.floor();
2521 c0 = x1; c0 += 2; c0 /= 12; c0.floor();
2522 j = k2; j /= 1461; j.floor(); j += c0;
2523 bool overflow = false; y = j.lintValue(&overflow); if(overflow) return false;
2524 c0 *= 12; x1 -= c0; x1 += 3; m = x1.lintValue();
2525 k1.mod(153); k1 /= 5; k1.floor(); k1++; d = k1.lintValue();
2526 return true;
2527 } else if(ct == CALENDAR_ISLAMIC) {
2528 Number k2, k1, j;
2529 k2 = J; k2 -= 1948440L; k2 *= 30; k2 += 15;
2530 k1 = k2; k1.mod(10631); k1 /= 30; k1.floor(); k1 *= 11; k1 += 5;
2531 j = k2; j /= 10631; j.floor(); j++;
2532 bool overflow = false; y = j.lintValue(&overflow); if(overflow) return false;
2533 k2 = k1; k2 /= 325; k2.floor(); k2++; m = k2.lintValue();
2534 k1.mod(153); k1 /= 11; k1.floor(); k1++; d = k1.lintValue();
2535 return true;
2536 } else if(ct == CALENDAR_EGYPTIAN) {
2537 Number y2, x2, y1, j;
2538 y2 = J; x2 = y2; x2 /= 365; x2.floor(); y1 = y2; y1.mod(365);
2539 j = x2; j++;
2540 bool overflow = false; y = j.lintValue(&overflow); if(overflow) return false;
2541 y2 = y1; y2 /= 30; y2.floor(); y2++; m = y2.lintValue();
2542 y1.mod(30); y1++; d = y1.lintValue();
2543 return true;
2544 } else if(ct == CALENDAR_INDIAN) {
2545 if(!cjdn_to_date(J, y, m, d, CALENDAR_GREGORIAN)) return false;
2546 bool leap = gregorian_leap_year(y);
2547 Number j(y); j -= 78;
2548 Number J0;
2549 J0 = date_to_cjdn(y, 1, 1, CALENDAR_GREGORIAN);
2550 Number yday(J); yday -= J0;
2551 if(yday.isLessThan(80)) {j--; yday += (leap ? 31 : 30) + (31 * 5) + (30 * 3) + 10 + 80;}
2552 yday -= 80;
2553 if(yday.isLessThan(leap ? 31 : 30)) {
2554 m = 1;
2555 yday++;
2556 d = yday.lintValue();
2557 } else {
2558 Number mday(yday); mday -= (leap ? 31 : 30);
2559 if(mday.isLessThan(31 * 5)) {
2560 m = quotient(mday, 31).lintValue() + 2;
2561 mday.rem(31);
2562 mday++;
2563 d = mday.lintValue();
2564 } else {
2565 mday -= 31 * 5;
2566 m = quotient(mday, 30).lintValue() + 7;
2567 mday.rem(30);
2568 mday++;
2569 d = mday.lintValue();
2570 }
2571 }
2572 bool overflow = false; y = j.lintValue(&overflow); if(overflow) return false;
2573 return true;
2574 } else {
2575 J -= 1721425L;
2576 return fixed_to_date(J, y, m, d, ct);
2577 }
2578 return false;
2579 }
2580
calendarToDate(QalculateDateTime & date,long int y,long int m,long int d,CalendarSystem ct)2581 bool calendarToDate(QalculateDateTime &date, long int y, long int m, long int d, CalendarSystem ct) {
2582 CALCULATOR->beginTemporaryStopIntervalArithmetic();
2583 long int new_y, new_m, new_d;
2584 if(!fixed_to_date(date_to_fixed(y, m, d, ct), new_y, new_m, new_d, CALENDAR_GREGORIAN)) {
2585 CALCULATOR->endTemporaryStopIntervalArithmetic();
2586 return false;
2587 }
2588 date.set(new_y, new_m, new_d);
2589 CALCULATOR->endTemporaryStopIntervalArithmetic();
2590 return true;
2591 }
dateToCalendar(const QalculateDateTime & date,long int & y,long int & m,long int & d,CalendarSystem ct)2592 bool dateToCalendar(const QalculateDateTime &date, long int &y, long int &m, long int &d, CalendarSystem ct) {
2593 if(ct == CALENDAR_GREGORIAN) {
2594 y = date.year(); m = date.month(); d = date.day();
2595 return true;
2596 }
2597 CALCULATOR->beginTemporaryStopIntervalArithmetic();
2598 if(!fixed_to_date(date_to_fixed(date.year(), date.month(), date.day(), CALENDAR_GREGORIAN), y, m, d, ct)) {
2599 CALCULATOR->endTemporaryStopIntervalArithmetic();
2600 return false;
2601 }
2602 CALCULATOR->endTemporaryStopIntervalArithmetic();
2603 return true;
2604 }
2605
numberOfMonths(CalendarSystem ct)2606 int numberOfMonths(CalendarSystem ct) {
2607 if(ct == CALENDAR_CHINESE) return 24;
2608 if(ct == CALENDAR_HEBREW || ct == CALENDAR_COPTIC || ct == CALENDAR_EGYPTIAN || ct == CALENDAR_ETHIOPIAN) return 13;
2609 return 12;
2610 }
monthName(long int month,CalendarSystem ct,bool append_number,bool append_leap)2611 string monthName(long int month, CalendarSystem ct, bool append_number, bool append_leap) {
2612 if(month < 1) return i2s(month);
2613 if(ct == CALENDAR_CHINESE) {
2614 if(month > 24) return i2s(month);
2615 bool leap = month > 12;
2616 if(leap) month -= 12;
2617 string str = i2s(month);
2618 if(leap && append_leap) {str += " ("; str += _("leap month"); str += ")";}
2619 return str;
2620 }
2621 if(month > 13) return i2s(month);
2622 string str;
2623 if(ct == CALENDAR_HEBREW) {
2624 str = HEBREW_MONTHS[month - 1];
2625 } else if(ct == CALENDAR_JULIAN || ct == CALENDAR_MILANKOVIC || ct == CALENDAR_GREGORIAN) {
2626 if(month == 13) return i2s(month);
2627 str = _(STANDARD_MONTHS[month - 1]);
2628 } else if(ct == CALENDAR_COPTIC) {
2629 str = _(COPTIC_MONTHS[month - 1]);
2630 } else if(ct == CALENDAR_ETHIOPIAN) {
2631 str = _(ETHIOPIAN_MONTHS[month - 1]);
2632 } else if(ct == CALENDAR_ISLAMIC) {
2633 if(month == 13) return i2s(month);
2634 str = _(ISLAMIC_MONTHS[month - 1]);
2635 } else if(ct == CALENDAR_PERSIAN) {
2636 if(month == 13) return i2s(month);
2637 str = _(PERSIAN_MONTHS[month - 1]);
2638 } else if(ct == CALENDAR_INDIAN) {
2639 if(month == 13) return i2s(month);
2640 str = _(INDIAN_MONTHS[month - 1]);
2641 } else {
2642 return i2s(month);
2643 }
2644 if(append_number) {str += " ("; str += i2s(month); str += ")";}
2645 return str;
2646 }
2647
chineseYearInfo(long int year,long int & cycle,long int & year_in_cycle,long int & stem,long int & branch)2648 void chineseYearInfo(long int year, long int &cycle, long int &year_in_cycle, long int &stem, long int &branch) {
2649 cycle = (year - 1) / 60 + 1;
2650 if(year <= 0) year += ((-year / 60) + 1) * 60;
2651 year_in_cycle = ((year - 1) % 60) + 1;
2652 stem = ((year_in_cycle - 1) % 10) + 1;
2653 branch = ((year_in_cycle - 1) % 12) + 1;
2654 }
chineseCycleYearToYear(long int cycle,long int year_in_cycle)2655 long int chineseCycleYearToYear(long int cycle, long int year_in_cycle) {
2656 return ((cycle - 1) * 60) + year_in_cycle;
2657 }
chineseStemBranchToCycleYear(long int stem,long int branch)2658 int chineseStemBranchToCycleYear(long int stem, long int branch) {
2659 stem = (stem + 1) / 2;
2660 stem -= (branch - 1) / 2;
2661 if(stem < 1) stem += 5;
2662 int cy = (stem - 1) * 12 + branch;
2663 if(cy < 0 || cy > 60) return 0;
2664 return cy;
2665 }
chineseStemName(long int stem)2666 string chineseStemName(long int stem) {
2667 stem = (stem + 1) / 2;
2668 if(stem < 1 || stem > 5) return empty_string;
2669 return _(CHINESE_ELEMENTS[stem - 1]);
2670 }
chineseBranchName(long int branch)2671 string chineseBranchName(long int branch) {
2672 if(branch < 1 || branch > 12) return empty_string;
2673 return _(CHINESE_ANIMALS[branch - 1]);
2674 }
2675
solarLongitude(const QalculateDateTime & date)2676 Number solarLongitude(const QalculateDateTime &date) {
2677 CALCULATOR->beginTemporaryStopIntervalArithmetic();
2678 Number fixed = date_to_fixed(date.year(), date.month(), date.day(), CALENDAR_GREGORIAN);
2679 Number time = date.second(); time /= 60; time += date.minute(); time -= dateTimeZone(date, false); time /= 60; time += date.hour(); time /= 24;
2680 fixed += time;
2681 Number longitude = solar_longitude(fixed);
2682 CALCULATOR->endTemporaryStopIntervalArithmetic();
2683 longitude.setPrecision(8);
2684 return longitude;
2685 }
findNextSolarLongitude(const QalculateDateTime & date,Number longitude)2686 QalculateDateTime findNextSolarLongitude(const QalculateDateTime &date, Number longitude) {
2687 CALCULATOR->beginTemporaryStopIntervalArithmetic();
2688 Number fixed = date_to_fixed(date.year(), date.month(), date.day(), CALENDAR_GREGORIAN);
2689 Number time = date.second(); time /= 60; time += date.minute(); time -= dateTimeZone(date, false); time /= 60; time += date.hour(); time /= 24;
2690 fixed += time;
2691 fixed = solar_longitude_after(longitude, fixed);
2692 long int y, m, d;
2693 fixed_to_date(fixed, y, m, d, CALENDAR_GREGORIAN);
2694 QalculateDateTime dt(y, m, d);
2695 Number fixed2 = date_to_fixed(y, m, d, CALENDAR_GREGORIAN);
2696 dt.addMinutes(dateTimeZone(dt, true));
2697 dt.addDays(fixed - fixed2);
2698 CALCULATOR->endTemporaryStopIntervalArithmetic();
2699 return dt;
2700 }
lunarPhase(const QalculateDateTime & date)2701 Number lunarPhase(const QalculateDateTime &date) {
2702 CALCULATOR->beginTemporaryStopIntervalArithmetic();
2703 Number fixed = date_to_fixed(date.year(), date.month(), date.day(), CALENDAR_GREGORIAN);
2704 Number time = date.second(); time /= 60; time += date.minute(); time -= dateTimeZone(date, false); time /= 60; time += date.hour(); time /= 24;
2705 fixed += time;
2706 Number phase = lunar_phase(fixed); phase /= 360;
2707 CALCULATOR->endTemporaryStopIntervalArithmetic();
2708 phase.setPrecision(8);
2709 return phase;
2710 }
findNextLunarPhase(const QalculateDateTime & date,Number phase)2711 QalculateDateTime findNextLunarPhase(const QalculateDateTime &date, Number phase) {
2712 CALCULATOR->beginTemporaryStopIntervalArithmetic();
2713 Number fixed = date_to_fixed(date.year(), date.month(), date.day(), CALENDAR_GREGORIAN);
2714 Number time = date.second(); time /= 60; time += date.minute(); time -= dateTimeZone(date, false); time /= 60; time += date.hour(); time /= 24;
2715 fixed += time;
2716 phase *= 360;
2717 fixed = lunar_phase_at_or_after(phase, fixed);
2718 long int y, m, d;
2719 fixed_to_date(fixed, y, m, d, CALENDAR_GREGORIAN);
2720 QalculateDateTime dt(y, m, d);
2721 Number fixed2 = date_to_fixed(y, m, d, CALENDAR_GREGORIAN);
2722 dt.addMinutes(dateTimeZone(dt, true));
2723 dt.addDays(fixed - fixed2);
2724 CALCULATOR->endTemporaryStopIntervalArithmetic();
2725 return dt;
2726 }
2727
2728