1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_i18npool.hxx" 30 31 #include <math.h> 32 #include <stdio.h> 33 34 #include "calendar_jewish.hxx" 35 36 using namespace ::com::sun::star::uno; 37 using namespace ::com::sun::star::lang; 38 using namespace ::com::sun::star::i18n; 39 using namespace ::rtl; 40 41 #define ERROR RuntimeException() 42 43 // not used 44 //static UErrorCode status; // status is shared in all calls to Calendar, it has to be reset for each call. 45 46 Calendar_jewish::Calendar_jewish() 47 { 48 cCalendar = "com.sun.star.i18n.Calendar_jewish"; 49 } 50 51 // The following C++ code is translated from the Lisp code in 52 // ``Calendrical Calculations'' by Nachum Dershowitz and Edward M. Reingold, 53 // Software---Practice & Experience, vol. 20, no. 9 (September, 1990), 54 // pp. 899--928. 55 56 // This code is in the public domain, but any use of it 57 // should acknowledge its source. 58 // http://www.ntu.edu.sg/home/ayxyan/date1.txt 59 60 // Hebrew dates 61 62 const int HebrewEpoch = -1373429; // Absolute date of start of Hebrew calendar 63 64 // True if year is an Hebrew leap year 65 sal_Bool HebrewLeapYear(sal_Int32 year) { 66 return ((((7 * year) + 1) % 19) < 7); 67 } 68 69 // Last month of Hebrew year. 70 sal_Int32 LastMonthOfHebrewYear(sal_Int32 year) { 71 return (HebrewLeapYear(year)) ? 13 : 12; 72 } 73 74 // Number of days elapsed from the Sunday prior to the start of the 75 // Hebrew calendar to the mean conjunction of Tishri of Hebrew year. 76 sal_Int32 HebrewCalendarElapsedDays(sal_Int32 year) { 77 sal_Int32 MonthsElapsed = 78 (235 * ((year - 1) / 19)) // Months in complete cycles so far. 79 + (12 * ((year - 1) % 19)) // Regular months in this cycle. 80 + (7 * ((year - 1) % 19) + 1) / 19; // Leap months this cycle 81 sal_Int32 PartsElapsed = 204 + 793 * (MonthsElapsed % 1080); 82 int HoursElapsed = 83 5 + 12 * MonthsElapsed + 793 * (MonthsElapsed / 1080) 84 + PartsElapsed / 1080; 85 sal_Int32 ConjunctionDay = 1 + 29 * MonthsElapsed + HoursElapsed / 24; 86 sal_Int32 ConjunctionParts = 1080 * (HoursElapsed % 24) + PartsElapsed % 1080; 87 sal_Int32 AlternativeDay; 88 89 if ((ConjunctionParts >= 19440) // If new moon is at or after midday, 90 || (((ConjunctionDay % 7) == 2) // ...or is on a Tuesday... 91 && (ConjunctionParts >= 9924) // at 9 hours, 204 parts or later... 92 && !(HebrewLeapYear(year))) // ...of a common year, 93 || (((ConjunctionDay % 7) == 1) // ...or is on a Monday at... 94 && (ConjunctionParts >= 16789) // 15 hours, 589 parts or later... 95 && (HebrewLeapYear(year - 1))))// at the end of a leap year 96 // Then postpone Rosh HaShanah one day 97 AlternativeDay = ConjunctionDay + 1; 98 else 99 AlternativeDay = ConjunctionDay; 100 101 if (((AlternativeDay % 7) == 0)// If Rosh HaShanah would occur on Sunday, 102 || ((AlternativeDay % 7) == 3) // or Wednesday, 103 || ((AlternativeDay % 7) == 5)) // or Friday 104 // Then postpone it one (more) day 105 return (1+ AlternativeDay); 106 else 107 return AlternativeDay; 108 } 109 110 // Number of days in Hebrew year. 111 sal_Int32 DaysInHebrewYear(sal_Int32 year) { 112 return ((HebrewCalendarElapsedDays(year + 1)) - 113 (HebrewCalendarElapsedDays(year))); 114 } 115 116 // True if Heshvan is long in Hebrew year. 117 sal_Bool LongHeshvan(sal_Int32 year) { 118 return ((DaysInHebrewYear(year) % 10) == 5); 119 } 120 121 // True if Kislev is short in Hebrew year. 122 sal_Bool ShortKislev(sal_Int32 year) { 123 return ((DaysInHebrewYear(year) % 10) == 3); 124 } 125 126 // Last day of month in Hebrew year. 127 sal_Int32 LastDayOfHebrewMonth(sal_Int32 month, sal_Int32 year) { 128 if ((month == 2) 129 || (month == 4) 130 || (month == 6) 131 || ((month == 8) && !(LongHeshvan(year))) 132 || ((month == 9) && ShortKislev(year)) 133 || (month == 10) 134 || ((month == 12) && !(HebrewLeapYear(year))) 135 || (month == 13)) 136 return 29; 137 else 138 return 30; 139 } 140 141 142 class HebrewDate { 143 private: 144 sal_Int32 year; // 1... 145 sal_Int32 month; // 1..LastMonthOfHebrewYear(year) 146 sal_Int32 day; // 1..LastDayOfHebrewMonth(month, year) 147 148 public: 149 HebrewDate(sal_Int32 m, sal_Int32 d, sal_Int32 y) { month = m; day = d; year = y; } 150 151 HebrewDate(sal_Int32 d) { // Computes the Hebrew date from the absolute date. 152 year = (d + HebrewEpoch) / 366; // Approximation from below. 153 // Search forward for year from the approximation. 154 while (d >= HebrewDate(7,1,year + 1)) 155 year++; 156 // Search forward for month from either Tishri or Nisan. 157 if (d < HebrewDate(1, 1, year)) 158 month = 7; // Start at Tishri 159 else 160 month = 1; // Start at Nisan 161 while (d > HebrewDate(month, (LastDayOfHebrewMonth(month,year)), year)) 162 month++; 163 // Calculate the day by subtraction. 164 day = d - HebrewDate(month, 1, year) + 1; 165 } 166 167 operator int() { // Computes the absolute date of Hebrew date. 168 sal_Int32 DayInYear = day; // Days so far this month. 169 if (month < 7) { // Before Tishri, so add days in prior months 170 // this year before and after Nisan. 171 sal_Int32 m = 7; 172 while (m <= (LastMonthOfHebrewYear(year))) { 173 DayInYear = DayInYear + LastDayOfHebrewMonth(m, year); 174 m++; 175 }; 176 m = 1; 177 while (m < month) { 178 DayInYear = DayInYear + LastDayOfHebrewMonth(m, year); 179 m++; 180 } 181 } 182 else { // Add days in prior months this year 183 sal_Int32 m = 7; 184 while (m < month) { 185 DayInYear = DayInYear + LastDayOfHebrewMonth(m, year); 186 m++; 187 } 188 } 189 return (DayInYear + 190 (HebrewCalendarElapsedDays(year)// Days in prior years. 191 + HebrewEpoch)); // Days elapsed before absolute date 1. 192 } 193 194 sal_Int32 GetMonth() { return month; } 195 sal_Int32 GetDay() { return day; } 196 sal_Int32 GetYear() { return year; } 197 198 }; 199 200 // Gregorian dates 201 202 int LastDayOfGregorianMonth(int month, int year) { 203 // Compute the last date of the month for the Gregorian calendar. 204 205 switch (month) { 206 case 2: 207 if ((((year % 4) == 0) && ((year % 100) != 0)) 208 || ((year % 400) == 0)) 209 return 29; 210 else 211 return 28; 212 case 4: 213 case 6: 214 case 9: 215 case 11: return 30; 216 default: return 31; 217 } 218 } 219 220 class GregorianDate { 221 private: 222 int year; // 1... 223 int month; // 1 == January, ..., 12 == December 224 int day; // 1..LastDayOfGregorianMonth(month, year) 225 226 public: 227 GregorianDate(int m, int d, int y) { month = m; day = d; year = y; } 228 229 GregorianDate(int d) { // Computes the Gregorian date from the absolute date. 230 // Search forward year by year from approximate year 231 year = d/366; 232 while (d >= GregorianDate(1,1,year+1)) 233 year++; 234 // Search forward month by month from January 235 month = 1; 236 while (d > GregorianDate(month, LastDayOfGregorianMonth(month,year), year)) 237 month++; 238 day = d - GregorianDate(month,1,year) + 1; 239 } 240 241 operator int() { // Computes the absolute date from the Gregorian date. 242 int N = day; // days this month 243 for (int m = month - 1; m > 0; m--) // days in prior months this year 244 N = N + LastDayOfGregorianMonth(m, year); 245 return 246 (N // days this year 247 + 365 * (year - 1) // days in previous years ignoring leap days 248 + (year - 1)/4 // Julian leap days before this year... 249 - (year - 1)/100 // ...minus prior century years... 250 + (year - 1)/400); // ...plus prior years divisible by 400 251 } 252 253 int GetMonth() { return month; } 254 int GetDay() { return day; } 255 int GetYear() { return year; } 256 257 }; 258 259 // map field value from gregorian calendar to other calendar, it can be overwritten by derived class. 260 void Calendar_jewish::mapFromGregorian() throw(RuntimeException) 261 { 262 int y = fieldValue[CalendarFieldIndex::YEAR]; 263 if (fieldValue[CalendarFieldIndex::ERA] == 0) 264 y = 1 - y; 265 GregorianDate Temp(fieldValue[CalendarFieldIndex::MONTH] + 1, fieldValue[CalendarFieldIndex::DAY_OF_MONTH], y); 266 HebrewDate hd(Temp); 267 268 fieldValue[CalendarFieldIndex::ERA] = hd.GetYear() <= 0 ? 0 : 1; 269 fieldValue[CalendarFieldIndex::MONTH] = sal::static_int_cast<sal_Int16>( hd.GetMonth() - 1 ); 270 fieldValue[CalendarFieldIndex::DAY_OF_MONTH] = (sal_Int16)hd.GetDay(); 271 fieldValue[CalendarFieldIndex::YEAR] = (sal_Int16)(hd.GetYear() <= 0 ? 1 - hd.GetYear() : hd.GetYear()); 272 } 273 274 #define FIELDS ((1 << CalendarFieldIndex::ERA) | (1 << CalendarFieldIndex::YEAR) | (1 << CalendarFieldIndex::MONTH) | (1 << CalendarFieldIndex::DAY_OF_MONTH)) 275 // map field value from other calendar to gregorian calendar, it should be implemented. 276 void Calendar_jewish::mapToGregorian() throw(RuntimeException) 277 { 278 if (fieldSet & FIELDS) { 279 sal_Int16 y = fieldSetValue[CalendarFieldIndex::YEAR]; 280 if (fieldSetValue[CalendarFieldIndex::ERA] == 0) 281 y = 1 - y; 282 HebrewDate Temp(fieldSetValue[CalendarFieldIndex::MONTH] + 1, fieldSetValue[CalendarFieldIndex::DAY_OF_MONTH], y); 283 GregorianDate gd(Temp); 284 285 fieldSetValue[CalendarFieldIndex::ERA] = gd.GetYear() <= 0 ? 0 : 1; 286 fieldSetValue[CalendarFieldIndex::MONTH] = sal::static_int_cast<sal_Int16>( gd.GetMonth() - 1 ); 287 fieldSetValue[CalendarFieldIndex::DAY_OF_MONTH] = (sal_Int16)gd.GetDay(); 288 fieldSetValue[CalendarFieldIndex::YEAR] = (sal_Int16)(gd.GetYear() <= 0 ? 1 - gd.GetYear() : gd.GetYear()); 289 fieldSet |= FIELDS; 290 } 291 } 292 293 // Methods in XExtendedCalendar 294 OUString SAL_CALL 295 Calendar_jewish::getDisplayString( sal_Int32 nCalendarDisplayCode, sal_Int16 nNativeNumberMode ) 296 throw (RuntimeException) 297 { 298 nNativeNumberMode = NativeNumberMode::NATNUM2; // make Hebrew number for Jewish calendar 299 300 if (nCalendarDisplayCode == CalendarDisplayCode::SHORT_YEAR) { 301 sal_Int32 value = getValue(CalendarFieldIndex::YEAR) % 1000; // take last 3 digits 302 return aNatNum.getNativeNumberString(OUString::valueOf(value), aLocale, nNativeNumberMode ); 303 } 304 else 305 return Calendar_gregorian::getDisplayString(nCalendarDisplayCode, nNativeNumberMode ); 306 } 307