The Labs \ Source Viewer \ SSCLI \ System.Globalization \ GregorianCalendar

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. namespace System.Globalization
  16. {
  17.     //
  18.     // N.B.:
  19.     // A lot of this code is directly from DateTime.cs. If you update that class,
  20.     // update this one as well.
  21.     // However, we still need these duplicated code because we will add era support
  22.     // in this class.
  23.     //
  24.     //
  25.    
  26.     using System.Threading;
  27.     using System;
  28.     using System.Globalization;
  29.    
  30.     //
  31.     // This class implements the Gregorian calendar. In 1582, Pope Gregory XIII made
  32.     // minor changes to the solar Julian or "Old Style" calendar to make it more
  33.     // accurate. Thus the calendar became known as the Gregorian or "New Style"
  34.     // calendar, and adopted in Catholic countries such as Spain and France. Later
  35.     // the Gregorian calendar became popular throughout Western Europe because it
  36.     // was accurate and convenient for international trade. Scandinavian countries
  37.     // adopted it in 1700, Great Britain in 1752, the American colonies in 1752 and
  38.     // India in 1757. China adopted the same calendar in 1911, Russia in 1918, and
  39.     // some Eastern European countries as late as 1940.
  40.     //
  41.     // This calendar recognizes two era values:
  42.     // 0 CurrentEra (AD)
  43.     // 1 BeforeCurrentEra (BC)
  44.    
  45.     [System.Runtime.InteropServices.ComVisible(true)]
  46.     [Serializable()]
  47.     public class GregorianCalendar : Calendar
  48.     {
  49. /*
  50.             A.D. = anno Domini (after the birth of Jesus Christ)
  51.         */       
  52.        
  53.         public const int ADEra = 1;
  54.        
  55.        
  56.         internal const int DatePartYear = 0;
  57.         internal const int DatePartDayOfYear = 1;
  58.         internal const int DatePartMonth = 2;
  59.         internal const int DatePartDay = 3;
  60.        
  61.         //
  62.         // This is the max Gregorian year can be represented by DateTime class. The limitation
  63.         // is derived from DateTime class.
  64.         //
  65.         internal const int MaxYear = 9999;
  66.        
  67.         internal GregorianCalendarTypes m_type;
  68.        
  69.         static internal readonly int[] DaysToMonth365 = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273,
  70.         304, 334, 365};
  71.        
  72.         static internal readonly int[] DaysToMonth366 = {0, 31, 60, 91, 121, 152, 182, 213, 244, 274,
  73.         305, 335, 366};
  74.        
  75.         static internal Calendar m_defaultInstance = null;
  76.        
  77.        
  78.         [System.Runtime.InteropServices.ComVisible(false)]
  79.         public override DateTime MinSupportedDateTime {
  80.             get { return (DateTime.MinValue); }
  81.         }
  82.        
  83.         [System.Runtime.InteropServices.ComVisible(false)]
  84.         public override DateTime MaxSupportedDateTime {
  85.             get { return (DateTime.MaxValue); }
  86.         }
  87.        
  88.         // Return the type of the Gregorian calendar.
  89.         //
  90.        
  91.         [System.Runtime.InteropServices.ComVisible(false)]
  92.         public override CalendarAlgorithmType AlgorithmType {
  93.             get { return CalendarAlgorithmType.SolarCalendar; }
  94.         }
  95.        
  96. /*=================================GetDefaultInstance==========================
  97.         **Action: Internal method to provide a default intance of GregorianCalendar.  Used by NLS+ implementation
  98.         **      and other calendars.
  99.         **Returns:
  100.         **Arguments:
  101.         **Exceptions:
  102.         ============================================================================*/       
  103.        
  104.         static internal Calendar GetDefaultInstance()
  105.         {
  106.             if (m_defaultInstance == null) {
  107.                 m_defaultInstance = new GregorianCalendar();
  108.             }
  109.             return (m_defaultInstance);
  110.         }
  111.        
  112.         // Construct an instance of gregorian calendar.
  113.        
  114.         public GregorianCalendar() : this(GregorianCalendarTypes.Localized)
  115.         {
  116.         }
  117.        
  118.        
  119.         public GregorianCalendar(GregorianCalendarTypes type)
  120.         {
  121.             if ((int)type < (int)GregorianCalendarTypes.Localized || (int)type > (int)GregorianCalendarTypes.TransliteratedFrench) {
  122.                 throw new ArgumentOutOfRangeException("type", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), GregorianCalendarTypes.Localized, GregorianCalendarTypes.TransliteratedFrench));
  123.             }
  124.             this.m_type = type;
  125.         }
  126.        
  127.         public virtual GregorianCalendarTypes CalendarType {
  128.             get { return (m_type); }
  129.            
  130.             set {
  131.                 VerifyWritable();
  132.                
  133.                 switch (value) {
  134.                     case GregorianCalendarTypes.Localized:
  135.                     case GregorianCalendarTypes.USEnglish:
  136.                     case GregorianCalendarTypes.MiddleEastFrench:
  137.                     case GregorianCalendarTypes.Arabic:
  138.                     case GregorianCalendarTypes.TransliteratedEnglish:
  139.                     case GregorianCalendarTypes.TransliteratedFrench:
  140.                         m_type = value;
  141.                         break;
  142.                     default:
  143.                        
  144.                         throw new ArgumentOutOfRangeException("m_type", Environment.GetResourceString("ArgumentOutOfRange_Enum"));
  145.                         break;
  146.                 }
  147.             }
  148.         }
  149.        
  150.         internal override int ID {
  151. // By returning different ID for different variations of GregorianCalendar,
  152. // we can support the Transliterated Gregorian calendar.
  153. // DateTimeFormatInfo will use this ID to get formatting information about
  154. // the calendar.
  155.             get { return ((int)m_type); }
  156.         }
  157.        
  158.        
  159.         // Returns a given date part of this DateTime. This method is used
  160.         // to compute the year, day-of-year, month, or day part.
  161.         internal virtual int GetDatePart(long ticks, int part)
  162.         {
  163.             // n = number of days since 1/1/0001
  164.             int n = (int)(ticks / TicksPerDay);
  165.             // y400 = number of whole 400-year periods since 1/1/0001
  166.             int y400 = n / DaysPer400Years;
  167.             // n = day number within 400-year period
  168.             n -= y400 * DaysPer400Years;
  169.             // y100 = number of whole 100-year periods within 400-year period
  170.             int y100 = n / DaysPer100Years;
  171.             // Last 100-year period has an extra day, so decrement result if 4
  172.             if (y100 == 4)
  173.                 y100 = 3;
  174.             // n = day number within 100-year period
  175.             n -= y100 * DaysPer100Years;
  176.             // y4 = number of whole 4-year periods within 100-year period
  177.             int y4 = n / DaysPer4Years;
  178.             // n = day number within 4-year period
  179.             n -= y4 * DaysPer4Years;
  180.             // y1 = number of whole years within 4-year period
  181.             int y1 = n / DaysPerYear;
  182.             // Last year has an extra day, so decrement result if 4
  183.             if (y1 == 4)
  184.                 y1 = 3;
  185.             // If year was requested, compute and return it
  186.             if (part == DatePartYear) {
  187.                 return (y400 * 400 + y100 * 100 + y4 * 4 + y1 + 1);
  188.             }
  189.             // n = day number within year
  190.             n -= y1 * DaysPerYear;
  191.             // If day-of-year was requested, return it
  192.             if (part == DatePartDayOfYear) {
  193.                 return (n + 1);
  194.             }
  195.             // Leap year calculation looks different from IsLeapYear since y1, y4,
  196.             // and y100 are relative to year 1, not year 0
  197.             bool leapYear = (y1 == 3 && (y4 != 24 || y100 == 3));
  198.             int[] days = leapYear ? DaysToMonth366 : DaysToMonth365;
  199.             // All months have less than 32 days, so n >> 5 is a good conservative
  200.             // estimate for the month
  201.             int m = n >> 5 + 1;
  202.             // m = 1-based month number
  203.             while (n >= days[m])
  204.                 m++;
  205.             // If month was requested, return it
  206.             if (part == DatePartMonth)
  207.                 return (m);
  208.             // Return 1-based day-of-month
  209.             return (n - days[m - 1] + 1);
  210.         }
  211.        
  212. /*=================================GetAbsoluteDate==========================
  213.         **Action: Gets the absolute date for the given Gregorian date.  The absolute date means
  214.         **      the number of days from January 1st, 1 A.D.
  215.         **Returns:  the absolute date
  216.         **Arguments:
  217.         **      year    the Gregorian year
  218.         **      month  the Gregorian month
  219.         **      day    the day
  220.         **Exceptions:
  221.         **      ArgumentOutOfRangException  if year, month, day value is valid.
  222.         **Note:
  223.         **      This is an internal method used by DateToTicks() and the calculations of Hijri and Hebrew calendars.
  224.         **      Number of Days in Prior Years (both common and leap years) +
  225.         **      Number of Days in Prior Months of Current Year +
  226.         **      Number of Days in Current Month
  227.         **
  228.         ============================================================================*/       
  229.        
  230.         static internal long GetAbsoluteDate(int year, int month, int day)
  231.         {
  232.             if (year >= 1 && year <= MaxYear && month >= 1 && month <= 12) {
  233.                 int[] days = ((year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))) ? DaysToMonth366 : DaysToMonth365;
  234.                 if (day >= 1 && (day <= days[month] - days[month - 1])) {
  235.                     int y = year - 1;
  236.                     int absoluteDate = y * 365 + y / 4 - y / 100 + y / 400 + days[month - 1] + day - 1;
  237.                     return (absoluteDate);
  238.                 }
  239.             }
  240.             throw new ArgumentOutOfRangeException(null, Environment.GetResourceString("ArgumentOutOfRange_BadYearMonthDay"));
  241.         }
  242.        
  243.         // Returns the tick count corresponding to the given year, month, and day.
  244.         // Will check the if the parameters are valid.
  245.         internal virtual long DateToTicks(int year, int month, int day)
  246.         {
  247.             return (GetAbsoluteDate(year, month, day) * TicksPerDay);
  248.         }
  249.        
  250.         // Returns the DateTime resulting from adding the given number of
  251.         // months to the specified DateTime. The result is computed by incrementing
  252.         // (or decrementing) the year and month parts of the specified DateTime by
  253.         // value months, and, if required, adjusting the day part of the
  254.         // resulting date downwards to the last day of the resulting month in the
  255.         // resulting year. The time-of-day part of the result is the same as the
  256.         // time-of-day part of the specified DateTime.
  257.         //
  258.         // In more precise terms, considering the specified DateTime to be of the
  259.         // form y / m / d + t, where y is the
  260.         // year, m is the month, d is the day, and t is the
  261.         // time-of-day, the result is y1 / m1 / d1 + t,
  262.         // where y1 and m1 are computed by adding value months
  263.         // to y and m, and d1 is the largest value less than
  264.         // or equal to d that denotes a valid day in month m1 of year
  265.         // y1.
  266.         //
  267.        
  268.         public override DateTime AddMonths(DateTime time, int months)
  269.         {
  270.             if (months < -120000 || months > 120000) {
  271.                 throw new ArgumentOutOfRangeException("months", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), -120000, 120000));
  272.             }
  273.             int y = GetDatePart(time.Ticks, DatePartYear);
  274.             int m = GetDatePart(time.Ticks, DatePartMonth);
  275.             int d = GetDatePart(time.Ticks, DatePartDay);
  276.             int i = m - 1 + months;
  277.             if (i >= 0) {
  278.                 m = i % 12 + 1;
  279.                 y = y + i / 12;
  280.             }
  281.             else {
  282.                 m = 12 + (i + 1) % 12;
  283.                 y = y + (i - 11) / 12;
  284.             }
  285.             int[] daysArray = (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) ? DaysToMonth366 : DaysToMonth365;
  286.             int days = (daysArray[m] - daysArray[m - 1]);
  287.            
  288.             if (d > days) {
  289.                 d = days;
  290.             }
  291.             long ticks = DateToTicks(y, m, d) + time.Ticks % TicksPerDay;
  292.             Calendar.CheckAddResult(ticks, MinSupportedDateTime, MaxSupportedDateTime);
  293.            
  294.             return (new DateTime(ticks));
  295.         }
  296.        
  297.        
  298.         // Returns the DateTime resulting from adding the given number of
  299.         // years to the specified DateTime. The result is computed by incrementing
  300.         // (or decrementing) the year part of the specified DateTime by value
  301.         // years. If the month and day of the specified DateTime is 2/29, and if the
  302.         // resulting year is not a leap year, the month and day of the resulting
  303.         // DateTime becomes 2/28. Otherwise, the month, day, and time-of-day
  304.         // parts of the result are the same as those of the specified DateTime.
  305.         //
  306.        
  307.         public override DateTime AddYears(DateTime time, int years)
  308.         {
  309.             return (AddMonths(time, years * 12));
  310.         }
  311.        
  312.         // Returns the day-of-month part of the specified DateTime. The returned
  313.         // value is an integer between 1 and 31.
  314.         //
  315.        
  316.         public override int GetDayOfMonth(DateTime time)
  317.         {
  318.             return (GetDatePart(time.Ticks, DatePartDay));
  319.         }
  320.        
  321.         // Returns the day-of-week part of the specified DateTime. The returned value
  322.         // is an integer between 0 and 6, where 0 indicates Sunday, 1 indicates
  323.         // Monday, 2 indicates Tuesday, 3 indicates Wednesday, 4 indicates
  324.         // Thursday, 5 indicates Friday, and 6 indicates Saturday.
  325.         //
  326.        
  327.         public override DayOfWeek GetDayOfWeek(DateTime time)
  328.         {
  329.             return ((DayOfWeek)((int)(time.Ticks / TicksPerDay + 1) % 7));
  330.         }
  331.        
  332.        
  333.         // This is copied from the generic implementation of Calendar.cs. The generic implementation is not good enough
  334.         // in the case of FristFullWeek and FirstFourDayWeek since it needs the data for B.C. year 1 near 0001/1/1.
  335.         // We override the generic implementation to handle this special case.
  336.         [System.Runtime.InteropServices.ComVisible(false)]
  337.         public override int GetWeekOfYear(DateTime time, CalendarWeekRule rule, DayOfWeek firstDayOfWeek)
  338.         {
  339.             if ((int)firstDayOfWeek < 0 || (int)firstDayOfWeek > 6) {
  340.                 throw new ArgumentOutOfRangeException("firstDayOfWeek", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), DayOfWeek.Sunday, DayOfWeek.Saturday));
  341.             }
  342.             switch (rule) {
  343.                 case CalendarWeekRule.FirstDay:
  344.                     return (GetFirstDayWeekOfYear(time, (int)firstDayOfWeek));
  345.                 case CalendarWeekRule.FirstFullWeek:
  346.                     return (InternalGetWeekOfYearFullDays(this, time, (int)firstDayOfWeek, 7, 365));
  347.                 case CalendarWeekRule.FirstFourDayWeek:
  348.                     return (InternalGetWeekOfYearFullDays(this, time, (int)firstDayOfWeek, 4, 365));
  349.             }
  350.             throw new ArgumentOutOfRangeException("rule", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), CalendarWeekRule.FirstDay, CalendarWeekRule.FirstFourDayWeek));
  351.            
  352.         }
  353.        
  354.        
  355.        
  356.         // This is copied from the generic implementation of GetWeekOfYearFullDays() in Calendar.cs. The generic implementation is not good enough
  357.         // in the case of FristFullWeek and FirstFourDayWeek since it needs the data for B.C. year 1 near 0001/1/1.
  358.         // We override the generic implementation to handle this special case.
  359.        
  360.         // Parameters
  361.         //
  362.         static internal int InternalGetWeekOfYearFullDays(Calendar cal, DateTime time, int firstDayOfWeek, int fullDays, int daysOfMinYearMinusOne)
  363.         {
  364.             int dayForJan1;
  365.             int offset;
  366.             int day;
  367.            
  368.             int dayOfYear = cal.GetDayOfYear(time) - 1;
  369.             // Make the day of year to be 0-based, so that 1/1 is day 0.
  370.             //
  371.             // Calculate the number of days between the first day of year (1/1) and the first day of the week.
  372.             // This value will be a positive value from 0 ~ 6. We call this value as "offset".
  373.             //
  374.             // If offset is 0, it means that the 1/1 is the start of the first week.
  375.             // Assume the first day of the week is Monday, it will look like this:
  376.             // Sun Mon Tue Wed Thu Fri Sat
  377.             // 12/31 1/1 1/2 1/3 1/4 1/5 1/6
  378.             // +--> First week starts here.
  379.             //
  380.             // If offset is 1, it means that the first day of the week is 1 day ahead of 1/1.
  381.             // Assume the first day of the week is Monday, it will look like this:
  382.             // Sun Mon Tue Wed Thu Fri Sat
  383.             // 1/1 1/2 1/3 1/4 1/5 1/6 1/7
  384.             // +--> First week starts here.
  385.             //
  386.             // If offset is 2, it means that the first day of the week is 2 days ahead of 1/1.
  387.             // Assume the first day of the week is Monday, it will look like this:
  388.             // Sat Sun Mon Tue Wed Thu Fri Sat
  389.             // 1/1 1/2 1/3 1/4 1/5 1/6 1/7 1/8
  390.             // +--> First week starts here.
  391.            
  392.            
  393.             // Day of week is 0-based.
  394.             // Get the day of week for 1/1. This can be derived from the day of week of the target day.
  395.             // Note that we can get a negative value. It's ok since we are going to make it a positive value when calculating the offset.
  396.             dayForJan1 = (int)cal.GetDayOfWeek(time) - (dayOfYear % 7);
  397.            
  398.             // Now, calucalte the offset. Substract the first day of week from the dayForJan1. And make it a positive value.
  399.             offset = (firstDayOfWeek - dayForJan1 + 14) % 7;
  400.             if (offset != 0 && offset >= fullDays) {
  401.                 //
  402.                 // If the offset is greater than the value of fullDays, it means that
  403.                 // the first week of the year starts on the week where Jan/1 falls on.
  404.                 //
  405.                 offset -= 7;
  406.             }
  407.             //
  408.             // Calculate the day of year for specified time by taking offset into account.
  409.             //
  410.             day = dayOfYear - offset;
  411.             if (day >= 0) {
  412.                 //
  413.                 // If the day of year value is greater than zero, get the week of year.
  414.                 //
  415.                 return (day / 7 + 1);
  416.             }
  417.             //
  418.             // Otherwise, the specified time falls on the week of previous year.
  419.             // Note that it is not always week 52 or 53, because it depends on the calendar. Different calendars have different number of days in a year.
  420.             //
  421.            
  422.             // Repeat the previous calculation logic using the previous year and calculate the week of year for the last day of previous year.
  423.             int year = cal.GetYear(time);
  424.             if (year <= cal.GetYear(cal.MinSupportedDateTime)) {
  425.                 // This specified time is in 0001/1/1 ~ 0001/1/7.
  426.                 dayOfYear = daysOfMinYearMinusOne;
  427.             }
  428.             else {
  429.                 dayOfYear = cal.GetDaysInYear(year - 1);
  430.             }
  431.             dayForJan1 = dayForJan1 - (dayOfYear % 7);
  432.             // Now, calucalte the offset. Substract the first day of week from the dayForJan1. And make it a positive value.
  433.             offset = (firstDayOfWeek - dayForJan1 + 14) % 7;
  434.             if (offset != 0 && offset >= fullDays) {
  435.                 //
  436.                 // If the offset is greater than the value of fullDays, it means that
  437.                 // the first week of the year starts on the week where Jan/1 falls on.
  438.                 //
  439.                 offset -= 7;
  440.             }
  441.             //
  442.             // Calculate the day of year for specified time by taking offset into account.
  443.             //
  444.             day = dayOfYear - offset;
  445.             return (day / 7 + 1);
  446.         }
  447.        
  448.        
  449.        
  450.         // Returns the day-of-year part of the specified DateTime. The returned value
  451.         // is an integer between 1 and 366.
  452.         //
  453.        
  454.         public override int GetDayOfYear(DateTime time)
  455.         {
  456.             return (GetDatePart(time.Ticks, DatePartDayOfYear));
  457.         }
  458.        
  459.         // Returns the number of days in the month given by the year and
  460.         // month arguments.
  461.         //
  462.        
  463.         public override int GetDaysInMonth(int year, int month, int era)
  464.         {
  465.             if (era == CurrentEra || era == ADEra) {
  466.                 if (year < 1 || year > MaxYear) {
  467.                     throw new ArgumentOutOfRangeException("year", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), 1, MaxYear));
  468.                 }
  469.                 if (month < 1 || month > 12) {
  470.                     throw new ArgumentOutOfRangeException("month", Environment.GetResourceString("ArgumentOutOfRange_Month"));
  471.                 }
  472.                 int[] days = ((year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? DaysToMonth366 : DaysToMonth365);
  473.                 return (days[month] - days[month - 1]);
  474.             }
  475.             throw new ArgumentOutOfRangeException("era", Environment.GetResourceString("ArgumentOutOfRange_InvalidEraValue"));
  476.         }
  477.        
  478.         // Returns the number of days in the year given by the year argument for the current era.
  479.         //
  480.        
  481.         public override int GetDaysInYear(int year, int era)
  482.         {
  483.             if (era == CurrentEra || era == ADEra) {
  484.                 if (year >= 1 && year <= MaxYear) {
  485.                     return ((year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? 366 : 365);
  486.                 }
  487.                 throw new ArgumentOutOfRangeException("year", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), 1, MaxYear));
  488.             }
  489.             throw new ArgumentOutOfRangeException("era", Environment.GetResourceString("ArgumentOutOfRange_InvalidEraValue"));
  490.         }
  491.        
  492.         // Returns the era for the specified DateTime value.
  493.        
  494.         public override int GetEra(DateTime time)
  495.         {
  496.             return (ADEra);
  497.         }
  498.        
  499.        
  500.         public override int[] Eras {
  501.             get { return (new int[] {ADEra}); }
  502.         }
  503.        
  504.        
  505.         // Returns the month part of the specified DateTime. The returned value is an
  506.         // integer between 1 and 12.
  507.         //
  508.        
  509.         public override int GetMonth(DateTime time)
  510.         {
  511.             return (GetDatePart(time.Ticks, DatePartMonth));
  512.         }
  513.        
  514.         // Returns the number of months in the specified year and era.
  515.        
  516.         public override int GetMonthsInYear(int year, int era)
  517.         {
  518.             if (era == CurrentEra || era == ADEra) {
  519.                 if (year >= 1 && year <= MaxYear) {
  520.                     return (12);
  521.                 }
  522.                 throw new ArgumentOutOfRangeException("year", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), 1, MaxYear));
  523.             }
  524.             throw new ArgumentOutOfRangeException("era", Environment.GetResourceString("ArgumentOutOfRange_InvalidEraValue"));
  525.         }
  526.        
  527.         // Returns the year part of the specified DateTime. The returned value is an
  528.         // integer between 1 and 9999.
  529.         //
  530.        
  531.         public override int GetYear(DateTime time)
  532.         {
  533.             return (GetDatePart(time.Ticks, DatePartYear));
  534.         }
  535.        
  536.         // Checks whether a given day in the specified era is a leap day. This method returns true if
  537.         // the date is a leap day, or false if not.
  538.         //
  539.        
  540.         public override bool IsLeapDay(int year, int month, int day, int era)
  541.         {
  542.             if (era != CurrentEra && era != ADEra) {
  543.                 throw new ArgumentOutOfRangeException("era", Environment.GetResourceString("ArgumentOutOfRange_InvalidEraValue"));
  544.             }
  545.             if (year < 1 || year > MaxYear) {
  546.                 throw new ArgumentOutOfRangeException("year", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), 1, MaxYear));
  547.             }
  548.            
  549.             if (month < 1 || month > 12) {
  550.                 throw new ArgumentOutOfRangeException("month", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), 1, 12));
  551.             }
  552.             if (day < 1 || day > GetDaysInMonth(year, month)) {
  553.                 throw new ArgumentOutOfRangeException("day", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), 1, GetDaysInMonth(year, month)));
  554.             }
  555.             if (!IsLeapYear(year)) {
  556.                 return (false);
  557.             }
  558.             if (month == 2 && day == 29) {
  559.                 return (true);
  560.             }
  561.             return (false);
  562.         }
  563.        
  564.         // Returns the leap month in a calendar year of the specified era. This method returns 0
  565.         // if this calendar does not have leap month, or this year is not a leap year.
  566.         //
  567.        
  568.         [System.Runtime.InteropServices.ComVisible(false)]
  569.         public override int GetLeapMonth(int year, int era)
  570.         {
  571.             if (era != CurrentEra && era != ADEra) {
  572.                 throw new ArgumentOutOfRangeException("era", Environment.GetResourceString("ArgumentOutOfRange_InvalidEraValue"));
  573.             }
  574.             if (year < 1 || year > MaxYear) {
  575.                 throw new ArgumentOutOfRangeException("year", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), 1, MaxYear));
  576.             }
  577.             return (0);
  578.         }
  579.        
  580.         // Checks whether a given month in the specified era is a leap month. This method returns true if
  581.         // month is a leap month, or false if not.
  582.         //
  583.        
  584.         public override bool IsLeapMonth(int year, int month, int era)
  585.         {
  586.             if (era != CurrentEra && era != ADEra) {
  587.                 throw new ArgumentOutOfRangeException("era", Environment.GetResourceString("ArgumentOutOfRange_InvalidEraValue"));
  588.             }
  589.            
  590.             if (year < 1 || year > MaxYear) {
  591.                 throw new ArgumentOutOfRangeException("year", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), 1, MaxYear));
  592.             }
  593.            
  594.             if (month < 1 || month > 12) {
  595.                 throw new ArgumentOutOfRangeException("month", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), 1, 12));
  596.             }
  597.             return (false);
  598.            
  599.         }
  600.        
  601.         // Checks whether a given year in the specified era is a leap year. This method returns true if
  602.         // year is a leap year, or false if not.
  603.         //
  604.        
  605.         public override bool IsLeapYear(int year, int era)
  606.         {
  607.             if (era == CurrentEra || era == ADEra) {
  608.                 if (year >= 1 && year <= MaxYear) {
  609.                     return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
  610.                 }
  611.                
  612.                 throw new ArgumentOutOfRangeException("year", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), 1, MaxYear));
  613.             }
  614.             throw new ArgumentOutOfRangeException("era", Environment.GetResourceString("ArgumentOutOfRange_InvalidEraValue"));
  615.         }
  616.        
  617.         // Returns the date and time converted to a DateTime value. Throws an exception if the n-tuple is invalid.
  618.         //
  619.        
  620.         public override DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era)
  621.         {
  622.             if (era == CurrentEra || era == ADEra) {
  623.                 return new DateTime(year, month, day, hour, minute, second, millisecond);
  624.             }
  625.             throw new ArgumentOutOfRangeException("era", Environment.GetResourceString("ArgumentOutOfRange_InvalidEraValue"));
  626.         }
  627.        
  628.         internal override bool TryToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era, out DateTime result)
  629.         {
  630.             if (era == CurrentEra || era == ADEra) {
  631.                 return DateTime.TryCreate(year, month, day, hour, minute, second, millisecond, out result);
  632.             }
  633.             result = DateTime.MinValue;
  634.             return false;
  635.         }
  636.        
  637.         private const int DEFAULT_TWO_DIGIT_YEAR_MAX = 2029;
  638.        
  639.        
  640.         public override int TwoDigitYearMax {
  641.             get {
  642.                 if (twoDigitYearMax == -1) {
  643.                     twoDigitYearMax = GetSystemTwoDigitYearSetting(ID, DEFAULT_TWO_DIGIT_YEAR_MAX);
  644.                 }
  645.                 return (twoDigitYearMax);
  646.             }
  647.            
  648.             set {
  649.                 VerifyWritable();
  650.                 if (value < 99 || value > MaxYear) {
  651.                     throw new ArgumentOutOfRangeException("year", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), 99, MaxYear));
  652.                    
  653.                 }
  654.                 twoDigitYearMax = value;
  655.             }
  656.         }
  657.        
  658.        
  659.         public override int ToFourDigitYear(int year)
  660.         {
  661.             if (year > MaxYear) {
  662.                 throw new ArgumentOutOfRangeException("year", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), 1, MaxYear));
  663.             }
  664.             return (base.ToFourDigitYear(year));
  665.         }
  666.     }
  667. }

Developer Fusion