We need you! We're working hard on the next version of Developer Fusion - Let us know what you think we should be up to!

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

  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.     using System.Security;
  19.     using System.Threading;
  20.     using System.Collections;
  21.     using System.Runtime.Serialization;
  22.     using System.Security.Permissions;
  23.     using System.Runtime.InteropServices;
  24.     using System.Text;
  25.    
  26.     //
  27.     // Flags used to indicate different styles of month names.
  28.     // This is an internal flag used by internalGetMonthName().
  29.     // Use flag here in case that we need to provide a combination of these styles
  30.     // (such as month name of a leap year in genitive form. Not likely for now,
  31.     // but would like to keep the option open).
  32.     //
  33.    
  34.     [Flags()]
  35.     internal enum MonthNameStyles
  36.     {
  37.         Regular = 0,
  38.         Genitive = 1,
  39.         LeapYear = 2
  40.     }
  41.    
  42.     //
  43.     // Flags used to indicate special rule used in parsing/formatting
  44.     // for a specific DateTimeFormatInfo instance.
  45.     // This is an internal flag.
  46.     //
  47.     // This flag is different from MonthNameStyles because this flag
  48.     // can be expanded to accomodate parsing behaviors like CJK month names
  49.     // or alternative month names, etc.
  50.    
  51.     [Flags()]
  52.     internal enum DateTimeFormatFlags
  53.     {
  54.         None = 0,
  55.         UseGenitiveMonth = 1,
  56.         UseLeapYearMonth = 2,
  57.         UseSpacesInMonthNames = 4,
  58.         // Has spaces or non-breaking space in the month names.
  59.         UseHebrewRule = 8,
  60.         // Format/Parse using the Hebrew calendar rule.
  61.         UseSpacesInDayNames = 16,
  62.         // Has spaces or non-breaking space in the day names.
  63.         UseDigitPrefixInTokens = 32,
  64.         // Has token starting with numbers.
  65.         NotInitialized = -1
  66.     }
  67.    
  68.    
  69.     [Serializable()]
  70.     [System.Runtime.InteropServices.ComVisible(true)]
  71.     public sealed class DateTimeFormatInfo : ICloneable, IFormatProvider
  72.     {
  73.        
  74.         // cache for the invarinat culture.
  75.         // invariantInfo is constant irrespective of your current culture.
  76.         private static DateTimeFormatInfo invariantInfo;
  77.        
  78.         // an index which points to a record in Culture Data Table.
  79.         [NonSerialized()]
  80.         internal CultureTableRecord m_cultureTableRecord;
  81.        
  82.         // The culture name used to create this DTFI.
  83.         [OptionalField(VersionAdded = 2)]
  84.         internal string m_name = null;
  85.        
  86.         // The language name of the culture used to create this DTFI.
  87.         [NonSerialized()]
  88.         internal string m_langName = null;
  89.        
  90.         // CompareInfo usually used by the parser.
  91.         [NonSerialized()]
  92.         internal CompareInfo m_compareInfo = null;
  93.        
  94.         // Flag to indicate if the specified calendar for this DTFI is the
  95.         // default calendar stored in the culture.nlp.
  96.         internal bool m_isDefaultCalendar;
  97.        
  98.         internal int CultureId {
  99.             get { return this.m_cultureTableRecord.CultureID; }
  100.         }
  101.        
  102.         //
  103.         //
  104.         //
  105.         //
  106.         //
  107.         internal bool bUseCalendarInfo = false;
  108.        
  109.         //
  110.         // Caches for various properties.
  111.         //
  112.         internal string amDesignator = null;
  113.         internal string pmDesignator = null;
  114.         internal string dateSeparator = null;
  115.         internal string longTimePattern = null;
  116.         internal string shortTimePattern = null;
  117.         internal string generalShortTimePattern = null;
  118.         internal string generalLongTimePattern = null;
  119.         internal string timeSeparator = null;
  120.         internal string monthDayPattern = null;
  121.        
  122.         // In case default time/date pattern included in the all patterns array then we always set it as first item.
  123.         // that is to be easy to know if we need to add the default pattern to the array when the array is requested.
  124.         // look at SetDefaultPatternAsFirstItem to see how we do that.
  125.         internal string[] allShortTimePatterns = null;
  126.         internal string[] allLongTimePatterns = null;
  127.        
  128.         //
  129.         // The following are constant values.
  130.         //
  131.         internal const string rfc1123Pattern = "ddd, dd MMM yyyy HH':'mm':'ss 'GMT'";
  132.         // The sortable pattern is based on ISO 8601.
  133.         internal const string sortableDateTimePattern = "yyyy'-'MM'-'dd'T'HH':'mm':'ss";
  134.         internal const string universalSortableDateTimePattern = "yyyy'-'MM'-'dd HH':'mm':'ss'Z'";
  135.        
  136.         //
  137.         // The following are affected by calendar settings.
  138.         //
  139.         internal Calendar calendar = null;
  140.        
  141.         internal int firstDayOfWeek = -1;
  142.         internal int calendarWeekRule = -1;
  143.        
  144.         internal string fullDateTimePattern = null;
  145.        
  146.         internal string longDatePattern = null;
  147.        
  148.         internal string shortDatePattern = null;
  149.        
  150.         internal string yearMonthPattern = null;
  151.        
  152.         internal string[] abbreviatedDayNames = null;
  153.        
  154.         [OptionalField(VersionAdded = 2)]
  155.         internal string[] m_superShortDayNames = null;
  156.        
  157.         internal string[] dayNames = null;
  158.         internal string[] abbreviatedMonthNames = null;
  159.         internal string[] monthNames = null;
  160.         // Cache the genitive month names that we retrieve from the data table.
  161.         [OptionalField(VersionAdded = 2)]
  162.         internal string[] genitiveMonthNames = null;
  163.        
  164.         // Cache the abbreviated genitive month names that we retrieve from the data table.
  165.         [OptionalField(VersionAdded = 2)]
  166.         internal string[] m_genitiveAbbreviatedMonthNames = null;
  167.        
  168.         // Cache the month names of a leap year that we retrieve from the data table.
  169.         [OptionalField(VersionAdded = 2)]
  170.         internal string[] leapYearMonthNames = null;
  171.        
  172.         // In case default time/date pattern included in the all patterns array then we always set it as first item.
  173.         // that is to be easy to know if we need to add the default pattern to the array when the array is requested.
  174.         // look at SetDefaultPatternAsFirstItem to see how we do that.
  175.        
  176.         [NonSerialized()]
  177.         // this is lazy intialized so no need to serialize it.
  178.         internal string[] allYearMonthPatterns = null;
  179.         internal string[] allShortDatePatterns = null;
  180.         internal string[] allLongDatePatterns = null;
  181.        
  182.        
  183.        
  184.         // Cache the era names for this DateTimeFormatInfo instance.
  185.         internal string[] m_eraNames = null;
  186.         internal string[] m_abbrevEraNames = null;
  187.         internal string[] m_abbrevEnglishEraNames = null;
  188.        
  189.         internal string[] m_dateWords = null;
  190.        
  191.         internal int[] optionalCalendars = null;
  192.        
  193.         private const int DEFAULT_ALL_DATETIMES_SIZE = 132;
  194.        
  195.         internal bool m_isReadOnly = false;
  196.         // This flag gives hints about if formatting/parsing should perform special code path for things like
  197.         // genitive form or leap year month names.
  198.         [OptionalField(VersionAdded = 2)]
  199.         internal DateTimeFormatFlags formatFlags = DateTimeFormatFlags.NotInitialized;
  200.        
  201.         private static Hashtable m_calendarNativeNames;
  202.         // Maps from calendar Id to calendar native name.
  203.         private static object s_InternalSyncObject;
  204.        
  205.         private static object InternalSyncObject {
  206.             get {
  207.                 if (s_InternalSyncObject == null) {
  208.                     object o = new object();
  209.                     Interlocked.CompareExchange(ref s_InternalSyncObject, o, null);
  210.                 }
  211.                 return s_InternalSyncObject;
  212.             }
  213.         }
  214.        
  215.         internal string CultureName {
  216.             get {
  217.                 if (m_name == null) {
  218.                     m_name = this.m_cultureTableRecord.SNAME;
  219.                 }
  220.                 return (m_name);
  221.             }
  222.         }
  223.        
  224.         internal string LanguageName {
  225.             get {
  226.                 if (m_langName == null) {
  227.                     m_langName = this.m_cultureTableRecord.SISO639LANGNAME;
  228.                 }
  229.                 return (m_langName);
  230.             }
  231.         }
  232.        
  233.         ////////////////////////////////////////////////////////////////////////////
  234.         //
  235.         // Create an array of string which contains the abbreviated day names.
  236.         //
  237.         ////////////////////////////////////////////////////////////////////////////
  238.        
  239.         private string[] GetAbbreviatedDayOfWeekNames()
  240.         {
  241.             if (abbreviatedDayNames == null) {
  242.                 if (abbreviatedDayNames == null) {
  243.                     string[] temp = null;
  244.                     if (!m_isDefaultCalendar) {
  245.                         BCLDebug.Assert(Calendar.ID > 0, "[DateTimeFormatInfo.GetAbbreviatedDayOfWeekNames] Expected Calendar.ID > 0");
  246.                         temp = CalendarTable.Default.SABBREVDAYNAMES(Calendar.ID);
  247.                     }
  248.                     if (temp == null || temp.Length == 0 || temp[0].Length == 0)
  249.                         temp = this.m_cultureTableRecord.SABBREVDAYNAMES;
  250.                     System.Threading.Thread.MemoryBarrier();
  251.                     abbreviatedDayNames = temp;
  252.                     BCLDebug.Assert(abbreviatedDayNames.Length == 7, "[DateTimeFormatInfo.GetAbbreviatedDayOfWeekNames] Expected 7 day names in a week");
  253.                 }
  254.             }
  255.             return (abbreviatedDayNames);
  256.         }
  257.        
  258.         ////////////////////////////////////////////////////////////////////////
  259.         //
  260.         // Action: Returns the string array of the one-letter day of week names.
  261.         // Returns:
  262.         // an array of one-letter day of week names
  263.         // Arguments:
  264.         // None
  265.         // Exceptions:
  266.         // None
  267.         //
  268.         ////////////////////////////////////////////////////////////////////////
  269.        
  270.         private string[] internalGetSuperShortDayNames()
  271.         {
  272.             if (this.m_superShortDayNames == null) {
  273.                 if (this.m_superShortDayNames == null) {
  274.                     string[] temp = null;
  275.                     if (!m_isDefaultCalendar) {
  276.                         BCLDebug.Assert(Calendar.ID > 0, "[DateTimeFormatInfo.internalGetSuperShortDayNames] Expected Calendar.ID > 0");
  277.                         temp = CalendarTable.Default.SSUPERSHORTDAYNAMES(Calendar.ID);
  278.                     }
  279.                     if (temp == null || temp.Length == 0 || temp[0].Length == 0)
  280.                         temp = this.m_cultureTableRecord.SSUPERSHORTDAYNAMES;
  281.                     System.Threading.Thread.MemoryBarrier();
  282.                     this.m_superShortDayNames = temp;
  283.                     BCLDebug.Assert(this.m_superShortDayNames.Length == 7, "[DateTimeFormatInfo.internalGetSuperShortDayNames] Expected 7 day names in a week");
  284.                 }
  285.             }
  286.             return (this.m_superShortDayNames);
  287.         }
  288.        
  289.         ////////////////////////////////////////////////////////////////////////////
  290.         //
  291.         // Create an array of string which contains the day names.
  292.         //
  293.         ////////////////////////////////////////////////////////////////////////////
  294.        
  295.         private string[] GetDayOfWeekNames()
  296.         {
  297.             if (dayNames == null) {
  298.                 if (dayNames == null) {
  299.                     string[] temp = null;
  300.                     if (!m_isDefaultCalendar) {
  301.                         BCLDebug.Assert(Calendar.ID > 0, "[DateTimeFormatInfo.GetDayOfWeekNames] Expected Calendar.ID > 0");
  302.                         temp = CalendarTable.Default.SDAYNAMES(Calendar.ID);
  303.                     }
  304.                     if (temp == null || temp.Length == 0 || temp[0].Length == 0)
  305.                         temp = this.m_cultureTableRecord.SDAYNAMES;
  306.                     System.Threading.Thread.MemoryBarrier();
  307.                     dayNames = temp;
  308.                     BCLDebug.Assert(dayNames.Length == 7, "[DateTimeFormatInfo.GetDayOfWeekNames] Expected 7 day names in a week");
  309.                 }
  310.             }
  311.             return (dayNames);
  312.         }
  313.        
  314.         ////////////////////////////////////////////////////////////////////////////
  315.         //
  316.         // Create an array of string which contains the abbreviated month names.
  317.         //
  318.         ////////////////////////////////////////////////////////////////////////////
  319.        
  320.         private string[] GetAbbreviatedMonthNames()
  321.         {
  322.             if (abbreviatedMonthNames == null) {
  323.                 if (abbreviatedMonthNames == null) {
  324.                     string[] temp = null;
  325.                     if (!m_isDefaultCalendar) {
  326.                         BCLDebug.Assert(Calendar.ID > 0, "[DateTimeFormatInfo.GetAbbreviatedMonthNames] Expected Calendar.ID > 0");
  327.                         temp = CalendarTable.Default.SABBREVMONTHNAMES(Calendar.ID);
  328.                     }
  329.                     if (temp == null || temp.Length == 0 || temp[0].Length == 0)
  330.                         temp = this.m_cultureTableRecord.SABBREVMONTHNAMES;
  331.                     System.Threading.Thread.MemoryBarrier();
  332.                     abbreviatedMonthNames = temp;
  333.                     BCLDebug.Assert(abbreviatedMonthNames.Length == 12 || abbreviatedMonthNames.Length == 13, "[DateTimeFormatInfo.GetAbbreviatedMonthNames] Expected 12 or 13 month names in a year");
  334.                 }
  335.             }
  336.             return (abbreviatedMonthNames);
  337.         }
  338.        
  339.        
  340.         ////////////////////////////////////////////////////////////////////////////
  341.         //
  342.         // Create an array of string which contains the month names.
  343.         //
  344.         ////////////////////////////////////////////////////////////////////////////
  345.        
  346.         private string[] GetMonthNames()
  347.         {
  348.             if (monthNames == null) {
  349.                 string[] temp = null;
  350.                 if (!m_isDefaultCalendar) {
  351.                     BCLDebug.Assert(Calendar.ID > 0, "[DateTimeFormatInfo.GetMonthNames] Expected Calendar.ID > 0");
  352.                     temp = CalendarTable.Default.SMONTHNAMES(Calendar.ID);
  353.                 }
  354.                 if (temp == null || temp.Length == 0 || temp[0].Length == 0)
  355.                     temp = this.m_cultureTableRecord.SMONTHNAMES;
  356.                 System.Threading.Thread.MemoryBarrier();
  357.                 monthNames = temp;
  358.                 BCLDebug.Assert(MonthNames.Length == 12 || MonthNames.Length == 13, "[DateTimeFormatInfo.GetMonthNames] Expected 12 or 13 month names in a year");
  359.             }
  360.            
  361.             return (monthNames);
  362.         }
  363.        
  364.        
  365.         public DateTimeFormatInfo()
  366.         {
  367.             //
  368.             // Invariant DateTimeFormatInfo doesn't have user-overriden values, so we pass false in useUserOverride.
  369.             //
  370.             this.m_cultureTableRecord = CultureInfo.InvariantCulture.m_cultureTableRecord;
  371.             // In Invariant culture, the default calendar store in culture.nlp is Gregorian localized.
  372.             // And the date/time pattern for invariant culture stored in
  373.             this.m_isDefaultCalendar = true;
  374.             this.calendar = GregorianCalendar.GetDefaultInstance();
  375.            
  376.             // We don't have to call the setter of Calendar property here because the Calendar getter
  377.             // will return Gregorian localized calendar by default.
  378.             InitializeOverridableProperties();
  379.         }
  380.        
  381.         internal DateTimeFormatInfo(CultureTableRecord cultureTable, int cultureID, Calendar cal)
  382.         {
  383.             this.m_cultureTableRecord = cultureTable;
  384.             // m_isDefaultCalendar is set in the setter of Calendar below.
  385.             this.Calendar = cal;
  386.         }
  387.        
  388.         #region Serialization
  389.         // The following fields are defined to keep the serialization compatibility with .NET V1.0/V1.1.
  390.         private int CultureID;
  391.         private bool m_useUserOverride;
  392.         private int nDataItem;
  393.        
  394.         [OnDeserialized()]
  395.         private void OnDeserialized(StreamingContext ctx)
  396.         {
  397.             BCLDebug.Assert(CultureID >= 0, "[DateTimeFormatInfo.OnDeserialized] clulture ID < 0");
  398.            
  399.             if (CultureTableRecord.IsCustomCultureId(CultureID))
  400.                 m_cultureTableRecord = CultureTableRecord.GetCultureTableRecord(m_name, m_useUserOverride);
  401.             else
  402.                 m_cultureTableRecord = CultureTableRecord.GetCultureTableRecord(CultureID, m_useUserOverride);
  403.            
  404.             if (calendar == null) {
  405.                 calendar = (Calendar)GregorianCalendar.GetDefaultInstance().Clone();
  406.                 calendar.SetReadOnlyState(m_isReadOnly);
  407.             }
  408.             else {
  409.                 CultureInfo.CheckDomainSafetyObject(calendar, this);
  410.             }
  411.            
  412.             InitializeOverridableProperties();
  413.         }
  414.        
  415.         [OnSerializing()]
  416.         private void OnSerializing(StreamingContext ctx)
  417.         {
  418.             CultureID = m_cultureTableRecord.CultureID;
  419.             m_useUserOverride = m_cultureTableRecord.UseUserOverride;
  420.             nDataItem = m_cultureTableRecord.EverettDataItem();
  421.            
  422.             //
  423.             // If we have custom culture then we serialize a valid name so it can be used
  424.             // during the deserialization as we cannot use the CultureID at that time.
  425.             //
  426.            
  427.             if (CultureTableRecord.IsCustomCultureId(CultureID)) {
  428.                 // make sure the m_name is initialized.
  429.                 m_name = this.CultureName;
  430.             }
  431.         }
  432.         #endregion Serialization
  433.        
  434.         // Returns a default DateTimeFormatInfo that will be universally
  435.         // supported and constant irrespective of the current culture.
  436.         // Used by FromString methods.
  437.         //
  438.        
  439.         public static DateTimeFormatInfo InvariantInfo {
  440.             get {
  441.                 if (invariantInfo == null) {
  442.                     DateTimeFormatInfo info = new DateTimeFormatInfo();
  443.                     info.Calendar.SetReadOnlyState(true);
  444.                     info.m_isReadOnly = true;
  445.                     invariantInfo = info;
  446.                 }
  447.                 return (invariantInfo);
  448.             }
  449.         }
  450.        
  451.         // Returns the current culture's DateTimeFormatInfo. Used by Parse methods.
  452.         //
  453.        
  454.         public static DateTimeFormatInfo CurrentInfo {
  455.             get {
  456.                 System.Globalization.CultureInfo culture = System.Threading.Thread.CurrentThread.CurrentCulture;
  457.                 if (!culture.m_isInherited) {
  458.                     DateTimeFormatInfo info = culture.dateTimeInfo;
  459.                     if (info != null) {
  460.                         return info;
  461.                     }
  462.                 }
  463.                 return (DateTimeFormatInfo)culture.GetFormat(typeof(DateTimeFormatInfo));
  464.             }
  465.         }
  466.        
  467.        
  468.         public static DateTimeFormatInfo GetInstance(IFormatProvider provider)
  469.         {
  470.             // Fast case for a regular CultureInfo
  471.             DateTimeFormatInfo info;
  472.             CultureInfo cultureProvider = provider as CultureInfo;
  473.             if (cultureProvider != null && !cultureProvider.m_isInherited) {
  474.                 info = cultureProvider.dateTimeInfo;
  475.                 if (info != null) {
  476.                     return info;
  477.                 }
  478.                 else {
  479.                     return cultureProvider.DateTimeFormat;
  480.                 }
  481.             }
  482.             // Fast case for a DTFI;
  483.             info = provider as DateTimeFormatInfo;
  484.             if (info != null) {
  485.                 return info;
  486.             }
  487.             if (provider != null) {
  488.                 info = provider.GetFormat(typeof(DateTimeFormatInfo)) as DateTimeFormatInfo;
  489.                 if (info != null) {
  490.                     return info;
  491.                 }
  492.             }
  493.             return CurrentInfo;
  494.         }
  495.        
  496.        
  497.         public object GetFormat(Type formatType)
  498.         {
  499.             return (formatType == typeof(DateTimeFormatInfo) ? this : null);
  500.         }
  501.        
  502.        
  503.         public object Clone()
  504.         {
  505.             DateTimeFormatInfo n = (DateTimeFormatInfo)MemberwiseClone();
  506.             // We can use the data member calendar in the setter, instead of the property Calendar,
  507.             // since the cloned copy should have the same state as the original copy.
  508.             n.calendar = (Calendar)this.Calendar.Clone();
  509.             n.m_isReadOnly = false;
  510.             return n;
  511.         }
  512.        
  513.        
  514.         public string AMDesignator {
  515.             get {
  516.                 BCLDebug.Assert(amDesignator != null, "DateTimeFormatInfo.AMDesignator, amDesignator != null");
  517.                 return (amDesignator);
  518.             }
  519.            
  520.             set {
  521.                 VerifyWritable();
  522.                 if (value == null) {
  523.                     throw new ArgumentNullException("value", Environment.GetResourceString("ArgumentNull_String"));
  524.                 }
  525.                 ClearTokenHashTable(true);
  526.                 amDesignator = value;
  527.             }
  528.         }
  529.        
  530.         private void InitializeOverridableProperties()
  531.         {
  532.             // These properties are not affected by calendar settings. And they should be always initialized.
  533.            
  534.             if (amDesignator == null) {
  535.                 amDesignator = m_cultureTableRecord.S1159;
  536.             }
  537.             if (pmDesignator == null) {
  538.                 pmDesignator = m_cultureTableRecord.S2359;
  539.             }
  540.             if (longTimePattern == null) {
  541.                 longTimePattern = m_cultureTableRecord.STIMEFORMAT;
  542.             }
  543.             if (firstDayOfWeek == -1) {
  544.                 firstDayOfWeek = m_cultureTableRecord.IFIRSTDAYOFWEEK;
  545.             }
  546.             if (calendarWeekRule == -1) {
  547.                 calendarWeekRule = m_cultureTableRecord.IFIRSTWEEKOFYEAR;
  548.             }
  549.            
  550.             // These 3 properties are affected by calendar settings.
  551.             if (yearMonthPattern == null) {
  552.                 yearMonthPattern = GetYearMonthPattern(calendar.ID);
  553.             }
  554.             if (shortDatePattern == null) {
  555.                 shortDatePattern = GetShortDatePattern(calendar.ID);
  556.             }
  557.             if (longDatePattern == null) {
  558.                 longDatePattern = GetLongDatePattern(calendar.ID);
  559.             }
  560.         }
  561.        
  562.        
  563.         public Calendar Calendar {
  564.             get {
  565.                 BCLDebug.Assert(calendar != null, "DateTimeFormatInfo.Calendar: calendar != null");
  566.                 return (calendar);
  567.             }
  568.            
  569.             set {
  570.                 VerifyWritable();
  571.                 if (value == null) {
  572.                     throw new ArgumentNullException("value", Environment.GetResourceString("ArgumentNull_Obj"));
  573.                 }
  574.                 if (value == calendar) {
  575.                     return;
  576.                 }
  577.                
  578.                 //
  579.                 // Because the culture is agile object which can be attached to a thread and then thread can travel
  580.                 // to another app domain then we prevent attaching any customized object to culture that we cannot contol.
  581.                 //
  582.                 CultureInfo.CheckDomainSafetyObject(value, this);
  583.                
  584.                 for (int i = 0; i < OptionalCalendars.Length; i++) {
  585.                     if (OptionalCalendars[i] == value.ID) {
  586.                         ClearTokenHashTable(false);
  587.                         //
  588.                         // Get the current Win32 user culture.
  589.                         //
  590.                         m_isDefaultCalendar = (value.ID == Calendar.CAL_GREGORIAN);
  591.                         /*
  592.                             When UseUserOverride is TRUE, we should follow the following table
  593.                             to retrieve date/time patterns.
  594.                             CurrentCulture:    Is the culture which creates the DTFI the current user default culture
  595.                                                 specified in the control panel?
  596.                             CurrentCalendar:    Is the specified calendar the current calendar specified in the control panel?
  597.                             n/r: not relavent, don't care.
  598.                             Case    CurrentCulture? CurrentCalendar?    GregorianLocalized? Get Data from
  599.                             ----    --------------- ----------------    ------------------- --------------------------
  600.                             1      Y              Y                  n/r                registry & culture.nlp (for user-overridable data)
  601.                             2      n/r            n/r                Y                  culture.nlp
  602.                             3      n/r            n/r                N                  CALENDAR.nlp*
  603.                         */                       
  604.                        
  605. if (calendar != null) {
  606.                             // clean related properties which are affected by the calendar setting,
  607.                             // so that they will be refreshed when they are accessed next time.
  608.                             //
  609.                            
  610.                             // These properites are in the order as appearing in calendar.xml.
  611.                             m_eraNames = null;
  612.                             m_abbrevEraNames = null;
  613.                             m_abbrevEnglishEraNames = null;
  614.                            
  615.                             shortDatePattern = null;
  616.                             yearMonthPattern = null;
  617.                             monthDayPattern = null;
  618.                             longDatePattern = null;
  619.                            
  620.                             dayNames = null;
  621.                             abbreviatedDayNames = null;
  622.                             m_superShortDayNames = null;
  623.                             monthNames = null;
  624.                             abbreviatedMonthNames = null;
  625.                             genitiveMonthNames = null;
  626.                             m_genitiveAbbreviatedMonthNames = null;
  627.                             leapYearMonthNames = null;
  628.                             formatFlags = DateTimeFormatFlags.NotInitialized;
  629.                            
  630.                             // These properies are not in calendar.xml, but they are dependent on the values like shortDatePattern.
  631.                             fullDateTimePattern = null;
  632.                             generalShortTimePattern = null;
  633.                             generalLongTimePattern = null;
  634.                             allShortDatePatterns = null;
  635.                             allLongDatePatterns = null;
  636.                             allYearMonthPatterns = null;
  637.                            
  638.                            
  639.                         }
  640.                        
  641.                         calendar = value;
  642.                        
  643.                         if (this.m_cultureTableRecord.UseCurrentCalendar(value.ID)) {
  644.                             //
  645.                             // [Case 1]
  646.                             //
  647.                             // If user overriden values are allowed, and the culture is the user default culture
  648.                             // and the specified calendar matches the calendar setting in the control panel,
  649.                             // use data from registry by setting bUseCalendarInfo to be false.
  650.                             //
  651.                             DTFIUserOverrideValues temp = new DTFIUserOverrideValues();
  652.                            
  653.                             // If this is the first time calendar is set, just assign
  654.                             // the value to calendar. We don't have to clean up
  655.                             // related fields.
  656.                             // We need to retrieve all user-override values and cache them to avoid to get different
  657.                             // values between calls to CultureInfo.ClearCachedData()
  658.                             m_cultureTableRecord.GetDTFIOverrideValues(ref temp);
  659.                            
  660.                            
  661.                             amDesignator = temp.amDesignator;
  662.                             pmDesignator = temp.pmDesignator;
  663.                             longTimePattern = temp.longTimePattern;
  664.                             firstDayOfWeek = (int)temp.firstDayOfWeek;
  665.                             calendarWeekRule = (int)temp.calendarWeekRule;
  666.                             shortDatePattern = temp.shortDatePattern;
  667.                             longDatePattern = temp.longDatePattern;
  668.                             yearMonthPattern = temp.yearMonthPattern;
  669.                            
  670.                             // To work around a Win9x data bug. GetLocaleInfo(LOCALE_SYEARMONTH) returns empty string in Win9x.
  671.                             // There is also a NLS bug that GetLocaleInfo returns incorrect YearMonth pattern when the reg key of for YearMonth does not
  672.                             // exists. GetDTFIOVerrideValues() will leave yearMonthPattern to be null in that case.
  673.                            
  674.                             // In these cases, fall back to the table value.
  675.                            
  676.                             if (yearMonthPattern == null || yearMonthPattern.Length == 0) {
  677.                                 yearMonthPattern = GetYearMonthPattern(value.ID);
  678.                             }
  679.                            
  680.                         }
  681.                         else {
  682.                             // Case 2 & Case 3
  683.                            
  684.                             InitializeOverridableProperties();
  685.                         }
  686.                         return;
  687.                     }
  688.                 }
  689.                 // The assigned calendar is not a valid calendar for this culture.
  690.                 throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("Argument_InvalidCalendar"));
  691.             }
  692.         }
  693.        
  694.         internal int[] OptionalCalendars {
  695.             get {
  696.                 if (optionalCalendars == null) {
  697.                     optionalCalendars = this.m_cultureTableRecord.IOPTIONALCALENDARS;
  698.                 }
  699.                 return (optionalCalendars);
  700.             }
  701.         }
  702.        
  703. /*=================================GetEra==========================
  704.         **Action: Get the era value by parsing the name of the era.
  705.         **Returns: The era value for the specified era name.
  706.         **      -1 if the name of the era is not valid or not supported.
  707.         **Arguments: eraName    the name of the era.
  708.         **Exceptions: None.
  709.         ============================================================================*/       
  710.        
  711.        
  712.         public int GetEra(string eraName)
  713.         {
  714.             if (eraName == null) {
  715.                 throw new ArgumentNullException("eraName", Environment.GetResourceString("ArgumentNull_String"));
  716.             }
  717.            
  718.             // The following is based on the assumption that the era value is starting from 1, and has a
  719.             // serial values.
  720.             // If that ever changes, the code has to be changed.
  721.            
  722.             // The calls to String.Compare should use the current culture for the string comparisons, but the
  723.             // invariant culture when comparing against the english names.
  724.             for (int i = 0; i < EraNames.Length; i++) {
  725.                 // Compare the era name in a case-insensitive way.
  726.                 if (m_eraNames[i].Length > 0) {
  727.                     if (String.Compare(eraName, m_eraNames[i], true, CultureInfo.CurrentCulture) == 0) {
  728.                         return (i + 1);
  729.                     }
  730.                 }
  731.             }
  732.             for (int i = 0; i < AbbreviatedEraNames.Length; i++) {
  733.                 if (String.Compare(eraName, m_abbrevEraNames[i], true, CultureInfo.CurrentCulture) == 0) {
  734.                     return (i + 1);
  735.                 }
  736.             }
  737.             for (int i = 0; i < AbbreviatedEnglishEraNames.Length; i++) {
  738.                 // this comparison should use the InvariantCulture. The English name could have linguistically
  739.                 // interesting characters.
  740.                 if (String.Compare(eraName, m_abbrevEnglishEraNames[i], true, CultureInfo.InvariantCulture) == 0) {
  741.                     return (i + 1);
  742.                 }
  743.             }
  744.             return (-1);
  745.         }
  746.        
  747.         internal string[] EraNames {
  748.             get {
  749.                 if (m_eraNames == null) {
  750.                     if (Calendar.ID == Calendar.CAL_GREGORIAN) {
  751.                         // If the calendar is Gregorian localized calendar,
  752.                         // grab the localized name from culture.nlp.
  753.                         m_eraNames = new string[1] {this.m_cultureTableRecord.SADERA};
  754.                     }
  755.                     else if (Calendar.ID != Calendar.CAL_TAIWAN) {
  756.                         // Use Calendar property so that we initialized the calendar when necessary.
  757.                         BCLDebug.Assert(Calendar.ID > 0, "[DateTimeFormatInfo.EraNames] Expected Calendar.ID > 0");
  758.                         m_eraNames = CalendarTable.Default.SERANAMES(Calendar.ID);
  759.                     }
  760.                     else {
  761.                         // Special case for Taiwan calendar.
  762.                         // 0x0404 is the locale ID for Taiwan.
  763.                         m_eraNames = new string[] {CalendarTable.nativeGetEraName(1028, Calendar.ID)};
  764.                     }
  765.                 }
  766.                 return (m_eraNames);
  767.             }
  768.         }
  769.        
  770. /*=================================GetEraName==========================
  771.         **Action: Get the name of the era for the specified era value.
  772.         **Returns: The name of the specified era.
  773.         **Arguments:
  774.         **      era the era value.
  775.         **Exceptions:
  776.         **      ArguementException if the era valie is invalid.
  777.         ============================================================================*/       
  778.        
  779.        
  780.         public string GetEraName(int era)
  781.         {
  782.             if (era == Calendar.CurrentEra) {
  783.                 era = Calendar.CurrentEraValue;
  784.             }
  785.            
  786.             // The following is based on the assumption that the era value is starting from 1, and has a
  787.             // serial values.
  788.             // If that ever changes, the code has to be changed.
  789.             if ((--era) < EraNames.Length && (era >= 0)) {
  790.                 return (m_eraNames[era]);
  791.             }
  792.             throw new ArgumentOutOfRangeException("era", Environment.GetResourceString("ArgumentOutOfRange_InvalidEraValue"));
  793.         }
  794.        
  795.         internal string[] AbbreviatedEraNames {
  796.             get {
  797.                 if (m_abbrevEraNames == null) {
  798.                     if (Calendar.ID == Calendar.CAL_TAIWAN) {
  799.