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

  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.Threading;
  18.     using System;
  19. /*=================================EraInfo==========================
  20.     **
  21.     ** This is the structure to store information about an era.
  22.     **
  23.     ============================================================================*/   
  24.    
  25.     [Serializable()]
  26.     internal class EraInfo
  27.     {
  28.         internal int era;
  29.         // The value of the era.
  30.         internal long ticks;
  31.         // The time in ticks when the era starts
  32.         internal int yearOffset;
  33.         // The offset to Gregorian year when the era starts.
  34.         // Gregorian Year = Era Year + yearOffset
  35.         // Era Year = Gregorian Year - yearOffset
  36.         internal int minEraYear;
  37.         // Min year value in this era. Generally, this value is 1, but this may
  38.         // be affected by the DateTime.MinValue;
  39.         internal int maxEraYear;
  40.         // Max year value in this era. (== the year length of the era + 1)
  41.         internal EraInfo(int era, long ticks, int yearOffset, int minEraYear, int maxEraYear)
  42.         {
  43.             this.era = era;
  44.             this.ticks = ticks;
  45.             this.yearOffset = yearOffset;
  46.             this.minEraYear = minEraYear;
  47.             this.maxEraYear = maxEraYear;
  48.         }
  49.     }
  50.    
  51.     //
  52.     // This class implements the Gregorian calendar. In 1582, Pope Gregory XIII made
  53.     // minor changes to the solar Julian or "Old Style" calendar to make it more
  54.     // accurate. Thus the calendar became known as the Gregorian or "New Style"
  55.     // calendar, and adopted in Catholic countries such as Spain and France. Later
  56.     // the Gregorian calendar became popular throughout Western Europe because it
  57.     // was accurate and convenient for international trade. Scandinavian countries
  58.     // adopted it in 1700, Great Britain in 1752, the American colonies in 1752 and
  59.     // India in 1757. China adopted the same calendar in 1911, Russia in 1918, and
  60.     // some Eastern European countries as late as 1940.
  61.     //
  62.     // This calendar recognizes two era values:
  63.     // 0 CurrentEra (AD)
  64.     // 1 BeforeCurrentEra (BC)
  65.     [Serializable()]
  66.     internal class GregorianCalendarHelper
  67.     {
  68.        
  69.         // 1 tick = 100ns = 10E-7 second
  70.         // Number of ticks per time unit
  71.         internal const long TicksPerMillisecond = 10000;
  72.         internal const long TicksPerSecond = TicksPerMillisecond * 1000;
  73.         internal const long TicksPerMinute = TicksPerSecond * 60;
  74.         internal const long TicksPerHour = TicksPerMinute * 60;
  75.         internal const long TicksPerDay = TicksPerHour * 24;
  76.        
  77.         // Number of milliseconds per time unit
  78.         internal const int MillisPerSecond = 1000;
  79.         internal const int MillisPerMinute = MillisPerSecond * 60;
  80.         internal const int MillisPerHour = MillisPerMinute * 60;
  81.         internal const int MillisPerDay = MillisPerHour * 24;
  82.        
  83.         // Number of days in a non-leap year
  84.         internal const int DaysPerYear = 365;
  85.         // Number of days in 4 years
  86.         internal const int DaysPer4Years = DaysPerYear * 4 + 1;
  87.         // Number of days in 100 years
  88.         internal const int DaysPer100Years = DaysPer4Years * 25 - 1;
  89.         // Number of days in 400 years
  90.         internal const int DaysPer400Years = DaysPer100Years * 4 + 1;
  91.        
  92.         // Number of days from 1/1/0001 to 1/1/10000
  93.         internal const int DaysTo10000 = DaysPer400Years * 25 - 366;
  94.        
  95.         internal const long MaxMillis = (long)DaysTo10000 * MillisPerDay;
  96.        
  97.         internal const int DatePartYear = 0;
  98.         internal const int DatePartDayOfYear = 1;
  99.         internal const int DatePartMonth = 2;
  100.         internal const int DatePartDay = 3;
  101.        
  102.         //
  103.         // This is the max Gregorian year can be represented by DateTime class. The limitation
  104.         // is derived from DateTime class.
  105.         //
  106.         internal int MaxYear {
  107.             get { return (m_maxYear); }
  108.         }
  109.        
  110.         static internal readonly int[] DaysToMonth365 = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273,
  111.         304, 334, 365};
  112.        
  113.         static internal readonly int[] DaysToMonth366 = {0, 31, 60, 91, 121, 152, 182, 213, 244, 274,
  114.         305, 335, 366};
  115.        
  116.         internal int m_maxYear = 9999;
  117.         internal int m_minYear;
  118.         internal Calendar m_Cal;
  119.         internal EraInfo[] m_EraInfo;
  120.         internal int[] m_eras = null;
  121.        
  122.         // m_minDate is existing here just to keep the serialization compatibility.
  123.         // it has nothing to do with the code anymore.
  124.         internal DateTime m_minDate;
  125.        
  126. /*=================================InitEraInfo==========================
  127.         **Action: Get the era range information from calendar.nlp.
  128.         **Returns: An array of EraInfo, which contains the information about an era.
  129.         **Arguments:
  130.         **      calID    the Calendar ID defined in Calendar.cs
  131.         ============================================================================*/       
  132.         static internal EraInfo[] InitEraInfo(int calID)
  133.         {
  134.             //
  135.             // Initialize era information.
  136.             //
  137.            
  138.             /*
  139.             Japaense era info example:
  140.             eraInfo[0] = new EraInfo(4, new DateTime(1989, 1, 8).Ticks, 1988, 1, GregorianCalendar.MaxYear - 1988);    // Heisei. Most recent
  141.             eraInfo[1] = new EraInfo(3, new DateTime(1926, 12, 25).Ticks, 1925, 1, 1989 - 1925);  // Showa
  142.             eraInfo[2] = new EraInfo(2, new DateTime(1912, 7, 30).Ticks, 1911, 1, 1926 - 1911);  // Taisho
  143.             eraInfo[3] = new EraInfo(1, new DateTime(1868, 9, 8).Ticks, 1867, 1, 1912 - 1867);    // Meiji           
  144.             */           
  145. BCLDebug.Assert(calID > 0, "[GregorianCalendarHelper.InitEraInfo] Expected calID > 0");
  146.             int[][] eraRanges = CalendarTable.Default.SERARANGES(calID);
  147.             EraInfo[] eraInfo = new EraInfo[eraRanges.Length];
  148.             int maxEraYear = GregorianCalendar.MaxYear;
  149.             for (int i = 0; i < eraRanges.Length; i++) {
  150.                 //
  151.                 // The eraRange arrays are each the form of "4 1989 1 8 1988 1".
  152.                 // eraRanges[i][0] is the era value.
  153.                 // eraRanges[i][1] is the year when the era starts.
  154.                 // eraRanges[i][2] is the month when the era starts.
  155.                 // eraRanges[i][3] is the day when the era starts.
  156.                 // eraRanges[i][4] is the offset to Gregorian year (1988).
  157.                 // eraRanges[i][5] is the minimum era year for this era.
  158.                 //
  159.                 BCLDebug.Assert(eraRanges[i].Length == 6, "[GregorianCalendarHelper.InitEraInfo] Expected 6 SERARANGE elements (0-5), not " + eraRanges[i].Length);
  160.                 eraInfo[i] = new EraInfo(eraRanges[i][0], new DateTime(eraRanges[i][1], eraRanges[i][2], eraRanges[i][3]).Ticks, eraRanges[i][4], eraRanges[i][5], maxEraYear - eraRanges[i][4]);
  161.                 maxEraYear = eraRanges[i][1];
  162.             }
  163.             return (eraInfo);
  164.         }
  165.        
  166.         // Construct an instance of gregorian calendar.
  167.         internal GregorianCalendarHelper(Calendar cal, EraInfo[] eraInfo)
  168.         {
  169.             m_Cal = cal;
  170.             m_EraInfo = eraInfo;
  171.             // m_minDate is existing here just to keep the serialization compatibility.
  172.             // it has nothing to do with the code anymore.
  173.             m_minDate = m_Cal.MinSupportedDateTime;
  174.             m_maxYear = m_EraInfo[0].maxEraYear;
  175.             m_minYear = m_EraInfo[0].minEraYear;
  176.             ;
  177.         }
  178.        
  179. /*=================================GetGregorianYear==========================
  180.         **Action: Get the Gregorian year value for the specified year in an era.
  181.         **Returns: The Gregorian year value.
  182.         **Arguments:
  183.         **      year    the year value in Japanese calendar
  184.         **      era    the Japanese emperor era value.
  185.         **Exceptions:
  186.         **      ArgumentOutOfRangeException if year value is invalid or era value is invalid.
  187.         ============================================================================*/       
  188.        
  189.         internal int GetGregorianYear(int year, int era)
  190.         {
  191.             if (year < 0) {
  192.                 throw new ArgumentOutOfRangeException("year", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
  193.             }
  194.            
  195.             if (era == Calendar.CurrentEra) {
  196.                 era = m_Cal.CurrentEraValue;
  197.             }
  198.            
  199.             for (int i = 0; i < m_EraInfo.Length; i++) {
  200.                 if (era == m_EraInfo[i].era) {
  201.                     if (year < m_EraInfo[i].minEraYear || year > m_EraInfo[i].maxEraYear) {
  202.                         throw new ArgumentOutOfRangeException("year", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), m_EraInfo[i].minEraYear, m_EraInfo[i].maxEraYear));
  203.                     }
  204.                     return (m_EraInfo[i].yearOffset + year);
  205.                 }
  206.             }
  207.             throw new ArgumentOutOfRangeException("era", Environment.GetResourceString("ArgumentOutOfRange_InvalidEraValue"));
  208.         }
  209.        
  210.         internal bool IsValidYear(int year, int era)
  211.         {
  212.             if (year < 0) {
  213.                 return false;
  214.             }
  215.            
  216.             if (era == Calendar.CurrentEra) {
  217.                 era = m_Cal.CurrentEraValue;
  218.             }
  219.            
  220.             for (int i = 0; i < m_EraInfo.Length; i++) {
  221.                 if (era == m_EraInfo[i].era) {
  222.                     if (year < m_EraInfo[i].minEraYear || year > m_EraInfo[i].maxEraYear) {
  223.                         return false;
  224.                     }
  225.                     return true;
  226.                 }
  227.             }
  228.             return false;
  229.         }
  230.        
  231.        
  232.         // Returns a given date part of this DateTime. This method is used
  233.         // to compute the year, day-of-year, month, or day part.
  234.         internal virtual int GetDatePart(long ticks, int part)
  235.         {
  236.             CheckTicksRange(ticks);
  237.             // n = number of days since 1/1/0001
  238.             int n = (int)(ticks / TicksPerDay);
  239.             // y400 = number of whole 400-year periods since 1/1/0001
  240.             int y400 = n / DaysPer400Years;
  241.             // n = day number within 400-year period
  242.             n -= y400 * DaysPer400Years;
  243.             // y100 = number of whole 100-year periods within 400-year period
  244.             int y100 = n / DaysPer100Years;
  245.             // Last 100-year period has an extra day, so decrement result if 4
  246.             if (y100 == 4)
  247.                 y100 = 3;
  248.             // n = day number within 100-year period
  249.             n -= y100 * DaysPer100Years;
  250.             // y4 = number of whole 4-year periods within 100-year period
  251.             int y4 = n / DaysPer4Years;
  252.             // n = day number within 4-year period
  253.             n -= y4 * DaysPer4Years;
  254.             // y1 = number of whole years within 4-year period
  255.             int y1 = n / DaysPerYear;
  256.             // Last year has an extra day, so decrement result if 4
  257.             if (y1 == 4)
  258.                 y1 = 3;
  259.             // If year was requested, compute and return it
  260.             if (part == DatePartYear) {
  261.                 return (y400 * 400 + y100 * 100 + y4 * 4 + y1 + 1);
  262.             }
  263.             // n = day number within year
  264.             n -= y1 * DaysPerYear;
  265.             // If day-of-year was requested, return it
  266.             if (part == DatePartDayOfYear) {
  267.                 return (n + 1);
  268.             }
  269.             // Leap year calculation looks different from IsLeapYear since y1, y4,
  270.             // and y100 are relative to year 1, not year 0
  271.             bool leapYear = (y1 == 3 && (y4 != 24 || y100 == 3));
  272.             int[] days = leapYear ? DaysToMonth366 : DaysToMonth365;
  273.             // All months have less than 32 days, so n >> 5 is a good conservative
  274.             // estimate for the month
  275.             int m = n >> 5 + 1;
  276.             // m = 1-based month number
  277.             while (n >= days[m])
  278.                 m++;
  279.             // If month was requested, return it
  280.             if (part == DatePartMonth)
  281.                 return (m);
  282.             // Return 1-based day-of-month
  283.             return (n - days[m - 1] + 1);
  284.         }
  285.        
  286. /*=================================GetAbsoluteDate==========================
  287.         **Action: Gets the absolute date for the given Gregorian date.  The absolute date means
  288.         **      the number of days from January 1st, 1 A.D.
  289.         **Returns:  the absolute date
  290.         **Arguments:
  291.         **      year    the Gregorian year
  292.         **      month  the Gregorian month
  293.         **      day    the day
  294.         **Exceptions:
  295.         **      ArgumentOutOfRangException  if year, month, day value is valid.
  296.         **Note:
  297.         **      This is an internal method used by DateToTicks() and the calculations of Hijri and Hebrew calendars.
  298.         **      Number of Days in Prior Years (both common and leap years) +
  299.         **      Number of Days in Prior Months of Current Year +
  300.         **      Number of Days in Current Month
  301.         **
  302.         ============================================================================*/       
  303.        
  304.         static internal long GetAbsoluteDate(int year, int month, int day)
  305.         {
  306.             if (year >= 1 && year <= 9999 && month >= 1 && month <= 12) {
  307.                 int[] days = ((year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))) ? DaysToMonth366 : DaysToMonth365;
  308.                 if (day >= 1 && (day <= days[month] - days[month - 1])) {
  309.                     int y = year - 1;
  310.                     int absoluteDate = y * 365 + y / 4 - y / 100 + y / 400 + days[month - 1] + day - 1;
  311.                     return (absoluteDate);
  312.                 }
  313.             }
  314.             throw new ArgumentOutOfRangeException(null, Environment.GetResourceString("ArgumentOutOfRange_BadYearMonthDay"));
  315.         }
  316.        
  317.         // Returns the tick count corresponding to the given year, month, and day.
  318.         // Will check the if the parameters are valid.
  319.         static internal long DateToTicks(int year, int month, int day)
  320.         {
  321.             return (GetAbsoluteDate(year, month, day) * TicksPerDay);
  322.         }
  323.        
  324.         // Return the tick count corresponding to the given hour, minute, second.
  325.         // Will check the if the parameters are valid.
  326.         static internal long TimeToTicks(int hour, int minute, int second, int millisecond)
  327.         {
  328.             //TimeSpan.TimeToTicks is a family access function which does no error checking, so
  329.             //we need to put some error checking out here.
  330.             if (hour >= 0 && hour < 24 && minute >= 0 && minute < 60 && second >= 0 && second < 60) {
  331.                 if (millisecond < 0 || millisecond >= MillisPerSecond) {
  332.                     throw new ArgumentOutOfRangeException("millisecond", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), 0, MillisPerSecond - 1));
  333.                 }
  334.                 return (TimeSpan.TimeToTicks(hour, minute, second) + millisecond * TicksPerMillisecond);
  335.                 ;
  336.             }
  337.             throw new ArgumentOutOfRangeException(null, Environment.GetResourceString("ArgumentOutOfRange_BadHourMinuteSecond"));
  338.         }
  339.        
  340.        
  341.         internal void CheckTicksRange(long ticks)
  342.         {
  343.             if (ticks < m_Cal.MinSupportedDateTime.Ticks || ticks > m_Cal.MaxSupportedDateTime.Ticks) {
  344.                 throw new ArgumentOutOfRangeException("time", String.Format(CultureInfo.InvariantCulture, Environment.GetResourceString("ArgumentOutOfRange_CalendarRange"), m_Cal.MinSupportedDateTime, m_Cal.MaxSupportedDateTime));
  345.             }
  346.         }
  347.        
  348.         // Returns the DateTime resulting from adding the given number of
  349.         // months to the specified DateTime. The result is computed by incrementing
  350.         // (or decrementing) the year and month parts of the specified DateTime by
  351.         // value months, and, if required, adjusting the day part of the
  352.         // resulting date downwards to the last day of the resulting month in the
  353.         // resulting year. The time-of-day part of the result is the same as the
  354.         // time-of-day part of the specified DateTime.
  355.         //
  356.         // In more precise terms, considering the specified DateTime to be of the
  357.         // form y / m / d + t, where y is the
  358.         // year, m is the month, d is the day, and t is the
  359.         // time-of-day, the result is y1 / m1 / d1 + t,
  360.         // where y1 and m1 are computed by adding value months
  361.         // to y and m, and d1 is the largest value less than
  362.         // or equal to d that denotes a valid day in month m1 of year
  363.         // y1.
  364.         //
  365.         public DateTime AddMonths(DateTime time, int months)
  366.         {
  367.             CheckTicksRange(time.Ticks);
  368.             if (months < -120000 || months > 120000) {
  369.                 throw new ArgumentOutOfRangeException("months", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), -120000, 120000));
  370.             }
  371.             int y = GetDatePart(time.Ticks, DatePartYear);
  372.             int m = GetDatePart(time.Ticks, DatePartMonth);
  373.             int d = GetDatePart(time.Ticks, DatePartDay);
  374.             int i = m - 1 + months;
  375.             if (i >= 0) {
  376.                 m = i % 12 + 1;
  377.                 y = y + i / 12;
  378.             }
  379.             else {
  380.                 m = 12 + (i + 1) % 12;
  381.                 y = y + (i - 11) / 12;
  382.             }
  383.             int[] daysArray = (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) ? DaysToMonth366 : DaysToMonth365;
  384.             int days = (daysArray[m] - daysArray[m - 1]);
  385.            
  386.             if (d > days) {
  387.                 d = days;
  388.             }
  389.             long ticks = DateToTicks(y, m, d) + (time.Ticks % TicksPerDay);
  390.             Calendar.CheckAddResult(ticks, m_Cal.MinSupportedDateTime, m_Cal.MaxSupportedDateTime);
  391.             return (new DateTime(ticks));
  392.         }
  393.        
  394.         // Returns the DateTime resulting from adding the given number of
  395.         // years to the specified DateTime. The result is computed by incrementing
  396.         // (or decrementing) the year part of the specified DateTime by value
  397.         // years. If the month and day of the specified DateTime is 2/29, and if the
  398.         // resulting year is not a leap year, the month and day of the resulting
  399.         // DateTime becomes 2/28. Otherwise, the month, day, and time-of-day
  400.         // parts of the result are the same as those of the specified DateTime.
  401.         //
  402.         public DateTime AddYears(DateTime time, int years)
  403.         {
  404.             return (AddMonths(time, years * 12));
  405.         }
  406.        
  407.         // Returns the day-of-month part of the specified DateTime. The returned
  408.         // value is an integer between 1 and 31.
  409.         //
  410.         public int GetDayOfMonth(DateTime time)
  411.         {
  412.             return (GetDatePart(time.Ticks, DatePartDay));
  413.         }
  414.        
  415.         // Returns the day-of-week part of the specified DateTime. The returned value
  416.         // is an integer between 0 and 6, where 0 indicates Sunday, 1 indicates
  417.         // Monday, 2 indicates Tuesday, 3 indicates Wednesday, 4 indicates
  418.         // Thursday, 5 indicates Friday, and 6 indicates Saturday.
  419.         //
  420.         public DayOfWeek GetDayOfWeek(DateTime time)
  421.         {
  422.             CheckTicksRange(time.Ticks);
  423.             return ((DayOfWeek)((time.Ticks / TicksPerDay + 1) % 7));
  424.         }
  425.        
  426.         // Returns the day-of-year part of the specified DateTime. The returned value
  427.         // is an integer between 1 and 366.
  428.         //
  429.         public int GetDayOfYear(DateTime time)
  430.         {
  431.             return (GetDatePart(time.Ticks, DatePartDayOfYear));
  432.         }
  433.        
  434.         // Returns the number of days in the month given by the year and
  435.         // month arguments.
  436.         //
  437.         public int GetDaysInMonth(int year, int month, int era)
  438.         {
  439.             //
  440.             // Convert year/era value to Gregorain year value.
  441.             //
  442.             year = GetGregorianYear(year, era);
  443.             if (month < 1 || month > 12) {
  444.                 throw new ArgumentOutOfRangeException("month", Environment.GetResourceString("ArgumentOutOfRange_Month"));
  445.             }
  446.             int[] days = ((year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? DaysToMonth366 : DaysToMonth365);
  447.             return (days[month] - days[month - 1]);
  448.         }
  449.        
  450.         // Returns the number of days in the year given by the year argument for the current era.
  451.         //
  452.        
  453.         public int GetDaysInYear(int year, int era)
  454.         {
  455.             //
  456.             // Convert year/era value to Gregorain year value.
  457.             //
  458.             year = GetGregorianYear(year, era);
  459.             return ((year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? 366 : 365);
  460.         }
  461.        
  462.         // Returns the era for the specified DateTime value.
  463.         public int GetEra(DateTime time)
  464.         {
  465.             long ticks = time.Ticks;
  466.             // The assumption here is that m_EraInfo is listed in reverse order.
  467.             for (int i = 0; i < m_EraInfo.Length; i++) {
  468.                 if (ticks >= m_EraInfo[i].ticks) {
  469.                     return (m_EraInfo[i].era);
  470.                 }
  471.             }
  472.             throw new ArgumentOutOfRangeException(Environment.GetResourceString("ArgumentOutOfRange_Era"));
  473.         }
  474.        
  475.        
  476.         public int[] Eras {
  477.             get {
  478.                 if (m_eras == null) {
  479.                     m_eras = new int[m_EraInfo.Length];
  480.                     for (int i = 0; i < m_EraInfo.Length; i++) {
  481.                         m_eras[i] = m_EraInfo[i].era;
  482.                     }
  483.                 }
  484.                 return ((int[])m_eras.Clone());
  485.             }
  486.         }
  487.        
  488.         // Returns the month part of the specified DateTime. The returned value is an
  489.         // integer between 1 and 12.
  490.         //
  491.         public int GetMonth(DateTime time)
  492.         {
  493.             return (GetDatePart(time.Ticks, DatePartMonth));
  494.         }
  495.        
  496.         // Returns the number of months in the specified year and era.
  497.         public int GetMonthsInYear(int year, int era)
  498.         {
  499.             year = GetGregorianYear(year, era);
  500.             return (12);
  501.         }
  502.        
  503.         // Returns the year part of the specified DateTime. The returned value is an
  504.         // integer between 1 and 9999.
  505.         //
  506.         public int GetYear(DateTime time)
  507.         {
  508.             long ticks = time.Ticks;
  509.             int year = GetDatePart(ticks, DatePartYear);
  510.             for (int i = 0; i < m_EraInfo.Length; i++) {
  511.                 if (ticks >= m_EraInfo[i].ticks) {
  512.                     return (year - m_EraInfo[i].yearOffset);
  513.                 }
  514.             }
  515.             throw new ArgumentException(Environment.GetResourceString("Argument_NoEra"));
  516.         }
  517.        
  518.         // Returns the year that match the specified Gregorian year. The returned value is an
  519.         // integer between 1 and 9999.
  520.         //
  521.         public int GetYear(int year, DateTime time)
  522.         {
  523.             long ticks = time.Ticks;
  524.             for (int i = 0; i < m_EraInfo.Length; i++) {
  525.                 if (ticks >= m_EraInfo[i].ticks) {
  526.                     return (year - m_EraInfo[i].yearOffset);
  527.                 }
  528.             }
  529.             throw new ArgumentException(Environment.GetResourceString("Argument_NoEra"));
  530.         }
  531.        
  532.         // Checks whether a given day in the specified era is a leap day. This method returns true if
  533.         // the date is a leap day, or false if not.
  534.         //
  535.         public bool IsLeapDay(int year, int month, int day, int era)
  536.         {
  537.             // year/month/era checking is done in GetDaysInMonth()
  538.             if (day < 1 || day > GetDaysInMonth(year, month, era)) {
  539.                 throw new ArgumentOutOfRangeException("day", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), 1, GetDaysInMonth(year, month, era)));
  540.             }
  541.            
  542.             if (!IsLeapYear(year, era)) {
  543.                 return (false);
  544.             }
  545.            
  546.             if (month == 2 && day == 29) {
  547.                 return (true);
  548.             }
  549.            
  550.             return (false);
  551.         }
  552.        
  553.         // Returns the leap month in a calendar year of the specified era. This method returns 0
  554.         // if this calendar does not have leap month, or this year is not a leap year.
  555.         //
  556.         public int GetLeapMonth(int year, int era)
  557.         {
  558.             year = GetGregorianYear(year, era);
  559.             return (0);
  560.         }
  561.        
  562.         // Checks whether a given month in the specified era is a leap month. This method returns true if
  563.         // month is a leap month, or false if not.
  564.         //
  565.         public bool IsLeapMonth(int year, int month, int era)
  566.         {
  567.             year = GetGregorianYear(year, era);
  568.             if (month < 1 || month > 12) {
  569.                 throw new ArgumentOutOfRangeException("month", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), 1, 12));
  570.             }
  571.             return (false);
  572.         }
  573.        
  574.         // Checks whether a given year in the specified era is a leap year. This method returns true if
  575.         // year is a leap year, or false if not.
  576.         //
  577.         public bool IsLeapYear(int year, int era)
  578.         {
  579.             year = GetGregorianYear(year, era);
  580.             return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
  581.         }
  582.        
  583.         // Returns the date and time converted to a DateTime value. Throws an exception if the n-tuple is invalid.
  584.         //
  585.         public DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era)
  586.         {
  587.             year = GetGregorianYear(year, era);
  588.             long ticks = DateToTicks(year, month, day) + TimeToTicks(hour, minute, second, millisecond);
  589.             CheckTicksRange(ticks);
  590.             return (new DateTime(ticks));
  591.         }
  592.        
  593.         public virtual int GetWeekOfYear(DateTime time, CalendarWeekRule rule, DayOfWeek firstDayOfWeek)
  594.         {
  595.             CheckTicksRange(time.Ticks);
  596.             // Use GregorianCalendar to get around the problem that the implmentation in Calendar.GetWeekOfYear()
  597.             // can call GetYear() that exceeds the supported range of the Gregorian-based calendars.
  598.             return (GregorianCalendar.GetDefaultInstance().GetWeekOfYear(time, rule, firstDayOfWeek));
  599.         }
  600.        
  601.        
  602.         public int ToFourDigitYear(int year, int twoDigitYearMax)
  603.         {
  604.             if (year < 0) {
  605.                 throw new ArgumentOutOfRangeException("year", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
  606.             }
  607.            
  608.             if (year < 100) {
  609.                 int y = year % 100;
  610.                 return ((twoDigitYearMax / 100 - (y > twoDigitYearMax % 100 ? 1 : 0)) * 100 + y);
  611.             }
  612.            
  613.             if (year < m_minYear || year > m_maxYear) {
  614.                 throw new ArgumentOutOfRangeException("year", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), m_minYear, m_maxYear));
  615.             }
  616.             // If the year value is above 100, just return the year value. Don't have to do
  617.             // the TwoDigitYearMax comparison.
  618.             return (year);
  619.         }
  620.     }
  621. }

Developer Fusion