**** Merged from MCS ****
[mono-project.git] / mcs / class / corlib / System.Globalization / DateTimeFormatInfo.cs
blob8b205086977c7867275107a221bafdbd65d37ec4
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)
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
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.
33 using System;
34 using System.Collections;
35 using System.Threading;
37 namespace System.Globalization
39 [Serializable]
40 [MonoTODO ("Fix serialization compatibility with MS.NET")]
41 public sealed class DateTimeFormatInfo : ICloneable, IFormatProvider {
42 private static readonly string MSG_READONLY = "This instance is read only";
43 private static readonly string MSG_ARRAYSIZE_MONTH = "An array with exactly 13 elements is needed";
44 private static readonly string MSG_ARRAYSIZE_DAY = "An array with exactly 7 elements is needed";
45 private static readonly string[] INVARIANT_ABBREVIATED_DAY_NAMES
46 = new string[7] { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
47 private static readonly string[] INVARIANT_DAY_NAMES
48 = new string[7] { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
49 private static readonly string[] INVARIANT_ABBREVIATED_MONTH_NAMES
50 = new string[13] { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""};
51 private static readonly string[] INVARIANT_MONTH_NAMES
52 = new string[13] { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", ""};
53 private static readonly string[] INVARIANT_ERA_NAMES = {"A.D."};
55 private static DateTimeFormatInfo theInvariantDateTimeFormatInfo;
57 private bool readOnly;
58 private string _AMDesignator;
59 private string _PMDesignator;
60 private string _DateSeparator;
61 private string _TimeSeparator;
62 private string _ShortDatePattern;
63 private string _LongDatePattern;
64 private string _ShortTimePattern;
65 private string _LongTimePattern;
66 private string _MonthDayPattern;
67 private string _YearMonthPattern;
68 private string _FullDateTimePattern;
69 private string _RFC1123Pattern;
70 private string _SortableDateTimePattern;
71 private string _UniversalSortableDateTimePattern;
72 private DayOfWeek _FirstDayOfWeek;
73 private Calendar _Calendar;
74 private CalendarWeekRule _CalendarWeekRule;
75 private string[] _AbbreviatedDayNames;
76 private string[] _DayNames;
77 private string[] _MonthNames;
78 private string[] _AbbreviatedMonthNames;
80 // FIXME: not supported other than invariant
81 private string [] _ShortDatePatterns;
82 private string [] _LongDatePatterns;
83 private string [] _ShortTimePatterns;
84 private string [] _LongTimePatterns;
85 private string [] _MonthDayPatterns;
86 private string [] _YearMonthPatterns;
88 public DateTimeFormatInfo()
90 readOnly = false;
91 _AMDesignator = "AM";
92 _PMDesignator = "PM";
93 _DateSeparator = "/";
94 _TimeSeparator = ":";
95 _ShortDatePattern = "MM/dd/yyyy";
96 _LongDatePattern = "dddd, dd MMMM yyyy";
97 _ShortTimePattern = "HH:mm";
98 _LongTimePattern = "HH:mm:ss";
99 _MonthDayPattern = "MMMM dd";
100 _YearMonthPattern = "yyyy MMMM";
101 _FullDateTimePattern = "dddd, dd MMMM yyyy HH:mm:ss";
103 // FIXME: for the following three pattern: "The
104 // default value of this property is derived
105 // from the calendar that is set for
106 // CultureInfo.CurrentCulture or the default
107 // calendar of CultureInfo.CurrentCulture."
109 // Actually, no predefined culture has different values
110 // than those default values.
112 _RFC1123Pattern = "ddd, dd MMM yyyy HH':'mm':'ss 'GMT'";
113 _SortableDateTimePattern = "yyyy'-'MM'-'dd'T'HH':'mm':'ss";
114 _UniversalSortableDateTimePattern = "yyyy'-'MM'-'dd HH':'mm':'ss'Z'";
116 _FirstDayOfWeek = DayOfWeek.Sunday;
117 _Calendar = new GregorianCalendar();
118 _CalendarWeekRule = CalendarWeekRule.FirstDay;
120 _AbbreviatedDayNames = INVARIANT_ABBREVIATED_DAY_NAMES;
121 _DayNames = INVARIANT_DAY_NAMES;
122 _AbbreviatedMonthNames = INVARIANT_ABBREVIATED_MONTH_NAMES;
123 _MonthNames = INVARIANT_MONTH_NAMES;
126 // LAMESPEC: this is not in ECMA specs
127 public static DateTimeFormatInfo GetInstance(IFormatProvider provider)
129 if (provider != null) {
130 DateTimeFormatInfo dtfi;
131 dtfi = (DateTimeFormatInfo)provider.GetFormat(typeof(DateTimeFormatInfo));
132 if (dtfi != null)
133 return dtfi;
136 return CurrentInfo;
139 public bool IsReadOnly {
140 get {
141 return readOnly;
145 public static DateTimeFormatInfo ReadOnly(DateTimeFormatInfo dtfi)
147 DateTimeFormatInfo copy = (DateTimeFormatInfo)dtfi.Clone();
148 copy.readOnly = true;
149 return copy;
152 public object Clone ()
154 DateTimeFormatInfo clone = (DateTimeFormatInfo) MemberwiseClone();
155 // clone is not read only
156 clone.readOnly = false;
157 return clone;
160 public object GetFormat(Type formatType)
162 return (formatType == GetType()) ? this : null;
165 [MonoTODO]
166 public string GetAbbreviatedEraName(int era)
168 if (era < _Calendar.Eras.Length || era >= _Calendar.Eras.Length)
169 throw new ArgumentOutOfRangeException();
170 notImplemented();
171 //FIXME: implement me
172 return null;
175 public string GetAbbreviatedMonthName(int month)
177 if (month < 1 || month > 13) throw new ArgumentOutOfRangeException();
178 return _AbbreviatedMonthNames[month-1];
181 [MonoTODO]
182 public int GetEra(string eraName)
184 if (eraName == null) throw new ArgumentNullException();
185 eraName = eraName.ToUpper();
186 notImplemented();
187 //FIXME: implement me
188 return -1;
191 [MonoTODO]
192 public string GetEraName(int era)
194 // if (era < _Calendar.Eras.Length || era >= _Calendar.Eras.Length)
195 // throw new ArgumentOutOfRangeException();
196 try {
197 return INVARIANT_ERA_NAMES[era - 1];
199 catch {
200 //FIXME: implement me
201 notImplemented();
202 return null;
206 public string GetMonthName(int month)
208 if (month < 1 || month > 13) throw new ArgumentOutOfRangeException();
209 return _MonthNames[month-1];
212 public string[] AbbreviatedDayNames
216 return (string[]) _AbbreviatedDayNames.Clone();
220 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
221 if (value == null) throw new ArgumentNullException();
222 if (value.GetLength(0) != 7) throw new ArgumentException(MSG_ARRAYSIZE_DAY);
223 _AbbreviatedDayNames = (string[]) value.Clone();
227 public string[] AbbreviatedMonthNames
231 return (string[]) _AbbreviatedMonthNames.Clone();
235 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
236 if (value == null) throw new ArgumentNullException();
237 if (value.GetLength(0) != 13) throw new ArgumentException(MSG_ARRAYSIZE_MONTH);
238 _AbbreviatedMonthNames = (string[]) value.Clone();
242 public string[] DayNames
246 return (string[]) _DayNames.Clone();
250 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
251 if (value == null) throw new ArgumentNullException();
252 if (value.GetLength(0) != 7) throw new ArgumentException(MSG_ARRAYSIZE_DAY);
253 _DayNames = (string[]) value.Clone();
257 public string[] MonthNames
261 return (string[]) _MonthNames.Clone();
265 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
266 if (value == null) throw new ArgumentNullException();
267 if (value.GetLength(0) != 13) throw new ArgumentException(MSG_ARRAYSIZE_MONTH);
268 _MonthNames = (string[]) value.Clone();
272 public string AMDesignator
276 return _AMDesignator;
280 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
281 if (value == null) throw new ArgumentNullException();
282 _AMDesignator = value;
286 public string PMDesignator
290 return _PMDesignator;
294 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
295 if (value == null) throw new ArgumentNullException();
296 _PMDesignator = value;
300 public string DateSeparator
304 return _DateSeparator;
308 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
309 if (value == null) throw new ArgumentNullException();
310 _DateSeparator = value;
314 public string TimeSeparator
318 return _TimeSeparator;
322 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
323 if (value == null) throw new ArgumentNullException();
324 _TimeSeparator = value;
328 public string LongDatePattern
332 return _LongDatePattern;
336 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
337 if (value == null) throw new ArgumentNullException();
338 _LongDatePattern = value;
342 public string ShortDatePattern
346 return _ShortDatePattern;
350 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
351 if (value == null) throw new ArgumentNullException();
352 _ShortDatePattern = value;
356 public string ShortTimePattern
360 return _ShortTimePattern;
364 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
365 if (value == null) throw new ArgumentNullException();
366 _ShortTimePattern = value;
370 public string LongTimePattern
374 return _LongTimePattern;
378 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
379 if (value == null) throw new ArgumentNullException();
380 _LongTimePattern = value;
384 public string MonthDayPattern
388 return _MonthDayPattern;
392 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
393 if (value == null) throw new ArgumentNullException();
394 _MonthDayPattern = value;
398 public string YearMonthPattern
402 return _YearMonthPattern;
406 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
407 if (value == null) throw new ArgumentNullException();
408 _YearMonthPattern = value;
412 public string FullDateTimePattern
416 if(_FullDateTimePattern!=null) {
417 return _FullDateTimePattern;
418 } else {
419 return(_LongDatePattern + " " + _LongTimePattern);
424 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
425 if (value == null) throw new ArgumentNullException();
426 _FullDateTimePattern = value;
430 public static DateTimeFormatInfo CurrentInfo
434 return Thread.CurrentThread.CurrentCulture.DateTimeFormat;
438 public static DateTimeFormatInfo InvariantInfo
442 if (theInvariantDateTimeFormatInfo == null) {
443 theInvariantDateTimeFormatInfo =
444 DateTimeFormatInfo.ReadOnly(new DateTimeFormatInfo());
445 theInvariantDateTimeFormatInfo.FillInvariantPatterns ();
447 return theInvariantDateTimeFormatInfo;
451 // LAMESPEC: this is not in ECMA specs
452 public DayOfWeek FirstDayOfWeek
456 return _FirstDayOfWeek;
460 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
461 if ((int) value < 0 || (int) value > 6) throw new ArgumentOutOfRangeException();
462 _FirstDayOfWeek = value;
466 // LAMESPEC: this is not in ECMA specs
467 public Calendar Calendar
471 return _Calendar;
475 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
476 if (value == null) throw new ArgumentNullException();
477 _Calendar = value;
481 public CalendarWeekRule CalendarWeekRule
485 return _CalendarWeekRule;
489 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
490 _CalendarWeekRule = value;
494 // LAMESPEC: this is not in ECMA specs
495 public string RFC1123Pattern
499 return _RFC1123Pattern;
503 // LAMESPEC: this is not in ECMA specs
504 public string SortableDateTimePattern
508 return _SortableDateTimePattern;
512 // LAMESPEC: this is not in ECMA specs
513 public string UniversalSortableDateTimePattern
517 return _UniversalSortableDateTimePattern;
521 // LAMESPEC: this is not in ECMA specs
522 [MonoTODO ("Not complete depending on GetAllDateTimePatterns(char)")]
523 public string[] GetAllDateTimePatterns()
525 ArrayList al = new ArrayList ();
526 foreach (string s in GetAllDateTimePatterns ('d'))
527 al.Add (s);
528 foreach (string s in GetAllDateTimePatterns ('D'))
529 al.Add (s);
530 foreach (string s in GetAllDateTimePatterns ('g'))
531 al.Add (s);
532 foreach (string s in GetAllDateTimePatterns ('G'))
533 al.Add (s);
534 foreach (string s in GetAllDateTimePatterns ('f'))
535 al.Add (s);
536 foreach (string s in GetAllDateTimePatterns ('F'))
537 al.Add (s);
538 // Yes, that is very meaningless, but that is what MS
539 // is doing (LAMESPEC: Since it is documented that
540 // 'M' and 'm' are equal, they should not cosider
541 // that there is a possibility that 'M' and 'm' are
542 // different.)
543 foreach (string s in GetAllDateTimePatterns ('m'))
544 al.Add (s);
545 foreach (string s in GetAllDateTimePatterns ('M'))
546 al.Add (s);
547 foreach (string s in GetAllDateTimePatterns ('r'))
548 al.Add (s);
549 foreach (string s in GetAllDateTimePatterns ('R'))
550 al.Add (s);
551 foreach (string s in GetAllDateTimePatterns ('s'))
552 al.Add (s);
553 foreach (string s in GetAllDateTimePatterns ('t'))
554 al.Add (s);
555 foreach (string s in GetAllDateTimePatterns ('T'))
556 al.Add (s);
557 foreach (string s in GetAllDateTimePatterns ('u'))
558 al.Add (s);
559 foreach (string s in GetAllDateTimePatterns ('U'))
560 al.Add (s);
561 foreach (string s in GetAllDateTimePatterns ('y'))
562 al.Add (s);
563 foreach (string s in GetAllDateTimePatterns ('Y'))
564 al.Add (s);
566 return al.ToArray (typeof (string)) as string [];
569 // LAMESPEC: this is not in ECMA specs
570 [MonoTODO ("We need more culture data in locale-builder")]
571 public string[] GetAllDateTimePatterns (char format)
573 string [] list;
574 switch (format) {
575 // Date
576 case 'D':
577 if (_LongDatePatterns != null && _LongDatePatterns.Length > 0)
578 return _LongDatePatterns.Clone () as string [];
579 return new string [] {LongDatePattern};
580 case 'd':
581 if (_ShortDatePatterns != null && _ShortDatePatterns.Length > 0)
582 return _ShortDatePatterns.Clone () as string [];
583 return new string [] {ShortDatePattern};
584 // Time
585 case 'T':
586 if (_LongTimePatterns != null && _LongTimePatterns.Length > 0)
587 return _LongTimePatterns.Clone () as string [];
588 return new string [] {LongTimePattern};
589 case 't':
590 if (_ShortTimePatterns != null && _ShortTimePatterns.Length > 0)
591 return _ShortTimePatterns.Clone () as string [];
592 return new string [] {ShortTimePattern};
593 // {Short|Long}Date + {Short|Long}Time
594 // FIXME: they should be the agglegation of the
595 // combination of the Date patterns and Time patterns.
596 case 'G':
597 list = PopulateCombinedList (_ShortDatePatterns, _LongTimePatterns);
598 if (list != null && list.Length > 0)
599 return list;
600 return new string [] {ShortDatePattern + ' ' + LongTimePattern};
601 case 'g':
602 list = PopulateCombinedList (_ShortDatePatterns, _ShortTimePatterns);
603 if (list != null && list.Length > 0)
604 return list;
605 return new string [] {ShortDatePattern + ' ' + ShortTimePattern};
606 // The 'U' pattern strings are always the same as 'F'.
607 // (only differs in assuming UTC or not.)
608 case 'U':
609 case 'F':
610 list = PopulateCombinedList (_LongDatePatterns, _LongTimePatterns);
611 if (list != null && list.Length > 0)
612 return list;
613 return new string [] {LongDatePattern + ' ' + LongTimePattern};
614 case 'f':
615 list = PopulateCombinedList (_LongDatePatterns, _ShortTimePatterns);
616 if (list != null && list.Length > 0)
617 return list;
618 return new string [] {LongDatePattern + ' ' + ShortTimePattern};
619 // MonthDay
620 case 'm':
621 case 'M':
622 if (_MonthDayPatterns != null && _MonthDayPatterns.Length > 0)
623 return _MonthDayPatterns.Clone () as string [];
624 return new string [] {MonthDayPattern};
625 // YearMonth
626 case 'Y':
627 case 'y':
628 if (_YearMonthPatterns != null && _YearMonthPatterns.Length > 0)
629 return _YearMonthPatterns.Clone () as string [];
630 return new string [] {YearMonthPattern};
631 // RFC1123
632 case 'r':
633 case 'R':
634 return new string [] {RFC1123Pattern};
635 case 's':
636 return new string [] {SortableDateTimePattern};
637 case 'u':
638 return new string [] {UniversalSortableDateTimePattern};
640 throw new ArgumentException ("Format specifier was invalid.");
643 // LAMESPEC: this is not in ECMA specs
644 public string GetDayName(DayOfWeek dayofweek)
646 int index = (int) dayofweek;
647 if (index < 0 || index > 6) throw new ArgumentOutOfRangeException();
648 return _DayNames[index];
651 // LAMESPEC: this is not in ECMA specs
652 public string GetAbbreviatedDayName(DayOfWeek dayofweek)
654 int index = (int) dayofweek;
655 if (index < 0 || index > 6) throw new ArgumentOutOfRangeException();
656 return _AbbreviatedDayNames[index];
659 private void FillInvariantPatterns ()
661 _ShortDatePatterns = new string [] {"MM/dd/yyyy"};
662 _LongDatePatterns = new string [] {"dddd, dd MMMM yyyy"};
663 _LongTimePatterns = new string [] {"HH:mm:ss"};
664 _ShortTimePatterns = new string [] {
665 "HH:mm",
666 "hh:mm tt",
667 "H:mm",
668 "h:mm tt"
670 _MonthDayPatterns = new string [] {"MMMM dd"};
671 _YearMonthPatterns = new string [] {"yyyy MMMM"};
674 private string [] PopulateCombinedList (string [] dates, string [] times)
676 if (dates != null && times != null) {
677 string [] list = new string [dates.Length * times.Length];
678 int i = 0;
679 foreach (string d in dates)
680 foreach (string t in times)
681 list [i++] = d + ' ' + t;
682 return list;
684 return null;
687 private static void notImplemented()
689 throw new Exception("Not implemented");