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 17 18 ******************************************************************************/ 19 20 module ocean.time.chrono.Hijri; 21 22 import ocean.time.chrono.Calendar; 23 24 import ocean.transition; 25 26 27 /** 28 * $(ANCHOR _Hijri) 29 * Represents the Hijri calendar. 30 */ 31 public class Hijri : Calendar { 32 33 private static Const!(uint[]) DAYS_TO_MONTH = [ 0, 30, 59, 89, 118, 148, 177, 207, 236, 266, 295, 325, 355 ]; 34 35 /** 36 * Represents the current era. 37 */ 38 public static immutable uint HIJRI_ERA = 1; 39 40 /** 41 * Overridden. Returns a Time value set to the specified date and time in the specified _era. 42 * Params: 43 * year = An integer representing the _year. 44 * month = An integer representing the _month. 45 * day = An integer representing the _day. 46 * hour = An integer representing the _hour. 47 * minute = An integer representing the _minute. 48 * second = An integer representing the _second. 49 * millisecond = An integer representing the _millisecond. 50 * era = An integer representing the _era. 51 * Returns: A Time set to the specified date and time. 52 */ 53 public override Time toTime(uint year, uint month, uint day, uint hour, uint minute, uint second, uint millisecond, uint era) { 54 return Time((daysSinceJan1(year, month, day) - 1) * TimeSpan.TicksPerDay + getTimeTicks(hour, minute, second)) + TimeSpan.fromMillis(millisecond); 55 } 56 57 /** 58 * Overridden. Returns the day of the week in the specified Time. 59 * Params: time = A Time value. 60 * Returns: A DayOfWeek value representing the day of the week of time. 61 */ 62 public override DayOfWeek getDayOfWeek(Time time) { 63 return cast(DayOfWeek) (cast(uint) (time.ticks / TimeSpan.TicksPerDay + 1) % 7); 64 } 65 66 /** 67 * Overridden. Returns the day of the month in the specified Time. 68 * Params: time = A Time value. 69 * Returns: An integer representing the day of the month of time. 70 */ 71 public override uint getDayOfMonth(Time time) { 72 return extractPart(time.ticks, DatePart.Day); 73 } 74 75 /** 76 * Overridden. Returns the day of the year in the specified Time. 77 * Params: time = A Time value. 78 * Returns: An integer representing the day of the year of time. 79 */ 80 public override uint getDayOfYear(Time time) { 81 return extractPart(time.ticks, DatePart.DayOfYear); 82 } 83 84 /** 85 * Overridden. Returns the day of the year in the specified Time. 86 * Params: time = A Time value. 87 * Returns: An integer representing the day of the year of time. 88 */ 89 public override uint getMonth(Time time) { 90 return extractPart(time.ticks, DatePart.Month); 91 } 92 93 /** 94 * Overridden. Returns the year in the specified Time. 95 * Params: time = A Time value. 96 * Returns: An integer representing the year in time. 97 */ 98 public override uint getYear(Time time) { 99 return extractPart(time.ticks, DatePart.Year); 100 } 101 102 /** 103 * Overridden. Returns the era in the specified Time. 104 * Params: time = A Time value. 105 * Returns: An integer representing the ear in time. 106 */ 107 public override uint getEra(Time time) { 108 return HIJRI_ERA; 109 } 110 111 /** 112 * Overridden. Returns the number of days in the specified _year and _month of the specified _era. 113 * Params: 114 * year = An integer representing the _year. 115 * month = An integer representing the _month. 116 * era = An integer representing the _era. 117 * Returns: The number of days in the specified _year and _month of the specified _era. 118 */ 119 public override uint getDaysInMonth(uint year, uint month, uint era) { 120 if (month == 12) 121 return isLeapYear(year, CURRENT_ERA) ? 30 : 29; 122 return (month % 2 == 1) ? 30 : 29; 123 } 124 125 /** 126 * Overridden. Returns the number of days in the specified _year of the specified _era. 127 * Params: 128 * year = An integer representing the _year. 129 * era = An integer representing the _era. 130 * Returns: The number of days in the specified _year in the specified _era. 131 */ 132 public override uint getDaysInYear(uint year, uint era) { 133 return isLeapYear(year, era) ? 355 : 354; 134 } 135 136 /** 137 * Overridden. Returns the number of months in the specified _year of the specified _era. 138 * Params: 139 * year = An integer representing the _year. 140 * era = An integer representing the _era. 141 * Returns: The number of months in the specified _year in the specified _era. 142 */ 143 public override uint getMonthsInYear(uint year, uint era) { 144 return 12; 145 } 146 147 /** 148 * Overridden. Indicates whether the specified _year in the specified _era is a leap _year. 149 * Params: year = An integer representing the _year. 150 * era = An integer representing the _era. 151 * Returns: true is the specified _year is a leap _year; otherwise, false. 152 */ 153 public override bool isLeapYear(uint year, uint era) { 154 return (14 + 11 * year) % 30 < 11; 155 } 156 157 /** 158 * $(I Property.) Overridden. Retrieves the list of eras in the current calendar. 159 * Returns: An integer array representing the eras in the current calendar. 160 */ 161 public override uint[] eras() { 162 auto tmp = [HIJRI_ERA]; 163 return tmp.dup; 164 } 165 166 /** 167 * $(I Property.) Overridden. Retrieves the identifier associated with the current calendar. 168 * Returns: An integer representing the identifier of the current calendar. 169 */ 170 public override uint id() { 171 return HIJRI; 172 } 173 174 private long daysToYear(uint year) { 175 int cycle = ((year - 1) / 30) * 30; 176 int remaining = year - cycle - 1; 177 long days = ((cycle * 10631L) / 30L) + 227013L; 178 while (remaining > 0) { 179 days += 354 + (isLeapYear(remaining, CURRENT_ERA) ? 1 : 0); 180 remaining--; 181 } 182 return days; 183 } 184 185 private long daysSinceJan1(uint year, uint month, uint day) { 186 return cast(long)(daysToYear(year) + DAYS_TO_MONTH[month - 1] + day); 187 } 188 189 private int extractPart(long ticks, DatePart part) { 190 long days = TimeSpan(ticks).days + 1; 191 int year = cast(int)(((days - 227013) * 30) / 10631) + 1; 192 long daysUpToYear = daysToYear(year); 193 long daysInYear = getDaysInYear(year, CURRENT_ERA); 194 if (days < daysUpToYear) { 195 daysUpToYear -= daysInYear; 196 year--; 197 } 198 else if (days == daysUpToYear) { 199 year--; 200 daysUpToYear -= getDaysInYear(year, CURRENT_ERA); 201 } 202 else if (days > daysUpToYear + daysInYear) { 203 daysUpToYear += daysInYear; 204 year++; 205 } 206 207 if (part == DatePart.Year) 208 return year; 209 210 days -= daysUpToYear; 211 if (part == DatePart.DayOfYear) 212 return cast(int)days; 213 214 int month = 1; 215 while (month <= 12 && days > DAYS_TO_MONTH[month - 1]) 216 month++; 217 month--; 218 if (part == DatePart.Month) 219 return month; 220 221 return cast(int)(days - DAYS_TO_MONTH[month - 1]); 222 } 223 224 } 225