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