New test.
[mono.git] / mcs / class / corlib / System.Globalization / DateTimeFormatInfo.cs
1 // System.Globalization.DateTimeFormatInfo
2 //
3 // Some useful functions are missing in the ECMA specs.
4 // They have been added following MS SDK Beta2
5 //
6 // Martin Weindel (martin.weindel@t-online.de)
7 //
8 // (C) Martin Weindel (martin.weindel@t-online.de)
9
10 //
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 using System;
34 using System.Collections;
35 using System.Threading;
36
37 namespace System.Globalization
38 {
39         [Serializable]
40         public sealed class DateTimeFormatInfo : ICloneable, IFormatProvider {
41                 private static readonly string MSG_READONLY = "This instance is read only";
42                 private static readonly string MSG_ARRAYSIZE_MONTH = "An array with exactly 13 elements is needed";
43                 private static readonly string MSG_ARRAYSIZE_DAY = "An array with exactly 7 elements is needed";
44                 private static readonly string[] INVARIANT_ABBREVIATED_DAY_NAMES
45                         = new string[7] { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
46                 private static readonly string[] INVARIANT_DAY_NAMES
47                         = new string[7] { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
48                 private static readonly string[] INVARIANT_ABBREVIATED_MONTH_NAMES
49                         = new string[13] { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""};
50                 private static readonly string[] INVARIANT_MONTH_NAMES
51                         = new string[13] { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ""};
52                 private static readonly string[] INVARIANT_ERA_NAMES = {"A.D."};
53
54                 private static DateTimeFormatInfo theInvariantDateTimeFormatInfo;
55
56                 //
57                 // BIG FAT WARNING:
58                 //
59                 // DO NOT ALTER THE NAME OR ORDER OF THESE FIELDS
60                 // AND DO NOT INSERT ANY VARIABLES ANYWHERE BUT AT THE END
61                 // SINCE MONO RELIES ON THE ORDER AND ON THE NAMES
62                 // see mono/mono/metadata/verify.c
63                 //
64                 private bool m_isReadOnly;
65                 private string amDesignator;
66                 private string pmDesignator;
67                 private string dateSeparator;
68                 private string timeSeparator;
69                 private string shortDatePattern;
70                 private string longDatePattern;
71                 private string shortTimePattern;
72                 private string longTimePattern;
73                 private string monthDayPattern;
74                 private string yearMonthPattern;
75                 private string fullDateTimePattern;
76                 private string _RFC1123Pattern;
77                 private string _SortableDateTimePattern;
78                 private string _UniversalSortableDateTimePattern;
79                 private DayOfWeek firstDayOfWeek;
80                 private Calendar calendar;
81                 private CalendarWeekRule calendarWeekRule;
82                 private string[] abbreviatedDayNames;
83                 private string[] dayNames;
84                 private string[] monthNames;
85                 private string[] abbreviatedMonthNames;
86
87                 // FIXME: not supported other than invariant
88                 private string [] allShortDatePatterns;
89                 private string [] allLongDatePatterns;
90                 private string [] allShortTimePatterns;
91                 private string [] allLongTimePatterns;
92                 private string [] monthDayPatterns;
93                 private string [] yearMonthPatterns;
94
95                 //
96                 // END OF BIG FAT WARNING
97                 //
98
99                 // MS Serialization needs this
100                 private int nDataItem;
101                 private bool m_useUserOverride;
102                 private bool m_isDefaultCalendar;
103                 private int CultureID;
104                 private bool bUseCalendarInfo;
105                 private string generalShortTimePattern;
106                 private string generalLongTimePattern;
107                 private string[] m_eraNames;
108                 private string[] m_abbrevEraNames;
109                 private string[] m_abbrevEnglishEraNames;
110                 private string[] m_dateWords;
111                 private int[] optionalCalendars;
112
113                 public DateTimeFormatInfo()
114                 {
115                         m_isReadOnly = false;
116                         amDesignator = "AM";
117                         pmDesignator = "PM";
118                         dateSeparator = "/";
119                         timeSeparator = ":";
120                         shortDatePattern = "MM/dd/yyyy";
121                         longDatePattern = "dddd, dd MMMM yyyy";
122                         shortTimePattern = "HH:mm";
123                         longTimePattern = "HH:mm:ss";
124                         monthDayPattern = "MMMM dd";
125                         yearMonthPattern = "yyyy MMMM";
126                         fullDateTimePattern = "dddd, dd MMMM yyyy HH:mm:ss";
127
128                         // FIXME: for the following three pattern: "The
129                         // default value of this property is derived
130                         // from the calendar that is set for
131                         // CultureInfo.CurrentCulture or the default
132                         // calendar of CultureInfo.CurrentCulture."
133
134                         // Actually, no predefined culture has different values
135                         // than those default values.
136
137                         _RFC1123Pattern = "ddd, dd MMM yyyy HH':'mm':'ss 'GMT'"; 
138                         _SortableDateTimePattern = "yyyy'-'MM'-'dd'T'HH':'mm':'ss";
139                         _UniversalSortableDateTimePattern = "yyyy'-'MM'-'dd HH':'mm':'ss'Z'";
140
141                         firstDayOfWeek = DayOfWeek.Sunday;
142                         calendar = new GregorianCalendar();
143                         calendarWeekRule = CalendarWeekRule.FirstDay;
144
145                         abbreviatedDayNames = INVARIANT_ABBREVIATED_DAY_NAMES;
146                         dayNames = INVARIANT_DAY_NAMES;
147                         abbreviatedMonthNames = INVARIANT_ABBREVIATED_MONTH_NAMES;
148                         monthNames = INVARIANT_MONTH_NAMES;
149                 }
150                                 
151                 // LAMESPEC: this is not in ECMA specs
152                 public static DateTimeFormatInfo GetInstance(IFormatProvider provider)
153                 {
154                         if (provider != null) {
155                                 DateTimeFormatInfo dtfi;
156                                 dtfi = (DateTimeFormatInfo)provider.GetFormat(typeof(DateTimeFormatInfo));
157                                 if (dtfi != null)
158                                         return dtfi;
159                         }
160                         
161                         return CurrentInfo;
162                 }
163
164                 public bool IsReadOnly {
165                         get {
166                                 return m_isReadOnly;
167                         }
168                 }
169
170                 public static DateTimeFormatInfo ReadOnly(DateTimeFormatInfo dtfi)
171                 {
172                         DateTimeFormatInfo copy = (DateTimeFormatInfo)dtfi.Clone();
173                         copy.m_isReadOnly = true;
174                         return copy;
175                 }                       
176
177                 public object Clone () 
178                 {
179                         DateTimeFormatInfo clone = (DateTimeFormatInfo) MemberwiseClone();
180                         // clone is not read only
181                         clone.m_isReadOnly = false;
182                         return clone;
183                 }
184
185                 public object GetFormat(Type formatType)
186                 {
187                         return (formatType == GetType()) ? this : null;
188                 }
189
190                 public string GetAbbreviatedEraName (int era)
191                 {
192                         if (era < 0 || era >= calendar.AbbreviatedEraNames.Length)
193                                 throw new ArgumentOutOfRangeException ("era", era.ToString ());
194                         return calendar.AbbreviatedEraNames [era];
195                 }
196
197                 public string GetAbbreviatedMonthName(int month)
198                 {
199                         if (month < 1 || month > 13) throw new ArgumentOutOfRangeException();
200                         return abbreviatedMonthNames[month-1];
201                 }
202
203                 public int GetEra (string eraName)
204                 {
205                         if (eraName == null)
206                                 throw new ArgumentNullException ();
207                         string [] eras = calendar.EraNames;
208                         for (int i = 0; i < eras.Length; i++)
209                                 if (CultureInfo.InvariantCulture.CompareInfo
210                                         .Compare (eraName, eras [i],
211                                         CompareOptions.IgnoreCase) == 0)
212                                         return i;
213                         return -1;
214                 }
215
216                 public string GetEraName (int era)
217                 {
218                         if (era < 0 || era > calendar.EraNames.Length)
219                                 throw new ArgumentOutOfRangeException ("era", era.ToString ());
220                         return calendar.EraNames [era - 1];
221                 }
222
223                 public string GetMonthName(int month)
224                 {
225                         if (month < 1 || month > 13) throw new ArgumentOutOfRangeException();
226                         return monthNames[month-1];
227                 }
228
229                 public string[] AbbreviatedDayNames
230                 {
231                         get
232                         {
233                                 return (string[]) abbreviatedDayNames.Clone();
234                         }
235                         set
236                         {
237                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
238                                 if (value == null) throw new ArgumentNullException();
239                                 if (value.GetLength(0) != 7) throw new ArgumentException(MSG_ARRAYSIZE_DAY);
240                                 abbreviatedDayNames = (string[]) value.Clone();
241                         }
242                 }
243
244                 public string[] AbbreviatedMonthNames
245                 {
246                         get
247                         {
248                                 return (string[]) abbreviatedMonthNames.Clone();
249                         }
250                         set
251                         {
252                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
253                                 if (value == null) throw new ArgumentNullException();
254                                 if (value.GetLength(0) != 13) throw new ArgumentException(MSG_ARRAYSIZE_MONTH);
255                                 abbreviatedMonthNames = (string[]) value.Clone();
256                         }
257                 }
258
259                 public string[] DayNames
260                 {
261                         get
262                         {
263                                 return (string[]) dayNames.Clone();
264                         }
265                         set
266                         {
267                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
268                                 if (value == null) throw new ArgumentNullException();
269                                 if (value.GetLength(0) != 7) throw new ArgumentException(MSG_ARRAYSIZE_DAY);
270                                 dayNames = (string[]) value.Clone();
271                         }
272                 }
273
274                 public string[] MonthNames
275                 {
276                         get
277                         {
278                                 return (string[]) monthNames.Clone();
279                         }
280                         set
281                         {
282                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
283                                 if (value == null) throw new ArgumentNullException();
284                                 if (value.GetLength(0) != 13) throw new ArgumentException(MSG_ARRAYSIZE_MONTH);
285                                 monthNames = (string[]) value.Clone();
286                         }
287                 }
288
289                 public string AMDesignator
290                 {
291                         get
292                         {
293                                 return amDesignator;
294                         }
295                         set
296                         {
297                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
298                                 if (value == null) throw new ArgumentNullException();
299                                 amDesignator = value;
300                         }
301                 }
302
303                 public string PMDesignator
304                 {
305                         get
306                         {
307                                 return pmDesignator;
308                         }
309                         set
310                         {
311                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
312                                 if (value == null) throw new ArgumentNullException();
313                                 pmDesignator = value;
314                         }
315                 }
316
317                 public string DateSeparator
318                 {
319                         get
320                         {
321                                 return dateSeparator;
322                         }
323                         set
324                         {
325                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
326                                 if (value == null) throw new ArgumentNullException();
327                                 dateSeparator = value;
328                         }
329                 }
330
331                 public string TimeSeparator
332                 {
333                         get
334                         {
335                                 return timeSeparator;
336                         }
337                         set
338                         {
339                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
340                                 if (value == null) throw new ArgumentNullException();
341                                 timeSeparator = value;
342                         }
343                 }
344
345                 public string LongDatePattern
346                 {
347                         get
348                         {
349                                 return longDatePattern;
350                         }
351                         set
352                         {
353                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
354                                 if (value == null) throw new ArgumentNullException();
355                                 longDatePattern = value;
356                         }
357                 }
358
359                 public string ShortDatePattern
360                 {
361                         get
362                         {
363                                 return shortDatePattern;
364                         }
365                         set
366                         {
367                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
368                                 if (value == null) throw new ArgumentNullException();
369                                 shortDatePattern = value;
370                         }
371                 }
372
373                 public string ShortTimePattern
374                 {
375                         get
376                         {
377                                 return shortTimePattern;
378                         }
379                         set
380                         {
381                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
382                                 if (value == null) throw new ArgumentNullException();
383                                 shortTimePattern = value;
384                         }
385                 }
386
387                 public string LongTimePattern
388                 {
389                         get
390                         {
391                                 return longTimePattern;
392                         }
393                         set
394                         {
395                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
396                                 if (value == null) throw new ArgumentNullException();
397                                 longTimePattern = value;
398                         }
399                 }
400
401                 public string MonthDayPattern
402                 {
403                         get
404                         {
405                                 return monthDayPattern;
406                         }
407                         set
408                         {
409                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
410                                 if (value == null) throw new ArgumentNullException();
411                                 monthDayPattern = value;
412                         }
413                 }
414
415                 public string YearMonthPattern
416                 {
417                         get
418                         {
419                                 return yearMonthPattern;
420                         }
421                         set
422                         {
423                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
424                                 if (value == null) throw new ArgumentNullException();
425                                 yearMonthPattern = value;
426                         }
427                 }
428
429                 public string FullDateTimePattern
430                 {
431                         get
432                         {
433                                 if(fullDateTimePattern!=null) {
434                                         return fullDateTimePattern;
435                                 } else {
436                                         return(longDatePattern + " " + longTimePattern);
437                                 }
438                         }
439                         set
440                         {
441                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
442                                 if (value == null) throw new ArgumentNullException();
443                                 fullDateTimePattern = value;
444                         }
445                 }
446
447                 public static DateTimeFormatInfo CurrentInfo
448                 {
449                         get
450                         {
451                                 return Thread.CurrentThread.CurrentCulture.DateTimeFormat;
452                         }
453                 }
454
455                 public static DateTimeFormatInfo InvariantInfo
456                 {
457                         get
458                         {
459                                 if (theInvariantDateTimeFormatInfo == null) {
460                                         theInvariantDateTimeFormatInfo = 
461                                                 DateTimeFormatInfo.ReadOnly(new DateTimeFormatInfo());
462                                         theInvariantDateTimeFormatInfo.FillInvariantPatterns ();
463                                 }
464                                 return theInvariantDateTimeFormatInfo;
465                         }
466                 }
467
468                 // LAMESPEC: this is not in ECMA specs
469                 public DayOfWeek FirstDayOfWeek
470                 {
471                         get
472                         {
473                                 return firstDayOfWeek;
474                         }
475                         set
476                         {
477                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
478                                 if ((int) value < 0 || (int) value > 6) throw new ArgumentOutOfRangeException();
479                                 firstDayOfWeek = value;
480                         }
481                 }
482
483                 // LAMESPEC: this is not in ECMA specs
484                 public Calendar Calendar
485                 {
486                         get
487                         {
488                                 return calendar;
489                         }
490                         set
491                         {
492                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
493                                 if (value == null) throw new ArgumentNullException();
494                                 calendar = value;
495                         }
496                 }
497
498                 public CalendarWeekRule CalendarWeekRule
499                 {
500                         get
501                         {
502                                 return calendarWeekRule;
503                         }
504                         set
505                         {
506                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
507                                 calendarWeekRule = value;
508                         }
509                 }
510
511                 // LAMESPEC: this is not in ECMA specs
512                 public string RFC1123Pattern
513                 {
514                         get
515                         {
516                                 return _RFC1123Pattern;
517                         }
518                 }
519
520                 // LAMESPEC: this is not in ECMA specs
521                 public string SortableDateTimePattern
522                 {
523                         get
524                         {
525                                 return _SortableDateTimePattern;
526                         }
527                 }
528
529                 // LAMESPEC: this is not in ECMA specs
530                 public string UniversalSortableDateTimePattern
531                 {
532                         get
533                         {
534                                 return _UniversalSortableDateTimePattern;
535                         }
536                 }
537                 
538                 // LAMESPEC: this is not in ECMA specs
539                 [MonoTODO ("Not complete depending on GetAllDateTimePatterns(char)")]
540                 public string[] GetAllDateTimePatterns() 
541                 {
542                         FillAllDateTimePatterns ();
543                         return (string []) all_date_time_patterns.Clone ();
544                 }
545
546
547                 // Same as above, but with no cloning, because we know that
548                 // clients are friendly
549                 internal string [] GetAllDateTimePatternsInternal ()
550                 {
551                         FillAllDateTimePatterns ();
552                         return all_date_time_patterns;
553                 }
554                 
555                 // Prevent write reordering
556                 volatile string [] all_date_time_patterns;
557                 
558                 void FillAllDateTimePatterns (){
559
560                         if (all_date_time_patterns != null)
561                                 return;
562                         
563                         ArrayList al = new ArrayList ();
564                         foreach (string s in GetAllDateTimePatterns ('d'))
565                                 al.Add (s);
566                         foreach (string s in GetAllDateTimePatterns ('D'))
567                                 al.Add (s);
568                         foreach (string s in GetAllDateTimePatterns ('g'))
569                                 al.Add (s);
570                         foreach (string s in GetAllDateTimePatterns ('G'))
571                                 al.Add (s);
572                         foreach (string s in GetAllDateTimePatterns ('f'))
573                                 al.Add (s);
574                         foreach (string s in GetAllDateTimePatterns ('F'))
575                                 al.Add (s);
576                         // Yes, that is very meaningless, but that is what MS
577                         // is doing (LAMESPEC: Since it is documented that
578                         // 'M' and 'm' are equal, they should not cosider
579                         // that there is a possibility that 'M' and 'm' are
580                         // different.)
581                         foreach (string s in GetAllDateTimePatterns ('m'))
582                                 al.Add (s);
583                         foreach (string s in GetAllDateTimePatterns ('M'))
584                                 al.Add (s);
585                         foreach (string s in GetAllDateTimePatterns ('r'))
586                                 al.Add (s);
587                         foreach (string s in GetAllDateTimePatterns ('R'))
588                                 al.Add (s);
589                         foreach (string s in GetAllDateTimePatterns ('s'))
590                                 al.Add (s);
591                         foreach (string s in GetAllDateTimePatterns ('t'))
592                                 al.Add (s);
593                         foreach (string s in GetAllDateTimePatterns ('T'))
594                                 al.Add (s);
595                         foreach (string s in GetAllDateTimePatterns ('u'))
596                                 al.Add (s);
597                         foreach (string s in GetAllDateTimePatterns ('U'))
598                                 al.Add (s);
599                         foreach (string s in GetAllDateTimePatterns ('y'))
600                                 al.Add (s);
601                         foreach (string s in GetAllDateTimePatterns ('Y'))
602                                 al.Add (s);
603
604                         // all_date_time_patterns needs to be volatile to prevent
605                         // reordering of writes here and still avoid any locking.
606                         all_date_time_patterns = (string []) al.ToArray (typeof (string)) as string [];
607                 }
608
609                 // LAMESPEC: this is not in ECMA specs
610                 [MonoTODO ("We need more culture data in locale-builder")]
611                 public string[] GetAllDateTimePatterns (char format)
612                 {
613                         string [] list;
614                         switch (format) {
615                         // Date
616                         case 'D':
617                                 if (allLongDatePatterns != null && allLongDatePatterns.Length > 0)
618                                         return allLongDatePatterns.Clone () as string [];
619                                 return new string [] {LongDatePattern};
620                         case 'd':
621                                 if (allShortDatePatterns != null && allShortDatePatterns.Length > 0)
622                                         return allShortDatePatterns.Clone () as string [];
623                                 return new string [] {ShortDatePattern};
624                         // Time
625                         case 'T':
626                                 if (allLongTimePatterns != null && allLongTimePatterns.Length > 0)
627                                         return allLongTimePatterns.Clone () as string [];
628                                 return new string [] {LongTimePattern};
629                         case 't':
630                                 if (allShortTimePatterns != null && allShortTimePatterns.Length > 0)
631                                         return allShortTimePatterns.Clone () as string [];
632                                 return new string [] {ShortTimePattern};
633                         // {Short|Long}Date + {Short|Long}Time
634                         // FIXME: they should be the agglegation of the
635                         // combination of the Date patterns and Time patterns.
636                         case 'G':
637                                 list = PopulateCombinedList (allShortDatePatterns, allLongTimePatterns);
638                                 if (list != null && list.Length > 0)
639                                         return list;
640                                 return new string [] {ShortDatePattern + " " + LongTimePattern};
641                         case 'g':
642                                 list = PopulateCombinedList (allShortDatePatterns, allShortTimePatterns);
643                                 if (list != null && list.Length > 0)
644                                         return list;
645                                 return new string [] {ShortDatePattern + " " + ShortTimePattern};
646                         // The 'U' pattern strings are always the same as 'F'.
647                         // (only differs in assuming UTC or not.)
648                         case 'U':
649                         case 'F':
650                                 list = PopulateCombinedList (allLongDatePatterns, allLongTimePatterns);
651                                 if (list != null && list.Length > 0)
652                                         return list;
653                                 return new string [] {LongDatePattern + " " + LongTimePattern};
654                         case 'f':
655                                 list = PopulateCombinedList (allLongDatePatterns, allShortTimePatterns);
656                                 if (list != null && list.Length > 0)
657                                         return list;
658                                 return new string [] {LongDatePattern + " " + ShortTimePattern};
659                         // MonthDay
660                         case 'm':
661                         case 'M':
662                                 if (monthDayPatterns != null && monthDayPatterns.Length > 0)
663                                         return monthDayPatterns.Clone () as string [];
664                                 return new string [] {MonthDayPattern};
665                         // YearMonth
666                         case 'Y':
667                         case 'y':
668                                 if (yearMonthPatterns != null && yearMonthPatterns.Length > 0)
669                                         return yearMonthPatterns.Clone () as string [];
670                                 return new string [] {YearMonthPattern};
671                         // RFC1123
672                         case 'r':
673                         case 'R':
674                                 return new string [] {RFC1123Pattern};
675                         case 's':
676                                 return new string [] {SortableDateTimePattern};
677                         case 'u':
678                                 return new string [] {UniversalSortableDateTimePattern};
679                         }
680                         throw new ArgumentException ("Format specifier was invalid.");
681                 }
682
683                 // LAMESPEC: this is not in ECMA specs
684                 public string GetDayName(DayOfWeek dayofweek)
685                 {
686                         int index = (int) dayofweek;
687                         if (index < 0 || index > 6) throw new ArgumentOutOfRangeException();
688                         return dayNames[index];
689                 }
690
691                 // LAMESPEC: this is not in ECMA specs
692                 public string GetAbbreviatedDayName(DayOfWeek dayofweek)
693                 {
694                         int index = (int) dayofweek;
695                         if (index < 0 || index > 6) throw new ArgumentOutOfRangeException();
696                         return abbreviatedDayNames[index];
697                 }
698
699                 private void FillInvariantPatterns ()
700                 {
701                         allShortDatePatterns = new string [] {"MM/dd/yyyy"};
702                         allLongDatePatterns = new string [] {"dddd, dd MMMM yyyy"};
703                         allLongTimePatterns = new string [] {"HH:mm:ss"};
704                         allShortTimePatterns = new string [] {
705                                 "HH:mm",
706                                 "hh:mm tt",
707                                 "H:mm",
708                                 "h:mm tt"
709                         };
710                         monthDayPatterns = new string [] {"MMMM dd"};
711                         yearMonthPatterns = new string [] {"yyyy MMMM"};
712                 }
713
714                 private string [] PopulateCombinedList (string [] dates, string [] times)
715                 {
716                         if (dates != null && times != null) {
717                                 string [] list = new string [dates.Length * times.Length];
718                                 int i = 0;
719                                 foreach (string d in dates)
720                                         foreach (string t in times)
721                                                 list [i++] = d + " " + t;
722                                 return list;
723                         }
724                         return null;
725                 }
726         }
727 }