1 // System.Globalization.DateTimeFormatInfo
3 // Some useful functions are missing in the ECMA specs.
4 // They have been added following MS SDK Beta2
6 // Martin Weindel (martin.weindel@t-online.de)
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:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
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.
34 using System.Collections;
35 using System.Threading;
37 namespace System.Globalization
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()
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));
139 public bool IsReadOnly {
145 public static DateTimeFormatInfo ReadOnly(DateTimeFormatInfo dtfi)
147 DateTimeFormatInfo copy = (DateTimeFormatInfo)dtfi.Clone();
148 copy.readOnly = true;
152 public object Clone ()
154 DateTimeFormatInfo clone = (DateTimeFormatInfo) MemberwiseClone();
155 // clone is not read only
156 clone.readOnly = false;
160 public object GetFormat(Type formatType)
162 return (formatType == GetType()) ? this : null;
165 public string GetAbbreviatedEraName (int era)
167 if (era < 0 || era >= _Calendar.AbbreviatedEraNames.Length)
168 throw new ArgumentOutOfRangeException ("era", era.ToString ());
169 return _Calendar.AbbreviatedEraNames [era];
172 public string GetAbbreviatedMonthName(int month)
174 if (month < 1 || month > 13) throw new ArgumentOutOfRangeException();
175 return _AbbreviatedMonthNames[month-1];
178 public int GetEra (string eraName)
181 throw new ArgumentNullException ();
182 string [] eras = _Calendar.EraNames;
183 for (int i = 0; i < eras.Length; i++)
184 if (CultureInfo.InvariantCulture.CompareInfo
185 .Compare (eraName, eras [i],
186 CompareOptions.IgnoreCase) == 0)
191 public string GetEraName (int era)
193 if (era < 0 || era > _Calendar.EraNames.Length)
194 throw new ArgumentOutOfRangeException ("era", era.ToString ());
195 return _Calendar.EraNames [era - 1];
198 public string GetMonthName(int month)
200 if (month < 1 || month > 13) throw new ArgumentOutOfRangeException();
201 return _MonthNames[month-1];
204 public string[] AbbreviatedDayNames
208 return (string[]) _AbbreviatedDayNames.Clone();
212 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
213 if (value == null) throw new ArgumentNullException();
214 if (value.GetLength(0) != 7) throw new ArgumentException(MSG_ARRAYSIZE_DAY);
215 _AbbreviatedDayNames = (string[]) value.Clone();
219 public string[] AbbreviatedMonthNames
223 return (string[]) _AbbreviatedMonthNames.Clone();
227 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
228 if (value == null) throw new ArgumentNullException();
229 if (value.GetLength(0) != 13) throw new ArgumentException(MSG_ARRAYSIZE_MONTH);
230 _AbbreviatedMonthNames = (string[]) value.Clone();
234 public string[] DayNames
238 return (string[]) _DayNames.Clone();
242 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
243 if (value == null) throw new ArgumentNullException();
244 if (value.GetLength(0) != 7) throw new ArgumentException(MSG_ARRAYSIZE_DAY);
245 _DayNames = (string[]) value.Clone();
249 public string[] MonthNames
253 return (string[]) _MonthNames.Clone();
257 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
258 if (value == null) throw new ArgumentNullException();
259 if (value.GetLength(0) != 13) throw new ArgumentException(MSG_ARRAYSIZE_MONTH);
260 _MonthNames = (string[]) value.Clone();
264 public string AMDesignator
268 return _AMDesignator;
272 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
273 if (value == null) throw new ArgumentNullException();
274 _AMDesignator = value;
278 public string PMDesignator
282 return _PMDesignator;
286 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
287 if (value == null) throw new ArgumentNullException();
288 _PMDesignator = value;
292 public string DateSeparator
296 return _DateSeparator;
300 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
301 if (value == null) throw new ArgumentNullException();
302 _DateSeparator = value;
306 public string TimeSeparator
310 return _TimeSeparator;
314 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
315 if (value == null) throw new ArgumentNullException();
316 _TimeSeparator = value;
320 public string LongDatePattern
324 return _LongDatePattern;
328 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
329 if (value == null) throw new ArgumentNullException();
330 _LongDatePattern = value;
334 public string ShortDatePattern
338 return _ShortDatePattern;
342 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
343 if (value == null) throw new ArgumentNullException();
344 _ShortDatePattern = value;
348 public string ShortTimePattern
352 return _ShortTimePattern;
356 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
357 if (value == null) throw new ArgumentNullException();
358 _ShortTimePattern = value;
362 public string LongTimePattern
366 return _LongTimePattern;
370 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
371 if (value == null) throw new ArgumentNullException();
372 _LongTimePattern = value;
376 public string MonthDayPattern
380 return _MonthDayPattern;
384 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
385 if (value == null) throw new ArgumentNullException();
386 _MonthDayPattern = value;
390 public string YearMonthPattern
394 return _YearMonthPattern;
398 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
399 if (value == null) throw new ArgumentNullException();
400 _YearMonthPattern = value;
404 public string FullDateTimePattern
408 if(_FullDateTimePattern!=null) {
409 return _FullDateTimePattern;
411 return(_LongDatePattern + " " + _LongTimePattern);
416 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
417 if (value == null) throw new ArgumentNullException();
418 _FullDateTimePattern = value;
422 public static DateTimeFormatInfo CurrentInfo
426 return Thread.CurrentThread.CurrentCulture.DateTimeFormat;
430 public static DateTimeFormatInfo InvariantInfo
434 if (theInvariantDateTimeFormatInfo == null) {
435 theInvariantDateTimeFormatInfo =
436 DateTimeFormatInfo.ReadOnly(new DateTimeFormatInfo());
437 theInvariantDateTimeFormatInfo.FillInvariantPatterns ();
439 return theInvariantDateTimeFormatInfo;
443 // LAMESPEC: this is not in ECMA specs
444 public DayOfWeek FirstDayOfWeek
448 return _FirstDayOfWeek;
452 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
453 if ((int) value < 0 || (int) value > 6) throw new ArgumentOutOfRangeException();
454 _FirstDayOfWeek = value;
458 // LAMESPEC: this is not in ECMA specs
459 public Calendar Calendar
467 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
468 if (value == null) throw new ArgumentNullException();
473 public CalendarWeekRule CalendarWeekRule
477 return _CalendarWeekRule;
481 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
482 _CalendarWeekRule = value;
486 // LAMESPEC: this is not in ECMA specs
487 public string RFC1123Pattern
491 return _RFC1123Pattern;
495 // LAMESPEC: this is not in ECMA specs
496 public string SortableDateTimePattern
500 return _SortableDateTimePattern;
504 // LAMESPEC: this is not in ECMA specs
505 public string UniversalSortableDateTimePattern
509 return _UniversalSortableDateTimePattern;
513 // LAMESPEC: this is not in ECMA specs
514 [MonoTODO ("Not complete depending on GetAllDateTimePatterns(char)")]
515 public string[] GetAllDateTimePatterns()
517 ArrayList al = new ArrayList ();
518 foreach (string s in GetAllDateTimePatterns ('d'))
520 foreach (string s in GetAllDateTimePatterns ('D'))
522 foreach (string s in GetAllDateTimePatterns ('g'))
524 foreach (string s in GetAllDateTimePatterns ('G'))
526 foreach (string s in GetAllDateTimePatterns ('f'))
528 foreach (string s in GetAllDateTimePatterns ('F'))
530 // Yes, that is very meaningless, but that is what MS
531 // is doing (LAMESPEC: Since it is documented that
532 // 'M' and 'm' are equal, they should not cosider
533 // that there is a possibility that 'M' and 'm' are
535 foreach (string s in GetAllDateTimePatterns ('m'))
537 foreach (string s in GetAllDateTimePatterns ('M'))
539 foreach (string s in GetAllDateTimePatterns ('r'))
541 foreach (string s in GetAllDateTimePatterns ('R'))
543 foreach (string s in GetAllDateTimePatterns ('s'))
545 foreach (string s in GetAllDateTimePatterns ('t'))
547 foreach (string s in GetAllDateTimePatterns ('T'))
549 foreach (string s in GetAllDateTimePatterns ('u'))
551 foreach (string s in GetAllDateTimePatterns ('U'))
553 foreach (string s in GetAllDateTimePatterns ('y'))
555 foreach (string s in GetAllDateTimePatterns ('Y'))
558 return al.ToArray (typeof (string)) as string [];
561 // LAMESPEC: this is not in ECMA specs
562 [MonoTODO ("We need more culture data in locale-builder")]
563 public string[] GetAllDateTimePatterns (char format)
569 if (_LongDatePatterns != null && _LongDatePatterns.Length > 0)
570 return _LongDatePatterns.Clone () as string [];
571 return new string [] {LongDatePattern};
573 if (_ShortDatePatterns != null && _ShortDatePatterns.Length > 0)
574 return _ShortDatePatterns.Clone () as string [];
575 return new string [] {ShortDatePattern};
578 if (_LongTimePatterns != null && _LongTimePatterns.Length > 0)
579 return _LongTimePatterns.Clone () as string [];
580 return new string [] {LongTimePattern};
582 if (_ShortTimePatterns != null && _ShortTimePatterns.Length > 0)
583 return _ShortTimePatterns.Clone () as string [];
584 return new string [] {ShortTimePattern};
585 // {Short|Long}Date + {Short|Long}Time
586 // FIXME: they should be the agglegation of the
587 // combination of the Date patterns and Time patterns.
589 list = PopulateCombinedList (_ShortDatePatterns, _LongTimePatterns);
590 if (list != null && list.Length > 0)
592 return new string [] {ShortDatePattern + ' ' + LongTimePattern};
594 list = PopulateCombinedList (_ShortDatePatterns, _ShortTimePatterns);
595 if (list != null && list.Length > 0)
597 return new string [] {ShortDatePattern + ' ' + ShortTimePattern};
598 // The 'U' pattern strings are always the same as 'F'.
599 // (only differs in assuming UTC or not.)
602 list = PopulateCombinedList (_LongDatePatterns, _LongTimePatterns);
603 if (list != null && list.Length > 0)
605 return new string [] {LongDatePattern + ' ' + LongTimePattern};
607 list = PopulateCombinedList (_LongDatePatterns, _ShortTimePatterns);
608 if (list != null && list.Length > 0)
610 return new string [] {LongDatePattern + ' ' + ShortTimePattern};
614 if (_MonthDayPatterns != null && _MonthDayPatterns.Length > 0)
615 return _MonthDayPatterns.Clone () as string [];
616 return new string [] {MonthDayPattern};
620 if (_YearMonthPatterns != null && _YearMonthPatterns.Length > 0)
621 return _YearMonthPatterns.Clone () as string [];
622 return new string [] {YearMonthPattern};
626 return new string [] {RFC1123Pattern};
628 return new string [] {SortableDateTimePattern};
630 return new string [] {UniversalSortableDateTimePattern};
632 throw new ArgumentException ("Format specifier was invalid.");
635 // LAMESPEC: this is not in ECMA specs
636 public string GetDayName(DayOfWeek dayofweek)
638 int index = (int) dayofweek;
639 if (index < 0 || index > 6) throw new ArgumentOutOfRangeException();
640 return _DayNames[index];
643 // LAMESPEC: this is not in ECMA specs
644 public string GetAbbreviatedDayName(DayOfWeek dayofweek)
646 int index = (int) dayofweek;
647 if (index < 0 || index > 6) throw new ArgumentOutOfRangeException();
648 return _AbbreviatedDayNames[index];
651 private void FillInvariantPatterns ()
653 _ShortDatePatterns = new string [] {"MM/dd/yyyy"};
654 _LongDatePatterns = new string [] {"dddd, dd MMMM yyyy"};
655 _LongTimePatterns = new string [] {"HH:mm:ss"};
656 _ShortTimePatterns = new string [] {
662 _MonthDayPatterns = new string [] {"MMMM dd"};
663 _YearMonthPatterns = new string [] {"yyyy MMMM"};
666 private string [] PopulateCombinedList (string [] dates, string [] times)
668 if (dates != null && times != null) {
669 string [] list = new string [dates.Length * times.Length];
671 foreach (string d in dates)
672 foreach (string t in times)
673 list [i++] = d + ' ' + t;