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