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 
14 Converter::Converter()
15 {
16 
17 }
18 
19 Converter::~Converter()
20 {
21 }
22 
23 long 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  */
45 long 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 */
68 void
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 */
87 void
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 */
109 int 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 
117 enum
118 { Nissan =
119  1, Iyar, Sivan, Tamuz, Ab, Elul, Tishrei, Cheshvan, Kislev, Tevet,
120  Shvat, Adar, AdarII, AdarI = 12
121 };
122 
123 enum
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 */
130 int 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 */
175 int
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 */
205 bool 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 */
217 bool 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
239 long 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 
257 long 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 */
288 int 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 */
294 void
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 */
313 void
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 */
330 void
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 }