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;
166 public string GetAbbreviatedEraName(int era
)
168 if (era
< _Calendar
.Eras
.Length
|| era
>= _Calendar
.Eras
.Length
)
169 throw new ArgumentOutOfRangeException();
171 //FIXME: implement me
175 public string GetAbbreviatedMonthName(int month
)
177 if (month
< 1 || month
> 13) throw new ArgumentOutOfRangeException();
178 return _AbbreviatedMonthNames
[month
-1];
182 public int GetEra(string eraName
)
184 if (eraName
== null) throw new ArgumentNullException();
185 eraName
= eraName
.ToUpper();
187 //FIXME: implement me
192 public string GetEraName(int era
)
194 // if (era < _Calendar.Eras.Length || era >= _Calendar.Eras.Length)
195 // throw new ArgumentOutOfRangeException();
197 return INVARIANT_ERA_NAMES
[era
- 1];
200 //FIXME: implement me
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
;
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
475 if (IsReadOnly
) throw new InvalidOperationException(MSG_READONLY
);
476 if (value == null) throw new ArgumentNullException();
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'))
528 foreach (string s
in GetAllDateTimePatterns ('D'))
530 foreach (string s
in GetAllDateTimePatterns ('g'))
532 foreach (string s
in GetAllDateTimePatterns ('G'))
534 foreach (string s
in GetAllDateTimePatterns ('f'))
536 foreach (string s
in GetAllDateTimePatterns ('F'))
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
543 foreach (string s
in GetAllDateTimePatterns ('m'))
545 foreach (string s
in GetAllDateTimePatterns ('M'))
547 foreach (string s
in GetAllDateTimePatterns ('r'))
549 foreach (string s
in GetAllDateTimePatterns ('R'))
551 foreach (string s
in GetAllDateTimePatterns ('s'))
553 foreach (string s
in GetAllDateTimePatterns ('t'))
555 foreach (string s
in GetAllDateTimePatterns ('T'))
557 foreach (string s
in GetAllDateTimePatterns ('u'))
559 foreach (string s
in GetAllDateTimePatterns ('U'))
561 foreach (string s
in GetAllDateTimePatterns ('y'))
563 foreach (string s
in GetAllDateTimePatterns ('Y'))
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
)
577 if (_LongDatePatterns
!= null && _LongDatePatterns
.Length
> 0)
578 return _LongDatePatterns
.Clone () as string [];
579 return new string [] {LongDatePattern}
;
581 if (_ShortDatePatterns
!= null && _ShortDatePatterns
.Length
> 0)
582 return _ShortDatePatterns
.Clone () as string [];
583 return new string [] {ShortDatePattern}
;
586 if (_LongTimePatterns
!= null && _LongTimePatterns
.Length
> 0)
587 return _LongTimePatterns
.Clone () as string [];
588 return new string [] {LongTimePattern}
;
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.
597 list
= PopulateCombinedList (_ShortDatePatterns
, _LongTimePatterns
);
598 if (list
!= null && list
.Length
> 0)
600 return new string [] {ShortDatePattern + ' ' + LongTimePattern}
;
602 list
= PopulateCombinedList (_ShortDatePatterns
, _ShortTimePatterns
);
603 if (list
!= null && list
.Length
> 0)
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.)
610 list
= PopulateCombinedList (_LongDatePatterns
, _LongTimePatterns
);
611 if (list
!= null && list
.Length
> 0)
613 return new string [] {LongDatePattern + ' ' + LongTimePattern}
;
615 list
= PopulateCombinedList (_LongDatePatterns
, _ShortTimePatterns
);
616 if (list
!= null && list
.Length
> 0)
618 return new string [] {LongDatePattern + ' ' + ShortTimePattern}
;
622 if (_MonthDayPatterns
!= null && _MonthDayPatterns
.Length
> 0)
623 return _MonthDayPatterns
.Clone () as string [];
624 return new string [] {MonthDayPattern}
;
628 if (_YearMonthPatterns
!= null && _YearMonthPatterns
.Length
> 0)
629 return _YearMonthPatterns
.Clone () as string [];
630 return new string [] {YearMonthPattern}
;
634 return new string [] {RFC1123Pattern}
;
636 return new string [] {SortableDateTimePattern}
;
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 [] {
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
];
679 foreach (string d
in dates
)
680 foreach (string t
in times
)
681 list
[i
++] = d
+ ' ' + t
;
687 private static void notImplemented()
689 throw new Exception("Not implemented");