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 moduleocean.time.chrono.Calendar;
21 22 publicimportocean.time.Time;
23 24 importocean.core.ExceptionDefinitions;
25 26 27 28 /**
29 * $(ANCHOR _Calendar)
30 * Represents time in week, month and year divisions.
31 * Remarks: Calendar is the abstract base class for the following Calendar implementations:
32 * $(LINK2 #Gregorian, Gregorian), $(LINK2 #Hebrew, Hebrew), $(LINK2 #Hijri, Hijri),
33 * $(LINK2 #Japanese, Japanese), $(LINK2 #Korean, Korean), $(LINK2 #Taiwan, Taiwan) and
34 * $(LINK2 #ThaiBuddhist, ThaiBuddhist).
35 */36 publicabstractclassCalendar37 {
38 /**
39 * Indicates the current era of the calendar.
40 */41 publicenum {CURRENT_ERA = 0};
42 43 // Corresponds to Win32 calendar IDs44 publicenum45 {
46 GREGORIAN = 1,
47 GREGORIAN_US = 2,
48 JAPAN = 3,
49 TAIWAN = 4,
50 KOREA = 5,
51 HIJRI = 6,
52 THAI = 7,
53 HEBREW = 8,
54 GREGORIAN_ME_FRENCH = 9,
55 GREGORIAN_ARABIC = 10,
56 GREGORIAN_XLIT_ENGLISH = 11,
57 GREGORIAN_XLIT_FRENCH = 1258 }
59 60 publicenumWeekRule61 {
62 FirstDay, /// Indicates that the first week of the year is the first week containing the first day of the year.63 FirstFullWeek, /// Indicates that the first week of the year is the first full week following the first day of the year.64 FirstFourDayWeek/// Indicates that the first week of the year is the first week containing at least four days.65 }
66 67 publicenumDatePart68 {
69 Year,
70 Month,
71 Day,
72 DayOfYear73 }
74 75 publicenumDayOfWeek76 {
77 Sunday, /// Indicates _Sunday.78 Monday, /// Indicates _Monday.79 Tuesday, /// Indicates _Tuesday.80 Wednesday, /// Indicates _Wednesday.81 Thursday, /// Indicates _Thursday.82 Friday, /// Indicates _Friday.83 Saturday/// Indicates _Saturday.84 }
85 86 87 /**
88 * Get the components of a Time structure using the rules of the
89 * calendar. This is useful if you want more than one of the given
90 * components. Note that this doesn't handle the time of day, as that
91 * is calculated directly from the Time struct.
92 *
93 * The default implemenation is to call all the other accessors
94 * directly, a derived class may override if it has a more efficient
95 * method.
96 */97 DatetoDate (Timetime)
98 {
99 Dated;
100 split (time, d.year, d.month, d.day, d.doy, d.dow, d.era);
101 returnd;
102 }
103 104 /**
105 * Get the components of a Time structure using the rules of the
106 * calendar. This is useful if you want more than one of the given
107 * components. Note that this doesn't handle the time of day, as that
108 * is calculated directly from the Time struct.
109 *
110 * The default implemenation is to call all the other accessors
111 * directly, a derived class may override if it has a more efficient
112 * method.
113 */114 voidsplit (Timetime, refuintyear, refuintmonth, refuintday, refuintdoy, refuintdow, refuintera)
115 {
116 year = getYear(time);
117 month = getMonth(time);
118 day = getDayOfMonth(time);
119 doy = getDayOfYear(time);
120 dow = getDayOfWeek(time);
121 era = getEra(time);
122 }
123 124 /**
125 * Returns a Time value set to the specified date and time in the current era.
126 * Params:
127 * year = An integer representing the _year.
128 * month = An integer representing the _month.
129 * day = An integer representing the _day.
130 * hour = An integer representing the _hour.
131 * minute = An integer representing the _minute.
132 * second = An integer representing the _second.
133 * millisecond = An integer representing the _millisecond.
134 * Returns: The Time set to the specified date and time.
135 */136 TimetoTime (uintyear, uintmonth, uintday, uinthour, uintminute, uintsecond, uintmillisecond=0)
137 {
138 returntoTime (year, month, day, hour, minute, second, millisecond, CURRENT_ERA);
139 }
140 141 /**
142 * Returns a Time value for the given Date, in the current era
143 * Params:
144 * d = a representation of the Date
145 * Returns: The Time set to the specified date.
146 */147 TimetoTime (Dated)
148 {
149 returntoTime (d.year, d.month, d.day, 0, 0, 0, 0, d.era);
150 }
151 152 /**
153 * Returns a Time value for the given DateTime, in the current era
154 * Params:
155 * dt = a representation of the date and time
156 * Returns: The Time set to the specified date and time.
157 */158 TimetoTime (DateTimedt)
159 {
160 returntoTime (dt.date, dt.time);
161 }
162 163 /**
164 * Returns a Time value for the given Date and TimeOfDay, in the current era
165 * Params:
166 * d = a representation of the date
167 * t = a representation of the day time
168 * Returns: The Time set to the specified date and time.
169 */170 TimetoTime (Dated, TimeOfDayt)
171 {
172 returntoTime (d.year, d.month, d.day, t.hours, t.minutes, t.seconds, t.millis, d.era);
173 }
174 175 /**
176 * When overridden, returns a Time value set to the specified date and time in the specified _era.
177 * Params:
178 * year = An integer representing the _year.
179 * month = An integer representing the _month.
180 * day = An integer representing the _day.
181 * hour = An integer representing the _hour.
182 * minute = An integer representing the _minute.
183 * second = An integer representing the _second.
184 * millisecond = An integer representing the _millisecond.
185 * era = An integer representing the _era.
186 * Returns: A Time set to the specified date and time.
187 */188 abstractTimetoTime (uintyear, uintmonth, uintday, uinthour, uintminute, uintsecond, uintmillisecond, uintera);
189 190 /**
191 * When overridden, returns the day of the week in the specified Time.
192 * Params: time = A Time value.
193 * Returns: A DayOfWeek value representing the day of the week of time.
194 */195 abstractDayOfWeekgetDayOfWeek (Timetime);
196 197 /**
198 * When overridden, returns the day of the month in the specified Time.
199 * Params: time = A Time value.
200 * Returns: An integer representing the day of the month of time.
201 */202 abstractuintgetDayOfMonth (Timetime);
203 204 /**
205 * When overridden, returns the day of the year in the specified Time.
206 * Params: time = A Time value.
207 * Returns: An integer representing the day of the year of time.
208 */209 abstractuintgetDayOfYear (Timetime);
210 211 /**
212 * When overridden, returns the month in the specified Time.
213 * Params: time = A Time value.
214 * Returns: An integer representing the month in time.
215 */216 abstractuintgetMonth (Timetime);
217 218 /**
219 * When overridden, returns the year in the specified Time.
220 * Params: time = A Time value.
221 * Returns: An integer representing the year in time.
222 */223 abstractuintgetYear (Timetime);
224 225 /**
226 * When overridden, returns the era in the specified Time.
227 * Params: time = A Time value.
228 * Returns: An integer representing the ear in time.
229 */230 abstractuintgetEra (Timetime);
231 232 /**
233 * Returns the number of days in the specified _year and _month of the current era.
234 * Params:
235 * year = An integer representing the _year.
236 * month = An integer representing the _month.
237 * Returns: The number of days in the specified _year and _month of the current era.
238 */239 uintgetDaysInMonth (uintyear, uintmonth)
240 {
241 returngetDaysInMonth (year, month, CURRENT_ERA);
242 }
243 244 /**
245 * When overridden, returns the number of days in the specified _year and _month of the specified _era.
246 * Params:
247 * year = An integer representing the _year.
248 * month = An integer representing the _month.
249 * era = An integer representing the _era.
250 * Returns: The number of days in the specified _year and _month of the specified _era.
251 */252 abstractuintgetDaysInMonth (uintyear, uintmonth, uintera);
253 254 /**
255 * Returns the number of days in the specified _year of the current era.
256 * Params: year = An integer representing the _year.
257 * Returns: The number of days in the specified _year in the current era.
258 */259 uintgetDaysInYear (uintyear)
260 {
261 returngetDaysInYear (year, CURRENT_ERA);
262 }
263 264 /**
265 * When overridden, returns the number of days in the specified _year of the specified _era.
266 * Params:
267 * year = An integer representing the _year.
268 * era = An integer representing the _era.
269 * Returns: The number of days in the specified _year in the specified _era.
270 */271 abstractuintgetDaysInYear (uintyear, uintera);
272 273 /**
274 * Returns the number of months in the specified _year of the current era.
275 * Params: year = An integer representing the _year.
276 * Returns: The number of months in the specified _year in the current era.
277 */278 uintgetMonthsInYear (uintyear)
279 {
280 returngetMonthsInYear (year, CURRENT_ERA);
281 }
282 283 /**
284 * When overridden, returns the number of months in the specified _year of the specified _era.
285 * Params:
286 * year = An integer representing the _year.
287 * era = An integer representing the _era.
288 * Returns: The number of months in the specified _year in the specified _era.
289 */290 abstractuintgetMonthsInYear (uintyear, uintera);
291 292 /**
293 * Returns the week of the year that includes the specified Time.
294 * Params:
295 * time = A Time value.
296 * rule = A WeekRule value defining a calendar week.
297 * firstDayOfWeek = A DayOfWeek value representing the first day of the week.
298 * Returns: An integer representing the week of the year that includes the date in time.
299 */300 uintgetWeekOfYear (Timetime, WeekRulerule, DayOfWeekfirstDayOfWeek)
301 {
302 autoyear = getYear (time);
303 autojan1 = cast(int) getDayOfWeek (toTime (year, 1, 1, 0, 0, 0, 0));
304 305 switch (rule)
306 {
307 caseWeekRule.FirstDay:
308 intn = jan1 - cast(int) firstDayOfWeek;
309 if (n < 0)
310 n += 7;
311 return (getDayOfYear (time) + n - 1) / 7 + 1;
312 313 caseWeekRule.FirstFullWeek:
314 caseWeekRule.FirstFourDayWeek:
315 intfullDays = (ruleisWeekRule.FirstFullWeek) ? 7 : 4;
316 intn = cast(int) firstDayOfWeek - jan1;
317 if (n != 0)
318 {
319 if (n < 0)
320 n += 7;
321 else322 if (n >= fullDays)
323 n -= 7;
324 }
325 326 intday = getDayOfYear (time) - n;
327 if (day > 0)
328 return (day - 1) / 7 + 1;
329 year = getYear(time) - 1;
330 intmonth = getMonthsInYear (year);
331 day = getDaysInMonth (year, month);
332 returngetWeekOfYear(toTime(year, month, day, 0, 0, 0, 0), rule, firstDayOfWeek);
333 334 default:
335 break;
336 }
337 thrownewIllegalArgumentException("Value was out of range.");
338 }
339 340 /**
341 * Indicates whether the specified _year in the current era is a leap _year.
342 * Params: year = An integer representing the _year.
343 * Returns: true is the specified _year is a leap _year; otherwise, false.
344 */345 boolisLeapYear(uintyear)
346 {
347 returnisLeapYear(year, CURRENT_ERA);
348 }
349 350 /**
351 * When overridden, indicates whether the specified _year in the specified _era is a leap _year.
352 * Params: year = An integer representing the _year.
353 * era = An integer representing the _era.
354 * Returns: true is the specified _year is a leap _year; otherwise, false.
355 */356 abstractboolisLeapYear(uintyear, uintera);
357 358 /**
359 * $(I Property.) When overridden, retrieves the list of eras in the current calendar.
360 * Returns: An integer array representing the eras in the current calendar.
361 */362 abstractuint[] eras();
363 364 /**
365 * $(I Property.) Retrieves the identifier associated with the current calendar.
366 * Returns: An integer representing the identifier of the current calendar.
367 */368 uintid()
369 {
370 return -1;
371 }
372 373 /**
374 * Returns a new Time with the specified number of months added. If
375 * the months are negative, the months are subtracted.
376 *
377 * If the target month does not support the day component of the input
378 * time, then an error will be thrown, unless truncateDay is set to
379 * true. If truncateDay is set to true, then the day is reduced to
380 * the maximum day of that month.
381 *
382 * For example, adding one month to 1/31/2000 with truncateDay set to
383 * true results in 2/28/2000.
384 *
385 * The default implementation uses information provided by the
386 * calendar to calculate the correct time to add. Derived classes may
387 * override if there is a more optimized method.
388 *
389 * Note that the generic method does not take into account crossing
390 * era boundaries. Derived classes may support this.
391 *
392 * Params: t = A time to add the months to
393 * nMonths = The number of months to add. This can be
394 * negative.
395 * truncateDay = Round the day down to the maximum day of the
396 * target month if necessary.
397 *
398 * Returns: A Time that represents the provided time with the number
399 * of months added.
400 */401 TimeaddMonths(Timet, intnMonths, booltruncateDay = false)
402 {
403 uintera = getEra(t);
404 uintyear = getYear(t);
405 uintmonth = getMonth(t);
406 407 //408 // Assume we go back to day 1 of the current year, taking409 // into account that offset using the nMonths and nDays410 // offsets.411 //412 nMonths += month - 1;
413 intorigDom = cast(int)getDayOfMonth(t);
414 longnDays = origDom - cast(int)getDayOfYear(t);
415 if(nMonths > 0)
416 {
417 //418 // Adding, add all the years until the year we want to419 // be in.420 //421 automiy = getMonthsInYear(year, era);
422 while(nMonths >= miy)
423 {
424 //425 // skip a whole year426 //427 nDays += getDaysInYear(year, era);
428 nMonths -= miy;
429 year++;
430 431 //432 // update miy433 //434 miy = getMonthsInYear(year, era);
435 }
436 }
437 elseif(nMonths < 0)
438 {
439 //440 // subtracting months441 //442 while(nMonths < 0)
443 {
444 automiy = getMonthsInYear(--year, era);
445 nDays -= getDaysInYear(year, era);
446 nMonths += miy;
447 }
448 }
449 450 //451 // we now are offset to the resulting year.452 // Add the rest of the months to get to the day we want.453 //454 intnewDom = cast(int)getDaysInMonth(year, nMonths + 1, era);
455 if(origDom > newDom)
456 {
457 //458 // error, the resulting day of month is out of range. See459 // if we should truncate460 //461 if(truncateDay)
462 nDays -= newDom - origDom;
463 else464 thrownewIllegalArgumentException("days out of range");
465 466 }
467 for(intm = 0; m < nMonths; m++)
468 nDays += getDaysInMonth(year, m + 1, era);
469 returnt + TimeSpan.fromDays(nDays);
470 }
471 472 /**
473 * Add the specified number of years to the given Time.
474 *
475 * The generic algorithm uses information provided by the abstract
476 * methods. Derived classes may re-implement this in order to
477 * optimize the algorithm
478 *
479 * Note that the generic algorithm does not take into account crossing
480 * era boundaries. Derived classes may support this.
481 *
482 * Params: t = A time to add the years to
483 * nYears = The number of years to add. This can be negative.
484 *
485 * Returns: A Time that represents the provided time with the number
486 * of years added.
487 */488 TimeaddYears(Timet, intnYears)
489 {
490 autodate = toDate(t);
491 autotod = t.ticks % TimeSpan.TicksPerDay;
492 if(tod < 0)
493 tod += TimeSpan.TicksPerDay;
494 date.year += nYears;
495 returntoTime(date) + TimeSpan(tod);
496 }
497 498 publicstaticlonggetTimeTicks (uinthour, uintminute, uintsecond)
499 {
500 return (TimeSpan.fromHours(hour) + TimeSpan.fromMinutes(minute) + TimeSpan.fromSeconds(second)).ticks;
501 }
502 }