converter.cpp
1/***************************************************************************
2 * Copyright (C) 2003 by Jonathan Singer *
3 * jsinger@leeta.net *
4 * Calendar routines from Hebrew Calendar by Frank Yellin *
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#include "converter.h"
12#include <tdelocale.h>
13
14Converter::Converter()
15{
16
17}
18
19Converter::~Converter()
20{
21}
22
23long Converter::absolute_from_gregorian(int year, int month, int day)
24{
25 int xyear, day_number;
26
27 xyear = year - 1;
28 day_number = day + 31 * (month - 1);
29 if (month > 2)
30 {
31 day_number -= (23 + (4 * month)) / 10;
32 if (gregorian_leap_year_p(year))
33 day_number++;
34 }
35 return day_number + /* the day number within the current year */
36 365L * xyear + /* days in prior years */
37 (xyear / 4) + /* Julian leap years */
38 (-(xyear / 100)) + /* deduct century years */
39 (xyear / 400); /* add Gregorian leap years */
40}
41
42/* Given a Hebrew date, calculate the number of days since
43 * January 0, 0001, Gregorian
44 */
45long Converter::absolute_from_hebrew(int year, int month, int day)
46{
47 long sum = day + hebrew_elapsed_days(year) - 1373429L;
48 int i;
49
50 if (month < 7)
51 {
52 int months = hebrew_months_in_year(year);
53
54 for (i = 7; i <= months; ++i)
55 sum += hebrew_month_length(year, i);
56 for (i = 1; i < month; ++i)
57 sum += hebrew_month_length(year, i);
58 }
59 else
60 {
61 for (i = 7; i < month; ++i)
62 sum += hebrew_month_length(year, i);
63 }
64 return sum;
65}
66
67/* Given an absolute date, calculate the gregorian date */
68void
69 Converter::gregorian_from_absolute(long date, int *yearp,
70 int *monthp, int *dayp)
71{
72 int year, month, day;
73
74 for (year = date / 366;
75 date >= absolute_from_gregorian(year + 1, 1, 1); ++year) ;
76 for (month = 1;
77 (month <= 11)
78 && (date >= absolute_from_gregorian(year, 1 + month, 1));
79 ++month ) ;
80 day = 1 + date - absolute_from_gregorian(year, month, 1);
81 *yearp = year;
82 *monthp = month;
83 *dayp = day;
84}
85
86/* Given an absolute date, calculate the Hebrew date */
87void
88 Converter::hebrew_from_absolute(long date, int *yearp, int *monthp,
89 int *dayp)
90{
91 int year, month, day, gyear, gmonth, gday, months;
92
93 gregorian_from_absolute(date, &gyear, &gmonth, &gday);
94 year = gyear + 3760;
95 while (date >= absolute_from_hebrew(1 + year, 7, 1))
96 year++;
97 months = hebrew_months_in_year(year);
98 for (month = 7;
99 date > absolute_from_hebrew(year, month,
100 hebrew_month_length(year, month));
101 month = 1 + (month % months)) ;
102 day = 1 + date - absolute_from_hebrew(year, month, 1);
103 *yearp = year;
104 *monthp = month;
105 *dayp = day;
106}
107
108/* Number of months in a Hebrew year */
109int Converter::hebrew_months_in_year(int year)
110{
111 if (hebrew_leap_year_p(year))
112 return 13;
113 else
114 return 12;
115}
116
117enum
118{ Nissan =
119 1, Iyar, Sivan, Tamuz, Ab, Elul, Tishrei, Cheshvan, Kislev, Tevet,
120 Shvat, Adar, AdarII, AdarI = 12
121};
122
123enum
124{ January =
125 1, February, March, April, May, June, July, August, September,
126 October, November, December
127};
128
129/* Number of days in a Hebrew month */
130int Converter::hebrew_month_length(int year, int month)
131{
132 switch (month)
133 {
134 case Tishrei:
135 case Shvat:
136 case Nissan:
137 case Sivan:
138 case Ab:
139 return 30;
140
141 case Tevet:
142 case Iyar:
143 case Tamuz:
144 case Elul:
145 case AdarII:
146 return 29;
147
148 case Cheshvan:
149 // 29 days, unless it's a long year.
150 if ((hebrew_year_length(year) % 10) == 5)
151 return 30;
152 else
153 return 29;
154
155 case Kislev:
156 // 30 days, unless it's a short year.
157 if ((hebrew_year_length(year) % 10) == 3)
158 return 29;
159 else
160 return 30;
161
162 case Adar:
163 // Adar (non-leap year) has 29 days. Adar I has 30 days.
164 if (hebrew_leap_year_p(year))
165 return 30;
166 else
167 return 29;
168
169 default:
170 return 0;
171 }
172}
173
174/* Number of days in a Julian or gregorian month */
175int
176 Converter::secular_month_length(int year,
177 int month /*, bool julianp */ )
178{
179 switch (month)
180 {
181 case January:
182 case March:
183 case May:
184 case July:
185 case August:
186 case October:
187 case December:
188 return 31;
189 case April:
190 case June:
191 case September:
192 case November:
193 return 30;
194 case February:
195 if (gregorian_leap_year_p(year))
196 return 29;
197 else
198 return 28;
199 default:
200 return 0;
201 }
202}
203
204/* Is it a Leap year in the gregorian calendar */
205bool Converter::gregorian_leap_year_p(int year)
206{
207 if ((year % 4) != 0)
208 return 0;
209 if ((year % 400) == 0)
210 return 1;
211 if ((year % 100) == 0)
212 return 0;
213 return 1;
214}
215
216/* Is it a leap year in the Jewish Calendar */
217bool Converter::hebrew_leap_year_p(int year)
218{
219 switch (year % 19)
220 {
221 case 0:
222 case 3:
223 case 6:
224 case 8:
225 case 11:
226 case 14:
227 case 17:
228 return 1;
229 default:
230 return 0;
231 }
232}
233
234/* Return the number of days from 1 Tishrei 0001 to the beginning of the given year.
235 * Since this routine gets called frequently with the same year arguments, we cache
236 * the most recent values.
237 */
238#define MEMORY 5
239long Converter::hebrew_elapsed_days(int year)
240{
241 static int saved_year[MEMORY] = { -1, -1, -1, -1, -1 };
242 static long saved_value[MEMORY];
243 int i;
244
245 for (i = 0; i < MEMORY; ++i)
246 if (year == saved_year[i])
247 return saved_value[i];
248 for (i = 0; i < MEMORY-1; ++i) {
249 saved_year[i] = saved_year[1 + i];
250 saved_value[i] = saved_value[1 + i];
251 }
252 saved_year[MEMORY - 1] = year;
253 saved_value[MEMORY - 1] = hebrew_elapsed_days2(year);
254 return saved_value[MEMORY - 1];
255}
256
257long Converter::hebrew_elapsed_days2(int year)
258{
259 long prev_year = year - 1;
260 long months_elapsed = 235L * (prev_year / 19) /* months in complete cycles so far */
261 + 12L * (prev_year % 19) /* regular months in this cycle */
262 + (((prev_year % 19) * 7 + 1) / 19); /* leap months this cycle */
263 long parts_elapsed = 5604 + 13753 * months_elapsed;
264 long day = 1 + 29 * months_elapsed + parts_elapsed / 25920;
265 long parts = parts_elapsed % 25920;
266 int weekday = (day % 7);
267 long alt_day = ((parts >= 19440)
268 || (weekday == 2 && (parts >= 9924)
269 && !hebrew_leap_year_p(year)) || (weekday == 1
270 && (parts >=
271 16789)
272 &&
273 hebrew_leap_year_p
274 (prev_year)))
275 ? day + 1 : day;
276 switch (alt_day % 7)
277 {
278 case 0:
279 case 3:
280 case 5:
281 return 1 + alt_day;
282 default:
283 return alt_day;
284 }
285}
286
287/* Number of days in the given Hebrew year */
288int Converter::hebrew_year_length(int year)
289{
290 return hebrew_elapsed_days(1 + year) - hebrew_elapsed_days(year);
291}
292
293/* Fill in the DateResult structure based on the given secular date */
294void
295 Converter::SecularToHebrewConversion(int syear, int smonth,
296 int sday,
297 struct DateResult *result)
298{
299 int hyear, hmonth, hday;
300 long absolute;
301
302 absolute = absolute_from_gregorian(syear, smonth, sday);
303
304 hebrew_from_absolute(absolute, &hyear, &hmonth, &hday);
305
306 result->year = hyear;
307 result->month = hmonth;
308 result->day = hday;
309 finish_up(absolute, hyear, hmonth, syear, smonth, result);
310}
311
312/* Fill in the DateResult structure based on the given Hebrew date */
313void
314 Converter::HebrewToSecularConversion(int hyear, int hmonth,
315 int hday,
316 struct DateResult *result)
317{
318 int syear, smonth, sday;
319 long absolute;
320
321 absolute = absolute_from_hebrew(hyear, hmonth, hday);
322 gregorian_from_absolute(absolute, &syear, &smonth, &sday);
323 result->year = hyear;
324 result->month = hmonth;
325 result->day = hday;
326 finish_up(absolute, hyear, hmonth, syear, smonth, result);
327}
328
329/* This is common code for filling up the DateResult structure */
330void
331 Converter::finish_up(long absolute, int hyear, int hmonth,
332 int syear, int smonth,
333 struct DateResult *result)
334{
335 result->hebrew_month_length = hebrew_month_length(hyear, hmonth);
336 result->secular_month_length = secular_month_length(syear, smonth);
337 result->hebrew_leap_year_p = hebrew_leap_year_p(hyear);
338 result->secular_leap_year_p = gregorian_leap_year_p(syear);
339 result->kvia = (hebrew_year_length(hyear) % 10) - 3;
340 // absolute is -1 on 1/1/0001 Julian
341 result->day_of_week = (7 + absolute) % 7;
342 result->hebrew_day_number =
343 absolute - absolute_from_hebrew(hyear, 7, 1) + 1;
344
345}