1 /******************************************************************************* 2 3 copyright: Copyright (c) 2005 John Chapman. All rights reserved 4 5 license: BSD style: $(LICENSE) 6 7 version: Mid 2005: Initial release 8 Apr 2007: reshaped 9 10 author: John Chapman, Kris, snoyberg 11 12 ******************************************************************************/ 13 14 module tango.time.chrono.Hebrew; 15 16 private import tango.core.Exception; 17 18 private import tango.time.chrono.Calendar; 19 20 21 22 /** 23 * $(ANCHOR _Hebrew) 24 * Represents the Hebrew calendar. 25 */ 26 public class Hebrew : Calendar { 27 28 private __gshared immutable uint[14][7] MonthDays = [ 29 // month // year type 30 [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], 31 [ 0, 30, 29, 29, 29, 30, 29, 0, 30, 29, 30, 29, 30, 29 ], // 1 32 [ 0, 30, 29, 30, 29, 30, 29, 0, 30, 29, 30, 29, 30, 29 ], // 2 33 [ 0, 30, 30, 30, 29, 30, 29, 0, 30, 29, 30, 29, 30, 29 ], // 3 34 [ 0, 30, 29, 29, 29, 30, 30, 29, 30, 29, 30, 29, 30, 29 ], // 4 35 [ 0, 30, 29, 30, 29, 30, 30, 29, 30, 29, 30, 29, 30, 29 ], // 5 36 [ 0, 30, 30, 30, 29, 30, 30, 29, 30, 29, 30, 29, 30, 29 ] // 6 37 ]; 38 39 private enum uint YearOfOneAD = 3760; 40 private enum uint DaysToOneAD = cast(int)(YearOfOneAD * 365.2735); 41 42 private enum uint PartsPerHour = 1080; 43 private enum uint PartsPerDay = 24 * PartsPerHour; 44 private enum uint DaysPerMonth = 29; 45 private enum uint DaysPerMonthFraction = 12 * PartsPerHour + 793; 46 private enum uint PartsPerMonth = DaysPerMonth * PartsPerDay + DaysPerMonthFraction; 47 private enum uint FirstNewMoon = 11 * PartsPerHour + 204; 48 49 private uint minYear_ = YearOfOneAD + 1583; 50 private uint maxYear_ = YearOfOneAD + 2240; 51 52 /** 53 * Represents the current era. 54 */ 55 public enum uint HEBREW_ERA = 1; 56 57 /** 58 * Overridden. Returns a Time value set to the specified date and time in the specified _era. 59 * Params: 60 * year = An integer representing the _year. 61 * month = An integer representing the _month. 62 * day = An integer representing the _day. 63 * hour = An integer representing the _hour. 64 * minute = An integer representing the _minute. 65 * second = An integer representing the _second. 66 * millisecond = An integer representing the _millisecond. 67 * era = An integer representing the _era. 68 * Returns: A Time set to the specified date and time. 69 */ 70 public override const Time toTime(uint year, uint month, uint day, uint hour, uint minute, uint second, uint millisecond, uint era) { 71 checkYear(year, era); 72 return getGregorianTime(year, month, day, hour, minute, second, millisecond); 73 } 74 75 /** 76 * Overridden. Returns the day of the week in the specified Time. 77 * Params: time = A Time value. 78 * Returns: A DayOfWeek value representing the day of the week of time. 79 */ 80 public override const DayOfWeek getDayOfWeek(const(Time) time) { 81 return cast(DayOfWeek) cast(uint) ((time.ticks / TimeSpan.TicksPerDay + 1) % 7); 82 } 83 84 /** 85 * Overridden. Returns the day of the month in the specified Time. 86 * Params: time = A Time value. 87 * Returns: An integer representing the day of the month of time. 88 */ 89 public override const uint getDayOfMonth(const(Time) time) { 90 auto year = getYear(time); 91 auto yearType = getYearType(year); 92 auto days = getStartOfYear(year) - DaysToOneAD; 93 auto day = cast(int)(time.ticks / TimeSpan.TicksPerDay) - days; 94 uint n; 95 while (n < 12 && day >= MonthDays[yearType][n + 1]) { 96 day -= MonthDays[yearType][n + 1]; 97 n++; 98 } 99 return day + 1; 100 } 101 102 /** 103 * Overridden. Returns the day of the year in the specified Time. 104 * Params: time = A Time value. 105 * Returns: An integer representing the day of the year of time. 106 */ 107 public override const uint getDayOfYear(const(Time) time) { 108 auto year = getYear(time); 109 auto days = getStartOfYear(year) - DaysToOneAD; 110 return (cast(uint)(time.ticks / TimeSpan.TicksPerDay) - days) + 1; 111 } 112 113 /** 114 * Overridden. Returns the month in the specified Time. 115 * Params: time = A Time value. 116 * Returns: An integer representing the month in time. 117 */ 118 public override const uint getMonth(const(Time) time) { 119 auto year = getYear(time); 120 auto yearType = getYearType(year); 121 auto days = getStartOfYear(year) - DaysToOneAD; 122 auto day = cast(int)(time.ticks / TimeSpan.TicksPerDay) - days; 123 uint n; 124 while (n < 12 && day >= MonthDays[yearType][n + 1]) { 125 day -= MonthDays[yearType][n + 1]; 126 n++; 127 } 128 return n + 1; 129 } 130 131 /** 132 * Overridden. Returns the year in the specified Time. 133 * Params: time = A Time value. 134 * Returns: An integer representing the year in time. 135 */ 136 public override const uint getYear(const(Time) time) { 137 auto day = cast(uint)(time.ticks / TimeSpan.TicksPerDay) + DaysToOneAD; 138 uint low = minYear_, high = maxYear_; 139 // Perform a binary search. 140 while (low <= high) { 141 auto mid = low + (high - low) / 2; 142 auto startDay = getStartOfYear(mid); 143 if (day < startDay) 144 high = mid - 1; 145 else if (day >= startDay && day < getStartOfYear(mid + 1)) 146 return mid; 147 else 148 low = mid + 1; 149 } 150 return low; 151 } 152 153 /** 154 * Overridden. Returns the era in the specified Time. 155 * Params: time = A Time value. 156 * Returns: An integer representing the ear in time. 157 */ 158 public override const uint getEra(const(Time) time) { 159 return HEBREW_ERA; 160 } 161 162 /** 163 * Overridden. Returns the number of days in the specified _year and _month of the specified _era. 164 * Params: 165 * year = An integer representing the _year. 166 * month = An integer representing the _month. 167 * era = An integer representing the _era. 168 * Returns: The number of days in the specified _year and _month of the specified _era. 169 */ 170 public override const uint getDaysInMonth(uint year, uint month, uint era) { 171 checkYear(year, era); 172 return MonthDays[getYearType(year)][month]; 173 } 174 175 /** 176 * Overridden. Returns the number of days in the specified _year of the specified _era. 177 * Params: 178 * year = An integer representing the _year. 179 * era = An integer representing the _era. 180 * Returns: The number of days in the specified _year in the specified _era. 181 */ 182 public override const uint getDaysInYear(uint year, uint era) { 183 return getStartOfYear(year + 1) - getStartOfYear(year); 184 } 185 186 /** 187 * Overridden. Returns the number of months in the specified _year of the specified _era. 188 * Params: 189 * year = An integer representing the _year. 190 * era = An integer representing the _era. 191 * Returns: The number of months in the specified _year in the specified _era. 192 */ 193 public override const uint getMonthsInYear(uint year, uint era) { 194 return isLeapYear(year, era) ? 13 : 12; 195 } 196 197 /** 198 * Overridden. Indicates whether the specified _year in the specified _era is a leap _year. 199 * Params: year = An integer representing the _year. 200 * Params: era = An integer representing the _era. 201 * Returns: true is the specified _year is a leap _year; otherwise, false. 202 */ 203 public override const bool isLeapYear(uint year, uint era) { 204 checkYear(year, era); 205 // true if year % 19 == 0, 3, 6, 8, 11, 14, 17 206 return ((7 * year + 1) % 19) < 7; 207 } 208 209 /** 210 * $(I Property.) Overridden. Retrieves the list of eras in the current calendar. 211 * Returns: An integer array representing the eras in the current calendar. 212 */ 213 public override const uint[] eras() { 214 auto tmp = [HEBREW_ERA]; 215 return tmp.dup; 216 } 217 218 /** 219 * $(I Property.) Overridden. Retrieves the identifier associated with the current calendar. 220 * Returns: An integer representing the identifier of the current calendar. 221 */ 222 public override const uint id() { 223 return HEBREW; 224 } 225 226 private const void checkYear(uint year, uint era) { 227 if ((era != CURRENT_ERA && era != HEBREW_ERA) || (year > maxYear_ || year < minYear_)) 228 throw new IllegalArgumentException("Value was out of range."); 229 } 230 231 private const uint getYearType(uint year) { 232 int yearLength = getStartOfYear(year + 1) - getStartOfYear(year); 233 if (yearLength > 380) 234 yearLength -= 30; 235 switch (yearLength) { 236 case 353: 237 // "deficient" 238 return 1; 239 case 383: 240 // "deficient" leap 241 return 4; 242 case 354: 243 // "normal" 244 return 2; 245 case 384: 246 // "normal" leap 247 return 5; 248 case 355: 249 // "complete" 250 return 3; 251 case 385: 252 // "complete" leap 253 return 6; 254 default: 255 break; 256 } 257 // Satisfies -w 258 throw new IllegalArgumentException("Value was not valid."); 259 } 260 261 private const uint getStartOfYear(uint year) { 262 auto months = (235 * year - 234) / 19; 263 auto fraction = months * DaysPerMonthFraction + FirstNewMoon; 264 auto day = months * 29 + (fraction / PartsPerDay); 265 fraction %= PartsPerDay; 266 267 auto dayOfWeek = day % 7; 268 if (dayOfWeek == 2 || dayOfWeek == 4 || dayOfWeek == 6) { 269 day++; 270 dayOfWeek = day % 7; 271 } 272 if (dayOfWeek == 1 && fraction > 15 * PartsPerHour + 204 && !isLeapYear(year, CURRENT_ERA)) 273 day += 2; 274 else if (dayOfWeek == 0 && fraction > 21 * PartsPerHour + 589 && isLeapYear(year, CURRENT_ERA)) 275 day++; 276 return day; 277 } 278 279 private const Time getGregorianTime(uint year, uint month, uint day, uint hour, uint minute, uint second, uint millisecond) { 280 auto yearType = getYearType(year); 281 auto days = getStartOfYear(year) - DaysToOneAD + day - 1; 282 for (int i = 1; i <= month; i++) 283 days += MonthDays[yearType][i - 1]; 284 return Time((days * TimeSpan.TicksPerDay) + getTimeTicks(hour, minute, second)) + TimeSpan.fromMillis(millisecond); 285 } 286 287 } 288