| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497 | /******************************************************************************* copyright: Copyright (c) 2005 John Chapman. All rights reserved license: BSD style: $(LICENSE) version: Mid 2005: Initial release Apr 2007: reshaped author: John Chapman, Kris ******************************************************************************/ module tango.time.chrono.Calendar; public import tango.time.Time; private import tango.core.Exception; /** * $(ANCHOR _Calendar) * Represents time in week, month and year divisions. * Remarks: Calendar is the abstract base class for the following Calendar implementations: * $(LINK2 #Gregorian, Gregorian), $(LINK2 #Hebrew, Hebrew), $(LINK2 #Hijri, Hijri), * $(LINK2 #Japanese, Japanese), $(LINK2 #Korean, Korean), $(LINK2 #Taiwan, Taiwan) and * $(LINK2 #ThaiBuddhist, ThaiBuddhist). */ public abstract class Calendar { /** * Indicates the current era of the calendar. */ package enum {CURRENT_ERA = 0}; // Corresponds to Win32 calendar IDs package enum { GREGORIAN = 1, GREGORIAN_US = 2, JAPAN = 3, TAIWAN = 4, KOREA = 5, HIJRI = 6, THAI = 7, HEBREW = 8, GREGORIAN_ME_FRENCH = 9, GREGORIAN_ARABIC = 10, GREGORIAN_XLIT_ENGLISH = 11, GREGORIAN_XLIT_FRENCH = 12 } package enum WeekRule { FirstDay, /// Indicates that the first week of the year is the first week containing the first day of the year. FirstFullWeek, /// Indicates that the first week of the year is the first full week following the first day of the year. FirstFourDayWeek /// Indicates that the first week of the year is the first week containing at least four days. } package enum DatePart { Year, Month, Day, DayOfYear } public enum DayOfWeek { Sunday, /// Indicates _Sunday. Monday, /// Indicates _Monday. Tuesday, /// Indicates _Tuesday. Wednesday, /// Indicates _Wednesday. Thursday, /// Indicates _Thursday. Friday, /// Indicates _Friday. Saturday /// Indicates _Saturday. } /** * Get the components of a Time structure using the rules of the * calendar. This is useful if you want more than one of the given * components. Note that this doesn't handle the time of day, as that * is calculated directly from the Time struct. * * The default implemenation is to call all the other accessors * directly, a derived class may override if it has a more efficient * method. */ const Date toDate (const(Time) time) { Date d; split (time, d.year, d.month, d.day, d.doy, d.dow, d.era); return d; } /** * Get the components of a Time structure using the rules of the * calendar. This is useful if you want more than one of the given * components. Note that this doesn't handle the time of day, as that * is calculated directly from the Time struct. * * The default implemenation is to call all the other accessors * directly, a derived class may override if it has a more efficient * method. */ const void split (const(Time) time, ref uint year, ref uint month, ref uint day, ref uint doy, ref uint dow, ref uint era) { year = getYear(time); month = getMonth(time); day = getDayOfMonth(time); doy = getDayOfYear(time); dow = getDayOfWeek(time); era = getEra(time); } /** * Returns a Time value set to the specified date and time in the current era. * Params: * year = An integer representing the _year. * month = An integer representing the _month. * day = An integer representing the _day. * hour = An integer representing the _hour. * minute = An integer representing the _minute. * second = An integer representing the _second. * millisecond = An integer representing the _millisecond. * Returns: The Time set to the specified date and time. */ const Time toTime (uint year, uint month, uint day, uint hour, uint minute, uint second, uint millisecond=0) { return toTime (year, month, day, hour, minute, second, millisecond, CURRENT_ERA); } /** * Returns a Time value for the given Date, in the current era * Params: * date = a representation of the Date * Returns: The Time set to the specified date. */ const Time toTime (const(Date) d) { return toTime (d.year, d.month, d.day, 0, 0, 0, 0, d.era); } /** * Returns a Time value for the given DateTime, in the current era * Params: * dt = a representation of the date and time * Returns: The Time set to the specified date and time. */ const Time toTime (const(DateTime) dt) { return toTime (dt.date, dt.time); } /** * Returns a Time value for the given Date and TimeOfDay, in the current era * Params: * d = a representation of the date * t = a representation of the day time * Returns: The Time set to the specified date and time. */ const Time toTime (const(Date) d, const(TimeOfDay) t) { return toTime (d.year, d.month, d.day, t.hours, t.minutes, t.seconds, t.millis, d.era); } /** * When overridden, returns a Time value set to the specified date and time in the specified _era. * Params: * year = An integer representing the _year. * month = An integer representing the _month. * day = An integer representing the _day. * hour = An integer representing the _hour. * minute = An integer representing the _minute. * second = An integer representing the _second. * millisecond = An integer representing the _millisecond. * era = An integer representing the _era. * Returns: A Time set to the specified date and time. */ abstract const Time toTime (uint year, uint month, uint day, uint hour, uint minute, uint second, uint millisecond, uint era); /** * When overridden, returns the day of the week in the specified Time. * Params: time = A Time value. * Returns: A DayOfWeek value representing the day of the week of time. */ abstract const DayOfWeek getDayOfWeek (const(Time) time); /** * When overridden, returns the day of the month in the specified Time. * Params: time = A Time value. * Returns: An integer representing the day of the month of time. */ abstract const uint getDayOfMonth (const(Time) time); /** * When overridden, returns the day of the year in the specified Time. * Params: time = A Time value. * Returns: An integer representing the day of the year of time. */ abstract const uint getDayOfYear (const(Time) time); /** * When overridden, returns the month in the specified Time. * Params: time = A Time value. * Returns: An integer representing the month in time. */ abstract const uint getMonth (const(Time) time); /** * When overridden, returns the year in the specified Time. * Params: time = A Time value. * Returns: An integer representing the year in time. */ abstract const uint getYear (const(Time) time); /** * When overridden, returns the era in the specified Time. * Params: time = A Time value. * Returns: An integer representing the ear in time. */ abstract const uint getEra (const(Time) time); /** * Returns the number of days in the specified _year and _month of the current era. * Params: * year = An integer representing the _year. * month = An integer representing the _month. * Returns: The number of days in the specified _year and _month of the current era. */ const uint getDaysInMonth (uint year, uint month) { return getDaysInMonth (year, month, CURRENT_ERA); } /** * When overridden, returns the number of days in the specified _year and _month of the specified _era. * Params: * year = An integer representing the _year. * month = An integer representing the _month. * era = An integer representing the _era. * Returns: The number of days in the specified _year and _month of the specified _era. */ abstract const uint getDaysInMonth (uint year, uint month, uint era); /** * Returns the number of days in the specified _year of the current era. * Params: year = An integer representing the _year. * Returns: The number of days in the specified _year in the current era. */ const uint getDaysInYear (uint year) { return getDaysInYear (year, CURRENT_ERA); } /** * When overridden, returns the number of days in the specified _year of the specified _era. * Params: * year = An integer representing the _year. * era = An integer representing the _era. * Returns: The number of days in the specified _year in the specified _era. */ abstract const uint getDaysInYear (uint year, uint era); /** * Returns the number of months in the specified _year of the current era. * Params: year = An integer representing the _year. * Returns: The number of months in the specified _year in the current era. */ const uint getMonthsInYear (uint year) { return getMonthsInYear (year, CURRENT_ERA); } /** * When overridden, returns the number of months in the specified _year of the specified _era. * Params: * year = An integer representing the _year. * era = An integer representing the _era. * Returns: The number of months in the specified _year in the specified _era. */ abstract const uint getMonthsInYear (uint year, uint era); /** * Returns the week of the year that includes the specified Time. * Params: * time = A Time value. * rule = A WeekRule value defining a calendar week. * firstDayOfWeek = A DayOfWeek value representing the first day of the week. * Returns: An integer representing the week of the year that includes the date in time. */ const uint getWeekOfYear (const(Time) time, WeekRule rule, DayOfWeek firstDayOfWeek) { auto year = getYear (time); auto jan1 = cast(int) getDayOfWeek (toTime (year, 1, 1, 0, 0, 0, 0)); switch (rule) { case WeekRule.FirstDay: int n = jan1 - cast(int) firstDayOfWeek; if (n < 0) n += 7; return (getDayOfYear (time) + n - 1) / 7 + 1; case WeekRule.FirstFullWeek: case WeekRule.FirstFourDayWeek: int fullDays = (rule is WeekRule.FirstFullWeek) ? 7 : 4; int n = cast(int) firstDayOfWeek - jan1; if (n != 0) { if (n < 0) n += 7; else if (n >= fullDays) n -= 7; } int day = getDayOfYear (time) - n; if (day > 0) return (day - 1) / 7 + 1; year = getYear(time) - 1; int month = getMonthsInYear (year); day = getDaysInMonth (year, month); return getWeekOfYear(toTime(year, month, day, 0, 0, 0, 0), rule, firstDayOfWeek); default: break; } throw new IllegalArgumentException("Value was out of range."); } /** * Indicates whether the specified _year in the current era is a leap _year. * Params: year = An integer representing the _year. * Returns: true is the specified _year is a leap _year; otherwise, false. */ const bool isLeapYear(uint year) { return isLeapYear(year, CURRENT_ERA); } /** * When overridden, indicates whether the specified _year in the specified _era is a leap _year. * Params: year = An integer representing the _year. * Params: era = An integer representing the _era. * Returns: true is the specified _year is a leap _year; otherwise, false. */ abstract const bool isLeapYear(uint year, uint era); /** * $(I Property.) When overridden, retrieves the list of eras in the current calendar. * Returns: An integer array representing the eras in the current calendar. */ @property abstract const uint[] eras(); /** * $(I Property.) Retrieves the identifier associated with the current calendar. * Returns: An integer representing the identifier of the current calendar. */ @property const uint id() { return -1; } /** * Returns a new Time with the specified number of months added. If * the months are negative, the months are subtracted. * * If the target month does not support the day component of the input * time, then an error will be thrown, unless truncateDay is set to * true. If truncateDay is set to true, then the day is reduced to * the maximum day of that month. * * For example, adding one month to 1/31/2000 with truncateDay set to * true results in 2/28/2000. * * The default implementation uses information provided by the * calendar to calculate the correct time to add. Derived classes may * override if there is a more optimized method. * * Note that the generic method does not take into account crossing * era boundaries. Derived classes may support this. * * Params: t = A time to add the months to * Params: nMonths = The number of months to add. This can be * negative. * Params: truncateDay = Round the day down to the maximum day of the * target month if necessary. * * Returns: A Time that represents the provided time with the number * of months added. */ const Time addMonths(const(Time) t, int nMonths, bool truncateDay = false) { uint era = getEra(t); uint year = getYear(t); uint month = getMonth(t); // // Assume we go back to day 1 of the current year, taking // into account that offset using the nMonths and nDays // offsets. // nMonths += month - 1; int origDom = cast(int)getDayOfMonth(t); long nDays = origDom - cast(int)getDayOfYear(t); if(nMonths > 0) { // // Adding, add all the years until the year we want to // be in. // auto miy = getMonthsInYear(year, era); while(nMonths >= miy) { // // skip a whole year // nDays += getDaysInYear(year, era); nMonths -= miy; year++; // // update miy // miy = getMonthsInYear(year, era); } } else if(nMonths < 0) { // // subtracting months // while(nMonths < 0) { auto miy = getMonthsInYear(--year, era); nDays -= getDaysInYear(year, era); nMonths += miy; } } // // we now are offset to the resulting year. // Add the rest of the months to get to the day we want. // int newDom = cast(int)getDaysInMonth(year, nMonths + 1, era); if(origDom > newDom) { // // error, the resulting day of month is out of range. See // if we should truncate // if(truncateDay) nDays -= newDom - origDom; else throw new IllegalArgumentException("days out of range"); } for(int m = 0; m < nMonths; m++) nDays += getDaysInMonth(year, m + 1, era); return t + TimeSpan.fromDays(nDays); } /** * Add the specified number of years to the given Time. * * The generic algorithm uses information provided by the abstract * methods. Derived classes may re-implement this in order to * optimize the algorithm * * Note that the generic algorithm does not take into account crossing * era boundaries. Derived classes may support this. * * Params: t = A time to add the years to * Params: nYears = The number of years to add. This can be negative. * * Returns: A Time that represents the provided time with the number * of years added. */ const Time addYears(const(Time) t, int nYears) { auto date = toDate(t); auto tod = t.ticks % TimeSpan.TicksPerDay; if(tod < 0) tod += TimeSpan.TicksPerDay; date.year += nYears; return toTime(date) + TimeSpan(tod); } package static long getTimeTicks (uint hour, uint minute, uint second) { return (TimeSpan.fromHours(hour) + TimeSpan.fromMinutes(minute) + TimeSpan.fromSeconds(second)).ticks; } } |