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