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