korganizer

converter.cpp

00001 /***************************************************************************
00002  *   Copyright (C) 2003 by Jonathan Singer                                             *
00003  *   jsinger@leeta.net                                                                                *
00004  *   Calendar routines from Hebrew Calendar by Frank Yellin                     *
00005  *                                                                                                             *
00006  *   This program is free software; you can redistribute it and/or modify      *
00007  *   it under the terms of the GNU General Public License as published by  *
00008  *   the Free Software Foundation; either version 2 of the License, or      *
00009  *   (at your option) any later version.                                                       *
00010  ***************************************************************************/
00011 #include "converter.h"
00012 #include <klocale.h>
00013 
00014 Converter::Converter()
00015 {
00016 
00017 }
00018 
00019 Converter::~Converter()
00020 {
00021 }
00022 
00023 long Converter::absolute_from_gregorian(int year, int month, int day)
00024 {
00025   int xyear, day_number;
00026 
00027   xyear = year - 1;
00028   day_number = day + 31 * (month - 1);
00029   if (month > 2)
00030       {
00031         day_number -= (23 + (4 * month)) / 10;
00032         if (gregorian_leap_year_p(year))
00033           day_number++;
00034       }
00035   return day_number +     /* the day number within the current year */
00036     365L * xyear +        /* days in prior years */
00037     (xyear / 4) +         /* Julian leap years */
00038     (-(xyear / 100)) +    /* deduct century years */
00039     (xyear / 400);        /* add Gregorian leap years */
00040 }
00041 
00042 /* Given a Hebrew date, calculate the number of days since
00043  * January 0, 0001, Gregorian
00044  */
00045 long Converter::absolute_from_hebrew(int year, int month, int day)
00046 {
00047   long sum = day + hebrew_elapsed_days(year) - 1373429L;
00048   int i;
00049 
00050   if (month < 7)
00051       {
00052         int months = hebrew_months_in_year(year);
00053 
00054         for (i = 7; i <= months; ++i)
00055           sum += hebrew_month_length(year, i);
00056         for (i = 1; i < month; ++i)
00057           sum += hebrew_month_length(year, i);
00058       }
00059   else
00060       {
00061         for (i = 7; i < month; ++i)
00062           sum += hebrew_month_length(year, i);
00063       }
00064   return sum;
00065 }
00066 
00067 /* Given an absolute date, calculate the gregorian date  */
00068 void
00069   Converter::gregorian_from_absolute(long date, int *yearp,
00070                                      int *monthp, int *dayp)
00071 {
00072   int year, month, day;
00073 
00074   for (year = date / 366;
00075        date >= absolute_from_gregorian(year + 1, 1, 1); ++year) ;
00076   for (month = 1;
00077        (month <= 11)
00078        && (date >= absolute_from_gregorian(year, 1 + month, 1));
00079        ++month ) ;
00080   day = 1 + date - absolute_from_gregorian(year, month, 1);
00081   *yearp = year;
00082   *monthp = month;
00083   *dayp = day;
00084 }
00085 
00086 /* Given an absolute date, calculate the Hebrew date */
00087 void
00088   Converter::hebrew_from_absolute(long date, int *yearp, int *monthp,
00089                                   int *dayp)
00090 {
00091   int year, month, day, gyear, gmonth, gday, months;
00092 
00093   gregorian_from_absolute(date, &gyear, &gmonth, &gday);
00094   year = gyear + 3760;
00095   while (date >= absolute_from_hebrew(1 + year, 7, 1))
00096     year++;
00097   months = hebrew_months_in_year(year);
00098   for (month = 7;
00099        date > absolute_from_hebrew(year, month,
00100                                    hebrew_month_length(year, month));
00101        month = 1 + (month % months)) ;
00102   day = 1 + date - absolute_from_hebrew(year, month, 1);
00103   *yearp = year;
00104   *monthp = month;
00105   *dayp = day;
00106 }
00107 
00108 /* Number of months in a Hebrew year */
00109 int Converter::hebrew_months_in_year(int year)
00110 {
00111   if (hebrew_leap_year_p(year))
00112     return 13;
00113   else
00114     return 12;
00115 }
00116 
00117 enum
00118 { Nissan =
00119     1, Iyar, Sivan, Tamuz, Ab, Elul, Tishrei, Cheshvan, Kislev, Tevet,
00120   Shvat, Adar, AdarII, AdarI = 12
00121 };
00122 
00123 enum
00124 { January =
00125     1, February, March, April, May, June, July, August, September,
00126   October, November, December
00127 };
00128 
00129 /* Number of days in a Hebrew month */
00130 int Converter::hebrew_month_length(int year, int month)
00131 {
00132   switch (month)
00133       {
00134       case Tishrei:
00135       case Shvat:
00136       case Nissan:
00137       case Sivan:
00138       case Ab:
00139         return 30;
00140 
00141       case Tevet:
00142       case Iyar:
00143       case Tamuz:
00144       case Elul:
00145       case AdarII:
00146         return 29;
00147 
00148       case Cheshvan:
00149         // 29 days, unless it's a long year.
00150         if ((hebrew_year_length(year) % 10) == 5)
00151           return 30;
00152         else
00153           return 29;
00154 
00155       case Kislev:
00156         // 30 days, unless it's a short year.
00157         if ((hebrew_year_length(year) % 10) == 3)
00158           return 29;
00159         else
00160           return 30;
00161 
00162       case Adar:
00163         // Adar (non-leap year) has 29 days.  Adar I has 30 days.
00164         if (hebrew_leap_year_p(year))
00165           return 30;
00166         else
00167           return 29;
00168 
00169       default:
00170         return 0;
00171       }
00172 }
00173 
00174 /* Number of days in a Julian or gregorian month */
00175 int
00176   Converter::secular_month_length(int year,
00177                                   int month /*, bool julianp */ )
00178 {
00179   switch (month)
00180       {
00181       case January:
00182       case March:
00183       case May:
00184       case July:
00185       case August:
00186       case October:
00187       case December:
00188         return 31;
00189       case April:
00190       case June:
00191       case September:
00192       case November:
00193         return 30;
00194       case February:
00195         if (gregorian_leap_year_p(year))
00196           return 29;
00197         else
00198           return 28;
00199       default:
00200         return 0;
00201       }
00202 }
00203 
00204 /* Is it a Leap year in the gregorian calendar */
00205 bool Converter::gregorian_leap_year_p(int year)
00206 {
00207   if ((year % 4) != 0)
00208     return 0;
00209   if ((year % 400) == 0)
00210     return 1;
00211   if ((year % 100) == 0)
00212     return 0;
00213   return 1;
00214 }
00215 
00216 /* Is it a leap year in the Jewish Calendar */
00217 bool Converter::hebrew_leap_year_p(int year)
00218 {
00219   switch (year % 19)
00220       {
00221       case 0:
00222       case 3:
00223       case 6:
00224       case 8:
00225       case 11:
00226       case 14:
00227       case 17:
00228         return 1;
00229       default:
00230         return 0;
00231       }
00232 }
00233 
00234 /* Return the number of days from 1 Tishrei 0001 to the beginning of the given year.
00235  * Since this routine gets called frequently with the same year arguments, we cache
00236  * the most recent values.
00237  */
00238 #define MEMORY 5
00239 long Converter::hebrew_elapsed_days(int year)
00240 {
00241   static int saved_year[MEMORY] = { -1, -1, -1, -1, -1 };
00242   static long saved_value[MEMORY];
00243   int i;
00244 
00245   for (i = 0; i < MEMORY; ++i)
00246     if (year == saved_year[i])
00247       return saved_value[i];
00248   for (i = 0; i < MEMORY-1; ++i) {
00249     saved_year[i] = saved_year[1 + i];
00250     saved_value[i] = saved_value[1 + i];
00251   }
00252   saved_year[MEMORY - 1] = year;
00253   saved_value[MEMORY - 1] = hebrew_elapsed_days2(year);
00254   return saved_value[MEMORY - 1];
00255 }
00256 
00257 long Converter::hebrew_elapsed_days2(int year)
00258 {
00259   long prev_year = year - 1;
00260   long months_elapsed = 235L * (prev_year / 19)  /* months in complete cycles so far */
00261     + 12L * (prev_year % 19)                     /* regular months in this cycle */
00262     + (((prev_year % 19) * 7 + 1) / 19);         /* leap months this cycle */
00263   long parts_elapsed = 5604 + 13753 * months_elapsed;
00264   long day = 1 + 29 * months_elapsed + parts_elapsed / 25920;
00265   long parts = parts_elapsed % 25920;
00266   int weekday = (day % 7);
00267   long alt_day = ((parts >= 19440)
00268                   || (weekday == 2 && (parts >= 9924)
00269                       && !hebrew_leap_year_p(year)) || (weekday == 1
00270                                                         && (parts >=
00271                                                             16789)
00272                                                         &&
00273                                                         hebrew_leap_year_p
00274                                                         (prev_year)))
00275     ? day + 1 : day;
00276   switch (alt_day % 7)
00277       {
00278       case 0:
00279       case 3:
00280       case 5:
00281         return 1 + alt_day;
00282       default:
00283         return alt_day;
00284       }
00285 }
00286 
00287 /* Number of days in the given Hebrew year */
00288 int Converter::hebrew_year_length(int year)
00289 {
00290   return hebrew_elapsed_days(1 + year) - hebrew_elapsed_days(year);
00291 }
00292 
00293 /* Fill in the DateResult structure based on the given secular date */
00294 void
00295   Converter::SecularToHebrewConversion(int syear, int smonth,
00296                                        int sday,
00297                                        struct DateResult *result)
00298 {
00299   int hyear, hmonth, hday;
00300   long absolute;
00301 
00302   absolute = absolute_from_gregorian(syear, smonth, sday);
00303 
00304   hebrew_from_absolute(absolute, &hyear, &hmonth, &hday);
00305 
00306   result->year = hyear;
00307   result->month = hmonth;
00308   result->day = hday;
00309   finish_up(absolute, hyear, hmonth, syear, smonth, result);
00310 }
00311 
00312 /* Fill in the DateResult structure based on the given Hebrew date */
00313 void
00314   Converter::HebrewToSecularConversion(int hyear, int hmonth,
00315                                        int hday,
00316                                        struct DateResult *result)
00317 {
00318   int syear, smonth, sday;
00319   long absolute;
00320 
00321   absolute = absolute_from_hebrew(hyear, hmonth, hday);
00322   gregorian_from_absolute(absolute, &syear, &smonth, &sday);
00323   result->year = hyear;
00324   result->month = hmonth;
00325   result->day = hday;
00326   finish_up(absolute, hyear, hmonth, syear, smonth, result);
00327 }
00328 
00329 /* This is common code for filling up the DateResult structure */
00330 void
00331   Converter::finish_up(long absolute, int hyear, int hmonth,
00332                        int syear, int smonth,
00333                        struct DateResult *result)
00334 {
00335   result->hebrew_month_length = hebrew_month_length(hyear, hmonth);
00336   result->secular_month_length = secular_month_length(syear, smonth);
00337   result->hebrew_leap_year_p = hebrew_leap_year_p(hyear);
00338   result->secular_leap_year_p = gregorian_leap_year_p(syear);
00339   result->kvia = (hebrew_year_length(hyear) % 10) - 3;
00340   // absolute is -1 on 1/1/0001 Julian
00341   result->day_of_week = (7 + absolute) % 7;
00342   result->hebrew_day_number =
00343     absolute - absolute_from_hebrew(hyear, 7, 1) + 1;
00344 
00345 }
KDE Home | KDE Accessibility Home | Description of Access Keys