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

  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.     using System;
  19.     //
  20.     // This class implements the Julian calendar. In 48 B.C. Julius Caesar ordered a calendar reform, and this calendar
  21.     // is called Julian calendar. It consisted of a solar year of twelve months and of 365 days with an extra day
  22.     // every fourth year.
  23.     //*
  24.     //* Calendar support range:
  25.     //* Calendar Minimum Maximum
  26.     //* ========== ========== ==========
  27.     //* Gregorian 0001/01/01 9999/12/31
  28.     //* Julia 0001/01/03 9999/10/19
  29.    
  30.     [Serializable()]
  31.     [System.Runtime.InteropServices.ComVisible(true)]
  32.     public class JulianCalendar : Calendar
  33.     {
  34.        
  35.        
  36.         public static readonly int JulianEra = 1;
  37.        
  38.         private const int DatePartYear = 0;
  39.         private const int DatePartDayOfYear = 1;
  40.         private const int DatePartMonth = 2;
  41.         private const int DatePartDay = 3;
  42.        
  43.         // Number of days in a non-leap year
  44.         private const int JulianDaysPerYear = 365;
  45.         // Number of days in 4 years
  46.         private const int JulianDaysPer4Years = JulianDaysPerYear * 4 + 1;
  47.        
  48.         //internal static Calendar m_defaultInstance;
  49.        
  50.         private static readonly int[] DaysToMonth365 = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273,
  51.         304, 334, 365};
  52.        
  53.         private static readonly int[] DaysToMonth366 = {0, 31, 60, 91, 121, 152, 182, 213, 244, 274,
  54.         305, 335, 366};
  55.        
  56.         // Gregorian Calendar 9999/12/31 = Julian Calendar 9999/10/19
  57.         // keep it as variable field for serialization compat.
  58.         internal int MaxYear = 9999;
  59.        
  60.        
  61.         [System.Runtime.InteropServices.ComVisible(false)]
  62.         public override DateTime MinSupportedDateTime {
  63.             get { return (DateTime.MinValue); }
  64.         }
  65.        
  66.         [System.Runtime.InteropServices.ComVisible(false)]
  67.         public override DateTime MaxSupportedDateTime {
  68.             get { return (DateTime.MaxValue); }
  69.         }
  70.        
  71.         // Return the type of the Julian calendar.
  72.         //
  73.        
  74.         [System.Runtime.InteropServices.ComVisible(false)]
  75.         public override CalendarAlgorithmType AlgorithmType {
  76.             get { return CalendarAlgorithmType.SolarCalendar; }
  77.         }
  78.        
  79. /*=================================GetDefaultInstance==========================
  80.         **Action: Internal method to provide a default intance of JulianCalendar.  Used by NLS+ implementation
  81.         **      and other calendars.
  82.         **Returns:
  83.         **Arguments:
  84.         **Exceptions:
  85.         ============================================================================*/       
  86. /*
  87.         internal static Calendar GetDefaultInstance() {
  88.             if (m_defaultInstance == null) {
  89.                 m_defaultInstance = new JulianCalendar();
  90.             }
  91.             return (m_defaultInstance);
  92.         }
  93.         */       
  94.        
  95.         // Construct an instance of gregorian calendar.
  96.        
  97.         public JulianCalendar()
  98.         {
  99.             // There is no system setting of TwoDigitYear max, so set the value here.
  100.             twoDigitYearMax = 2029;
  101.         }
  102.        
  103.         internal override int ID {
  104.             get { return (CAL_JULIAN); }
  105.         }
  106.        
  107.         internal void CheckEraRange(int era)
  108.         {
  109.             if (era != CurrentEra && era != JulianEra) {
  110.                 throw new ArgumentOutOfRangeException("era", Environment.GetResourceString("ArgumentOutOfRange_InvalidEraValue"));
  111.             }
  112.         }
  113.        
  114.         internal void CheckYearEraRange(int year, int era)
  115.         {
  116.             CheckEraRange(era);
  117.             if (year <= 0 || year > MaxYear) {
  118.                 throw new ArgumentOutOfRangeException("year", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), 1, MaxYear));
  119.             }
  120.         }
  121.        
  122.         internal void CheckMonthRange(int month)
  123.         {
  124.             if (month < 1 || month > 12) {
  125.                 throw new ArgumentOutOfRangeException("month", Environment.GetResourceString("ArgumentOutOfRange_Month"));
  126.             }
  127.         }
  128.        
  129. /*=================================GetDefaultInstance==========================
  130.         **Action: Check for if the day value is valid.
  131.         **Returns:
  132.         **Arguments:
  133.         **Exceptions:
  134.         **Notes:
  135.         **  Before calling this method, call CheckYearEraRange()/CheckMonthRange() to make
  136.         **  sure year/month values are correct.
  137.         ============================================================================*/       
  138.        
  139.         internal void CheckDayRange(int year, int month, int day)
  140.         {
  141.             if (year == 1 && month == 1) {
  142.                 // The mimimum supported Julia date is Julian 0001/01/03.
  143.                 if (day < 3) {
  144.                     throw new ArgumentOutOfRangeException(null, Environment.GetResourceString("ArgumentOutOfRange_BadYearMonthDay"));
  145.                 }
  146.             }
  147.             bool isLeapYear = (year % 4) == 0;
  148.             int[] days = isLeapYear ? DaysToMonth366 : DaysToMonth365;
  149.             int monthDays = days[month] - days[month - 1];
  150.             if (day < 1 || day > monthDays) {
  151.                 throw new ArgumentOutOfRangeException("day", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), 1, monthDays));
  152.             }
  153.         }
  154.        
  155.        
  156.         // Returns a given date part of this DateTime. This method is used
  157.         // to compute the year, day-of-year, month, or day part.
  158.         internal int GetDatePart(long ticks, int part)
  159.         {
  160.             // Gregorian 1/1/0001 is Julian 1/3/0001. Remember DateTime(0) is refered to Gregorian 1/1/0001.
  161.             // The following line convert Gregorian ticks to Julian ticks.
  162.             long julianTicks = ticks + TicksPerDay * 2;
  163.             // n = number of days since 1/1/0001
  164.             int n = (int)(julianTicks / TicksPerDay);
  165.             // y4 = number of whole 4-year periods within 100-year period
  166.             int y4 = n / JulianDaysPer4Years;
  167.             // n = day number within 4-year period
  168.             n -= y4 * JulianDaysPer4Years;
  169.             // y1 = number of whole years within 4-year period
  170.             int y1 = n / JulianDaysPerYear;
  171.             // Last year has an extra day, so decrement result if 4
  172.             if (y1 == 4)
  173.                 y1 = 3;
  174.             // If year was requested, compute and return it
  175.             if (part == DatePartYear) {
  176.                 return (y4 * 4 + y1 + 1);
  177.             }
  178.             // n = day number within year
  179.             n -= y1 * JulianDaysPerYear;
  180.             // If day-of-year was requested, return it
  181.             if (part == DatePartDayOfYear) {
  182.                 return (n + 1);
  183.             }
  184.             // Leap year calculation looks different from IsLeapYear since y1, y4,
  185.             // and y100 are relative to year 1, not year 0
  186.             bool leapYear = (y1 == 3);
  187.             int[] days = leapYear ? DaysToMonth366 : DaysToMonth365;
  188.             // All months have less than 32 days, so n >> 5 is a good conservative
  189.             // estimate for the month
  190.             int m = n >> 5 + 1;
  191.             // m = 1-based month number
  192.             while (n >= days[m])
  193.                 m++;
  194.             // If month was requested, return it
  195.             if (part == DatePartMonth)
  196.                 return (m);
  197.             // Return 1-based day-of-month
  198.             return (n - days[m - 1] + 1);
  199.         }
  200.        
  201.         // Returns the tick count corresponding to the given year, month, and day.
  202.         internal long DateToTicks(int year, int month, int day)
  203.         {
  204.             int[] days = (year % 4 == 0) ? DaysToMonth366 : DaysToMonth365;
  205.             int y = year - 1;
  206.             int n = y * 365 + y / 4 + days[month - 1] + day - 1;
  207.             // Gregorian 1/1/0001 is Julian 1/3/0001. n * TicksPerDay is the ticks in JulianCalendar.
  208.             // Therefore, we subtract two days in the following to convert the ticks in JulianCalendar
  209.             // to ticks in Gregorian calendar.
  210.             return ((n - 2) * TicksPerDay);
  211.         }
  212.        
  213.        
  214.         public override DateTime AddMonths(DateTime time, int months)
  215.         {
  216.             if (months < -120000 || months > 120000) {
  217.                 throw new ArgumentOutOfRangeException("months", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), -120000, 120000));
  218.             }
  219.             int y = GetDatePart(time.Ticks, DatePartYear);
  220.             int m = GetDatePart(time.Ticks, DatePartMonth);
  221.             int d = GetDatePart(time.Ticks, DatePartDay);
  222.             int i = m - 1 + months;
  223.             if (i >= 0) {
  224.                 m = i % 12 + 1;
  225.                 y = y + i / 12;
  226.             }
  227.             else {
  228.                 m = 12 + (i + 1) % 12;
  229.                 y = y + (i - 11) / 12;
  230.             }
  231.             int[] daysArray = (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) ? DaysToMonth366 : DaysToMonth365;
  232.             int days = (daysArray[m] - daysArray[m - 1]);
  233.            
  234.             if (d > days) {
  235.                 d = days;
  236.             }
  237.             long ticks = DateToTicks(y, m, d) + time.Ticks % TicksPerDay;
  238.             Calendar.CheckAddResult(ticks, MinSupportedDateTime, MaxSupportedDateTime);
  239.             return (new DateTime(ticks));
  240.         }
  241.        
  242.        
  243.         public override DateTime AddYears(DateTime time, int years)
  244.         {
  245.             return (AddMonths(time, years * 12));
  246.         }
  247.        
  248.        
  249.         public override int GetDayOfMonth(DateTime time)
  250.         {
  251.             return (GetDatePart(time.Ticks, DatePartDay));
  252.         }
  253.        
  254.        
  255.         public override DayOfWeek GetDayOfWeek(DateTime time)
  256.         {
  257.             return ((DayOfWeek)((int)(time.Ticks / TicksPerDay + 1) % 7));
  258.         }
  259.        
  260.        
  261.         public override int GetDayOfYear(DateTime time)
  262.         {
  263.             return (GetDatePart(time.Ticks, DatePartDayOfYear));
  264.         }
  265.        
  266.        
  267.         public override int GetDaysInMonth(int year, int month, int era)
  268.         {
  269.             CheckYearEraRange(year, era);
  270.             CheckMonthRange(month);
  271.             int[] days = (year % 4 == 0) ? DaysToMonth366 : DaysToMonth365;
  272.             return (days[month] - days[month - 1]);
  273.         }
  274.        
  275.        
  276.         public override int GetDaysInYear(int year, int era)
  277.         {
  278.             // Year/Era range is done in IsLeapYear().
  279.             return (IsLeapYear(year, era) ? 366 : 365);
  280.         }
  281.        
  282.        
  283.         public override int GetEra(DateTime time)
  284.         {
  285.             return (JulianEra);
  286.         }
  287.        
  288.        
  289.         public override int GetMonth(DateTime time)
  290.         {
  291.             return (GetDatePart(time.Ticks, DatePartMonth));
  292.         }
  293.        
  294.        
  295.         public override int[] Eras {
  296.             get { return (new int[] {JulianEra}); }
  297.         }
  298.        
  299.        
  300.         public override int GetMonthsInYear(int year, int era)
  301.         {
  302.             CheckYearEraRange(year, era);
  303.             return (12);
  304.         }
  305.        
  306.        
  307.         public override int GetYear(DateTime time)
  308.         {
  309.             return (GetDatePart(time.Ticks, DatePartYear));
  310.         }
  311.        
  312.        
  313.         public override bool IsLeapDay(int year, int month, int day, int era)
  314.         {
  315.             CheckMonthRange(month);
  316.             // Year/Era range check is done in IsLeapYear().
  317.             if (IsLeapYear(year, era)) {
  318.                 CheckDayRange(year, month, day);
  319.                 return (month == 2 && day == 29);
  320.             }
  321.             CheckDayRange(year, month, day);
  322.             return (false);
  323.         }
  324.        
  325.         // Returns the leap month in a calendar year of the specified era. This method returns 0
  326.         // if this calendar does not have leap month, or this year is not a leap year.
  327.         //
  328.        
  329.         [System.Runtime.InteropServices.ComVisible(false)]
  330.         public override int GetLeapMonth(int year, int era)
  331.         {
  332.             CheckYearEraRange(year, era);
  333.             return (0);
  334.         }
  335.        
  336.        
  337.         public override bool IsLeapMonth(int year, int month, int era)
  338.         {
  339.             CheckYearEraRange(year, era);
  340.             CheckMonthRange(month);
  341.             return (false);
  342.         }
  343.        
  344.         // Checks whether a given year in the specified era is a leap year. This method returns true if
  345.         // year is a leap year, or false if not.
  346.         //
  347.        
  348.         public override bool IsLeapYear(int year, int era)
  349.         {
  350.             CheckYearEraRange(year, era);
  351.             return (year % 4 == 0);
  352.         }
  353.        
  354.        
  355.         public override DateTime ToDateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int era)
  356.         {
  357.             CheckYearEraRange(year, era);
  358.             CheckMonthRange(month);
  359.             CheckDayRange(year, month, day);
  360.             if (millisecond < 0 || millisecond >= MillisPerSecond) {
  361.                 throw new ArgumentOutOfRangeException("millisecond", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), 0, MillisPerSecond - 1));
  362.             }
  363.            
  364.             if (hour >= 0 && hour < 24 && minute >= 0 && minute < 60 && second >= 0 && second < 60) {
  365.                 return new DateTime(DateToTicks(year, month, day) + (new TimeSpan(0, hour, minute, second, millisecond)).Ticks);
  366.             }
  367.             else {
  368.                 throw new ArgumentOutOfRangeException(null, Environment.GetResourceString("ArgumentOutOfRange_BadHourMinuteSecond"));
  369.             }
  370.         }
  371.        
  372.        
  373.         public override int TwoDigitYearMax {
  374.             get { return (twoDigitYearMax); }
  375.            
  376.             set {
  377.                 VerifyWritable();
  378.                 if (value < 99 || value > MaxYear) {
  379.                     throw new ArgumentOutOfRangeException("year", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Range"), 99, MaxYear));
  380.                    
  381.                 }
  382.                 twoDigitYearMax = value;
  383.             }
  384.         }
  385.        
  386.        
  387.         public override int ToFourDigitYear(int year)
  388.         {
  389.             if (year > MaxYear) {
  390.                 throw new ArgumentOutOfRangeException("year", String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("ArgumentOutOfRange_Bounds_Lower_Upper"), 1, MaxYear));
  391.             }
  392.             return (base.ToFourDigitYear(year));
  393.         }
  394.     }
  395.    
  396. }

Developer Fusion