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

  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.     using System;
  18.    
  19.     ////////////////////////////////////////////////////////////////////////////
  20.     //
  21.     // Notes about EastAsianLunisolarCalendar
  22.     //
  23.     ////////////////////////////////////////////////////////////////////////////
  24.    
  25.    
  26.     [Serializable()]
  27.     [System.Runtime.InteropServices.ComVisible(true)]
  28.     public abstract class EastAsianLunisolarCalendar : Calendar
  29.     {
  30.         internal const int LeapMonth = 0;
  31.         internal const int Jan1Month = 1;
  32.         internal const int Jan1Date = 2;
  33.         internal const int nDaysPerMonth = 3;
  34.        
  35.         // # of days so far in the solar year
  36.         static internal readonly int[] DaysToMonth365 = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273,
  37.         304, 334};
  38.        
  39.         static internal readonly int[] DaysToMonth366 = {0, 31, 60, 91, 121, 152, 182, 213, 244, 274,
  40.         305, 335};
  41.        
  42.         internal const int DatePartYear = 0;
  43.         internal const int DatePartDayOfYear = 1;
  44.         internal const int DatePartMonth = 2;
  45.         internal const int DatePartDay = 3;
  46.        
  47.         // Return the type of the East Asian Lunisolar calendars.
  48.         //
  49.        
  50.         public override CalendarAlgorithmType AlgorithmType {
  51.             get { return CalendarAlgorithmType.LunisolarCalendar; }
  52.         }
  53.        
  54.         // Return the year number in the 60-year cycle.
  55.         //
  56.        
  57.         public virtual int GetSexagenaryYear(DateTime time)
  58.         {
  59.             CheckTicksRange(time.Ticks);
  60.            
  61.             int year = 0;
  62.             int month = 0;
  63.             int day = 0;
  64.             TimeToLunar(time, ref year, ref month, ref day);
  65.            
  66.             return ((year - 4) % 60) + 1;
  67.         }
  68.        
  69.         // Return the celestial year from the 60-year cycle.
  70.         // The returned value is from 1 ~ 10.
  71.         //
  72.        
  73.         public int GetCelestialStem(int sexagenaryYear)
  74.         {
  75.             if ((sexagenaryYear < 1) || (sexagenaryYear > 60)) {
  76.                 throw new ArgumentOutOfRangeException("sexagenaryYear", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), 1, 60));
  77.             }
  78.            
  79.             return ((sexagenaryYear - 1) % 10) + 1;
  80.         }
  81.        
  82.         // Return the Terrestial Branch from the the 60-year cycle.
  83.         // The returned value is from 1 ~ 12.
  84.         //
  85.        
  86.         public int GetTerrestrialBranch(int sexagenaryYear)
  87.         {
  88.             if ((sexagenaryYear < 1) || (sexagenaryYear > 60)) {
  89.                 throw new ArgumentOutOfRangeException("sexagenaryYear", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), 1, 60));
  90.             }
  91.            
  92.             return ((sexagenaryYear - 1) % 12) + 1;
  93.         }
  94.        
  95.         internal abstract int GetYearInfo(int LunarYear, int Index);
  96.         internal abstract int GetYear(int year, DateTime time);
  97.         internal abstract int GetGregorianYear(int year, int era);
  98.        
  99.         internal abstract int MinCalendarYear {
  100.             get;
  101.         }
  102.         internal abstract int MaxCalendarYear {
  103.             get;
  104.         }
  105.         internal abstract EraInfo[] CalEraInfo {
  106.             get;
  107.         }
  108.         internal abstract DateTime MinDate {
  109.             get;
  110.         }
  111.         internal abstract DateTime MaxDate {
  112.             get;
  113.         }
  114.        
  115.         internal const int MaxCalendarMonth = 13;
  116.         internal const int MaxCalendarDay = 30;
  117.        
  118.         internal int MinEraCalendarYear(int era)
  119.         {
  120.             EraInfo[] mEraInfo = CalEraInfo;
  121.             //ChineseLunisolarCalendar does not has m_EraInfo it is going to retuen null
  122.             if (mEraInfo == null) {
  123.                 return MinCalendarYear;
  124.             }
  125.            
  126.             if (era == Calendar.CurrentEra) {
  127.                 era = CurrentEraValue;
  128.             }
  129.             //era has to be in the supported range otherwise we will throw exception in CheckEraRange()
  130.             if (era == GetEra(MinDate)) {
  131.                 return (GetYear(MinCalendarYear, MinDate));
  132.             }
  133.            
  134.             for (int i = 0; i < mEraInfo.Length; i++) {
  135.                 if (era == mEraInfo[i].era) {
  136.                     return (mEraInfo[i].minEraYear);
  137.                 }
  138.             }
  139.             throw new ArgumentOutOfRangeException("era", Environment.GetResourceString("ArgumentOutOfRange_InvalidEraValue"));
  140.         }
  141.        
  142.         internal int MaxEraCalendarYear(int era)
  143.         {
  144.             EraInfo[] mEraInfo = CalEraInfo;
  145.             //ChineseLunisolarCalendar does not has m_EraInfo it is going to retuen null
  146.             if (mEraInfo == null) {
  147.                 return MaxCalendarYear;
  148.             }
  149.            
  150.             if (era == Calendar.CurrentEra) {
  151.                 era = CurrentEraValue;
  152.             }
  153.             //era has to be in the supported range otherwise we will throw exception in CheckEraRange()
  154.             if (era == GetEra(MaxDate)) {
  155.                 return (GetYear(MaxCalendarYear, MaxDate));
  156.             }
  157.            
  158.             for (int i = 0; i < mEraInfo.Length; i++) {
  159.                 if (era == mEraInfo[i].era) {
  160.                     return (mEraInfo[i].maxEraYear);
  161.                 }
  162.             }
  163.             throw new ArgumentOutOfRangeException("era", Environment.GetResourceString("ArgumentOutOfRange_InvalidEraValue"));
  164.         }
  165.        
  166.         // Construct an instance of EastAsianLunisolar calendar.
  167.        
  168.         internal EastAsianLunisolarCalendar()
  169.         {
  170.         }
  171.        
  172.         internal void CheckTicksRange(long ticks)
  173.         {
  174.             if (ticks < MinSupportedDateTime.Ticks || ticks > MaxSupportedDateTime.Ticks) {
  175.                 throw new ArgumentOutOfRangeException("time", String.Format(CultureInfo.InvariantCulture, Environment.GetResourceString("ArgumentOutOfRange_CalendarRange"), MinSupportedDateTime, MaxSupportedDateTime));
  176.             }
  177.         }
  178.        
  179.         internal void CheckEraRange(int era)
  180.         {
  181.             if (era == Calendar.CurrentEra) {
  182.                 era = CurrentEraValue;
  183.             }
  184.            
  185.             if ((era < GetEra(MinDate)) || (era > GetEra(MaxDate))) {
  186.                 throw new ArgumentOutOfRangeException("era", Environment.GetResourceString("ArgumentOutOfRange_InvalidEraValue"));
  187.             }
  188.         }
  189.        
  190.         internal int CheckYearRange(int year, int era)
  191.         {
  192.             CheckEraRange(era);
  193.             year = GetGregorianYear(year, era);
  194.            
  195.             if ((year < MinCalendarYear) || (year > MaxCalendarYear)) {
  196.                 throw new ArgumentOutOfRangeException("year", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), MinEraCalendarYear(era), MaxEraCalendarYear(era)));
  197.             }
  198.             return year;
  199.         }
  200.        
  201.         internal int CheckYearMonthRange(int year, int month, int era)
  202.         {
  203.             year = CheckYearRange(year, era);
  204.            
  205.             if (month == 13) {
  206.                 //Reject if there is no leap month this year
  207.                 if (GetYearInfo(year, LeapMonth) == 0)
  208.                     throw new ArgumentOutOfRangeException("month", Environment.GetResourceString("ArgumentOutOfRange_Month"));
  209.             }
  210.            
  211.             if (month < 1 || month > 13) {
  212.                 throw new ArgumentOutOfRangeException("month", Environment.GetResourceString("ArgumentOutOfRange_Month"));
  213.             }
  214.             return year;
  215.         }
  216.        
  217.         internal int InternalGetDaysInMonth(int year, int month)
  218.         {
  219.             int nDays;
  220.             int mask;
  221.             // mask for extracting bits
  222.             mask = 32768;
  223.             // convert the lunar day into a lunar month/date
  224.             mask >>= (month - 1);
  225.             if ((GetYearInfo(year, nDaysPerMonth) & mask) == 0)
  226.                 nDays = 29;
  227.             else
  228.                 nDays = 30;
  229.             return nDays;
  230.         }
  231.        
  232.         // Returns the number of days in the month given by the year and
  233.         // month arguments.
  234.         //
  235.        
  236.         public override int GetDaysInMonth(int year, int month, int era)
  237.         {
  238.             year = CheckYearMonthRange(year, month, era);
  239.             return InternalGetDaysInMonth(year, month);
  240.         }
  241.        
  242.         internal int GergIsleap(int y)
  243.         {
  244.             return ((((y) % 4) != 0) ? 0 : ((((y) % 100) != 0) ? 1 : ((((y) % 400) != 0) ? 0 : 1)));
  245.         }
  246.        
  247.         // Returns the date and time converted to a DateTime value. Throws an exception if the n-tuple is invalid.
  248.         //
  249.        
  250.         public override DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era)
  251.         {
  252.             year = CheckYearMonthRange(year, month, era);
  253.             int daysInMonth = InternalGetDaysInMonth(year, month);
  254.             if (day < 1 || day > daysInMonth) {
  255.                 BCLDebug.Log("year = " + year + ", month = " + month + ", day = " + day);
  256.                 throw new ArgumentOutOfRangeException("day", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Day"), daysInMonth, month));
  257.             }
  258.            
  259.             int gy = 0;
  260.             int gm = 0;
  261.             int gd = 0;
  262.            
  263.             if (LunarToGregorian(year, month, day, ref gy, ref gm, ref gd)) {
  264.                 return new DateTime(gy, gm, gd, hour, minute, second, millisecond);
  265.             }
  266.             else {
  267.                 throw new ArgumentOutOfRangeException(null, Environment.GetResourceString("ArgumentOutOfRange_BadYearMonthDay"));
  268.             }
  269.         }
  270.        
  271.        
  272.         //
  273.         // GregorianToLunar calculates lunar calendar info for the given gregorian year, month, date.
  274.         // The input date should be validated before calling this method.
  275.         //
  276.         internal void GregorianToLunar(int nSYear, int nSMonth, int nSDate, ref int nLYear, ref int nLMonth, ref int nLDate)
  277.         {
  278.             // unsigned int nLYear, nLMonth, nLDate; // lunar ymd
  279.             int nSolarDay;
  280.             // day # in solar year
  281.             int nLunarDay;
  282.             // day # in lunar year
  283.             int fLeap;
  284.             // is it a solar leap year?
  285.             int LDpM;
  286.             // lunar days/month bitfield
  287.             int mask;
  288.             // mask for extracting bits
  289.             int nDays;
  290.             // # days this lunar month
  291.             int nJan1Month;
  292.             int nJan1Date;
  293.            
  294.             // calc the solar day of year
  295.             fLeap = GergIsleap(nSYear);
  296.             nSolarDay = (fLeap == 1) ? DaysToMonth366[nSMonth - 1] : DaysToMonth365[nSMonth - 1];
  297.             nSolarDay += nSDate;
  298.            
  299.             // init lunar year info
  300.             nLunarDay = nSolarDay;
  301.             nLYear = nSYear;
  302.             if (nLYear == (MaxCalendarYear + 1)) {
  303.                 nLYear--;
  304.                 nLunarDay += ((GergIsleap(nLYear) == 1) ? 366 : 365);
  305.                 nJan1Month = GetYearInfo(nLYear, Jan1Month);
  306.                 nJan1Date = GetYearInfo(nLYear, Jan1Date);
  307.             }
  308.             else {
  309.                
  310.                 nJan1Month = GetYearInfo(nLYear, Jan1Month);
  311.                 nJan1Date = GetYearInfo(nLYear, Jan1Date);
  312.                
  313.                 // check if this solar date is actually part of the previous
  314.                 // lunar year
  315.                 if ((nSMonth < nJan1Month) || (nSMonth == nJan1Month && nSDate < nJan1Date)) {
  316.                     // the corresponding lunar day is actually part of the previous
  317.                     // lunar year
  318.                     nLYear--;
  319.                    
  320.                     // add a solar year to the lunar day #
  321.                     nLunarDay += ((GergIsleap(nLYear) == 1) ? 366 : 365);
  322.                    
  323.                     // update the new start of year
  324.                     nJan1Month = GetYearInfo(nLYear, Jan1Month);
  325.                     nJan1Date = GetYearInfo(nLYear, Jan1Date);
  326.                 }
  327.             }
  328.            
  329.             // convert solar day into lunar day.
  330.             // subtract off the beginning part of the solar year which is not
  331.             // part of the lunar year. since this part is always in Jan or Feb,
  332.             // we don't need to handle Leap Year (LY only affects March
  333.             // and later).
  334.             nLunarDay -= DaysToMonth365[nJan1Month - 1];
  335.             nLunarDay -= (nJan1Date - 1);
  336.            
  337.             // convert the lunar day into a lunar month/date
  338.             mask = 32768;
  339.             LDpM = GetYearInfo(nLYear, nDaysPerMonth);
  340.             nDays = ((LDpM & mask) != 0) ? 30 : 29;
  341.             nLMonth = 1;
  342.             while (nLunarDay > nDays) {
  343.                 nLunarDay -= nDays;
  344.                 nLMonth++;
  345.                 mask >>= 1;
  346.                 nDays = ((LDpM & mask) != 0) ? 30 : 29;
  347.             }
  348.             nLDate = nLunarDay;
  349.         }
  350.        
  351. /*
  352.         //Convert from Lunar to Gregorian
  353.         //Highly inefficient, but it works based on the forward conversion
  354.         */       
  355.         internal bool LunarToGregorian(int nLYear, int nLMonth, int nLDate, ref int nSolarYear, ref int nSolarMonth, ref int nSolarDay)
  356.         {
  357.             int numLunarDays;
  358.            
  359.             if (nLDate < 1 || nLDate > 30)
  360.                 return false;
  361.            
  362.             numLunarDays = nLDate - 1;
  363.            
  364.             //Add previous months days to form the total num of days from the first of the month.
  365.             for (int i = 1; i < nLMonth; i++) {
  366.                 numLunarDays += InternalGetDaysInMonth(nLYear, i);
  367.             }
  368.            
  369.             //Get Gregorian First of year
  370.             int nJan1Month = GetYearInfo(nLYear, Jan1Month);
  371.             int nJan1Date = GetYearInfo(nLYear, Jan1Date);
  372.            
  373.             // calc the solar day of year of 1 Lunar day
  374.             int fLeap = GergIsleap(nLYear);
  375.             int[] days = (fLeap == 1) ? DaysToMonth366 : DaysToMonth365;
  376.            
  377.             nSolarDay = nJan1Date;
  378.            
  379.             if (nJan1Month > 1)
  380.                 nSolarDay += days[nJan1Month - 1];
  381.            
  382.             // Add the actual lunar day to get the solar day we want
  383.             nSolarDay = nSolarDay + numLunarDays;
  384.             // - 1;
  385.             if (nSolarDay > (fLeap + 365)) {
  386.                 nSolarYear = nLYear + 1;
  387.                 nSolarDay -= (fLeap + 365);
  388.             }
  389.             else {
  390.                 nSolarYear = nLYear;
  391.             }
  392.            
  393.             for (nSolarMonth = 1; nSolarMonth < 12; nSolarMonth++) {
  394.                 if (days[nSolarMonth] >= nSolarDay)
  395.                     break;
  396.             }
  397.            
  398.             nSolarDay -= days[nSolarMonth - 1];
  399.             return true;
  400.         }
  401.        
  402.         internal DateTime LunarToTime(DateTime time, int year, int month, int day)
  403.         {
  404.             int gy = 0;
  405.             int gm = 0;
  406.             int gd = 0;
  407.             LunarToGregorian(year, month, day, ref gy, ref gm, ref gd);
  408.             return (GregorianCalendar.GetDefaultInstance().ToDateTime(gy, gm, gd, time.Hour, time.Minute, time.Second, time.Millisecond));
  409.         }
  410.        
  411.         internal void TimeToLunar(DateTime time, ref int year, ref int month, ref int day)
  412.         {
  413.             int gy = 0;
  414.             int gm = 0;
  415.             int gd = 0;
  416.            
  417.             Calendar Greg = GregorianCalendar.GetDefaultInstance();
  418.             gy = Greg.GetYear(time);
  419.             gm = Greg.GetMonth(time);
  420.             gd = Greg.GetDayOfMonth(time);
  421.            
  422.             GregorianToLunar(gy, gm, gd, ref year, ref month, ref day);
  423.         }
  424.        
  425.         // Returns the DateTime resulting from adding the given number of
  426.         // months to the specified DateTime. The result is computed by incrementing
  427.         // (or decrementing) the year and month parts of the specified DateTime by
  428.         // value months, and, if required, adjusting the day part of the
  429.         // resulting date downwards to the last day of the resulting month in the
  430.         // resulting year. The time-of-day part of the result is the same as the
  431.         // time-of-day part of the specified DateTime.
  432.         //
  433.        
  434.         public override DateTime AddMonths(DateTime time, int months)
  435.         {
  436.             if (months < -120000 || months > 120000) {
  437.                 throw new ArgumentOutOfRangeException("months", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), -120000, 120000));
  438.             }
  439.            
  440.             CheckTicksRange(time.Ticks);
  441.            
  442.             int y = 0;
  443.             int m = 0;
  444.             int d = 0;
  445.             TimeToLunar(time, ref y, ref m, ref d);
  446.            
  447.             int i = m + months;
  448.             if (i > 0) {
  449.                 int monthsInYear = InternalIsLeapYear(y) ? 13 : 12;
  450.                
  451.                 while (i - monthsInYear > 0) {
  452.                     i -= monthsInYear;
  453.                     y++;
  454.                     monthsInYear = InternalIsLeapYear(y) ? 13 : 12;
  455.                 }
  456.                 m = i;
  457.             }
  458.             else {
  459.                 int monthsInYear;
  460.                 while (i <= 0) {
  461.                     monthsInYear = InternalIsLeapYear(y - 1) ? 13 : 12;
  462.                     i += monthsInYear;
  463.                     y--;
  464.                 }
  465.                 m = i;
  466.             }
  467.            
  468.             int days = InternalGetDaysInMonth(y, m);
  469.             if (d > days) {
  470.                 d = days;
  471.             }
  472.             DateTime dt = LunarToTime(time, y, m, d);
  473.            
  474.             CheckAddResult(dt.Ticks, MinSupportedDateTime, MaxSupportedDateTime);
  475.             return (dt);
  476.         }
  477.        
  478.        
  479.         public override DateTime AddYears(DateTime time, int years)
  480.         {
  481.             CheckTicksRange(time.Ticks);
  482.            
  483.             int y = 0;
  484.             int m = 0;
  485.             int d = 0;
  486.             TimeToLunar(time, ref y, ref m, ref d);
  487.            
  488.             y += years;
  489.            
  490.             if (m == 13 && !InternalIsLeapYear(y)) {
  491.                 m = 12;
  492.                 d = InternalGetDaysInMonth(y, m);
  493.             }
  494.             int DaysInMonths = InternalGetDaysInMonth(y, m);
  495.             if (d > DaysInMonths) {
  496.                 d = DaysInMonths;
  497.             }
  498.            
  499.             DateTime dt = LunarToTime(time, y, m, d);
  500.             CheckAddResult(dt.Ticks, MinSupportedDateTime, MaxSupportedDateTime);
  501.             return (dt);
  502.         }
  503.        
  504.         // Returns the day-of-year part of the specified DateTime. The returned value
  505.         // is an integer between 1 and [354|355 |383|384].
  506.         //
  507.        
  508.         public override int GetDayOfYear(DateTime time)
  509.         {
  510.             CheckTicksRange(time.Ticks);
  511.            
  512.             int y = 0;
  513.             int m = 0;
  514.             int d = 0;
  515.             TimeToLunar(time, ref y, ref m, ref d);
  516.            
  517.             for (int i = 1; i < m; i++) {
  518.                 d = d + InternalGetDaysInMonth(y, i);
  519.             }
  520.             return d;
  521.         }
  522.        
  523.         // Returns the day-of-month part of the specified DateTime. The returned
  524.         // value is an integer between 1 and 29 or 30.
  525.         //
  526.        
  527.         public override int GetDayOfMonth(DateTime time)
  528.         {
  529.             CheckTicksRange(time.Ticks);
  530.            
  531.             int y = 0;
  532.             int m = 0;
  533.             int d = 0;
  534.             TimeToLunar(time, ref y, ref m, ref d);
  535.            
  536.             return d;
  537.         }
  538.        
  539.         // Returns the number of days in the year given by the year argument for the current era.
  540.         //
  541.        
  542.         public override int GetDaysInYear(int year, int era)
  543.         {
  544.             year = CheckYearRange(year, era);
  545.            
  546.             int Days = 0;
  547.             int monthsInYear = InternalIsLeapYear(year) ? 13 : 12;
  548.            
  549.             while (monthsInYear != 0)
  550.                 Days += InternalGetDaysInMonth(year, monthsInYear--);
  551.            
  552.             return Days;
  553.         }
  554.        
  555.         // Returns the month part of the specified DateTime. The returned value is an
  556.         // integer between 1 and 13.
  557.         //
  558.        
  559.         public override int GetMonth(DateTime time)
  560.         {
  561.             CheckTicksRange(time.Ticks);
  562.            
  563.             int y = 0;
  564.             int m = 0;
  565.             int d = 0;
  566.             TimeToLunar(time, ref y, ref m, ref d);
  567.            
  568.             return m;
  569.         }
  570.        
  571.         // Returns the year part of the specified DateTime. The returned value is an
  572.         // integer between 1 and MaxCalendarYear.
  573.         //
  574.        
  575.         public override int GetYear(DateTime time)
  576.         {
  577.             CheckTicksRange(time.Ticks);
  578.            
  579.             int y = 0;
  580.             int m = 0;
  581.             int d = 0;
  582.             TimeToLunar(time, ref y, ref m, ref d);
  583.            
  584.             return GetYear(y, time);
  585.         }
  586.        
  587.         // Returns the day-of-week part of the specified DateTime. The returned value
  588.         // is an integer between 0 and 6, where 0 indicates Sunday, 1 indicates
  589.         // Monday, 2 indicates Tuesday, 3 indicates Wednesday, 4 indicates
  590.         // Thursday, 5 indicates Friday, and 6 indicates Saturday.
  591.         //
  592.        
  593.         public override DayOfWeek GetDayOfWeek(DateTime time)
  594.         {
  595.             CheckTicksRange(time.Ticks);
  596.             return ((DayOfWeek)((int)(time.Ticks / Calendar.TicksPerDay + 1) % 7));
  597.         }
  598.        
  599.         // Returns the number of months in the specified year and era.
  600.        
  601.         public override int GetMonthsInYear(int year, int era)
  602.         {
  603.             year = CheckYearRange(year, era);
  604.             return (InternalIsLeapYear(year) ? 13 : 12);
  605.         }
  606.        
  607.         // Checks whether a given day in the specified era is a leap day. This method returns true if
  608.         // the date is a leap day, or false if not.
  609.         //
  610.        
  611.         public override bool IsLeapDay(int year, int month, int day, int era)
  612.         {
  613.             year = CheckYearMonthRange(year, month, era);
  614.             int daysInMonth = InternalGetDaysInMonth(year, month);
  615.            
  616.             if (day < 1 || day > daysInMonth) {
  617.                 throw new ArgumentOutOfRangeException("day", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Day"), daysInMonth, month));
  618.             }
  619.             int m = GetYearInfo(year, LeapMonth);
  620.             return ((m != 0) && (month == (m + 1)));
  621.         }
  622.        
  623.         // Checks whether a given month in the specified era is a leap month. This method returns true if
  624.         // month is a leap month, or false if not.
  625.         //
  626.        
  627.         public override bool IsLeapMonth(int year, int month, int era)
  628.         {
  629.             year = CheckYearMonthRange(year, month, era);
  630.             int m = GetYearInfo(year, LeapMonth);
  631.             return ((m != 0) && (month == (m + 1)));
  632.         }
  633.        
  634.         // Returns the leap month in a calendar year of the specified era. This method returns 0
  635.         // if this this year is not a leap year.
  636.         //
  637.        
  638.         public override int GetLeapMonth(int year, int era)
  639.         {
  640.             year = CheckYearRange(year, era);
  641.             int month = GetYearInfo(year, LeapMonth);
  642.             if (month > 0) {
  643.                 return (month + 1);
  644.             }
  645.             return 0;
  646.         }
  647.        
  648.         internal bool InternalIsLeapYear(int year)
  649.         {
  650.             return (GetYearInfo(year, LeapMonth) != 0);
  651.         }
  652.         // Checks whether a given year in the specified era is a leap year. This method returns true if
  653.         // year is a leap year, or false if not.
  654.         //
  655.        
  656.         public override bool IsLeapYear(int year, int era)
  657.         {
  658.             year = CheckYearRange(year, era);
  659.             return InternalIsLeapYear(year);
  660.         }
  661.        
  662.         private const int DEFAULT_GREGORIAN_TWO_DIGIT_YEAR_MAX = 2029;
  663.        
  664.        
  665.         public override int TwoDigitYearMax {
  666.             get {
  667.                 if (twoDigitYearMax == -1) {
  668.                     twoDigitYearMax = GetSystemTwoDigitYearSetting(BaseCalendarID, GetYear(new DateTime(DEFAULT_GREGORIAN_TWO_DIGIT_YEAR_MAX, 1, 1)));
  669.                 }
  670.                 return (twoDigitYearMax);
  671.             }
  672.            
  673.             set {
  674.                 VerifyWritable();
  675.                 if (value < 99 || value > MaxCalendarYear) {
  676.                     throw new ArgumentOutOfRangeException("value", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), 99, MaxCalendarYear));
  677.                 }
  678.                 twoDigitYearMax = value;
  679.             }
  680.         }
  681.        
  682.        
  683.         public override int ToFourDigitYear(int year)
  684.         {
  685.            
  686.             year = base.ToFourDigitYear(year);
  687.             CheckYearRange(year, CurrentEra);
  688.             return (year);
  689.         }
  690.        
  691.     }
  692. }

Developer Fusion