This commit was manufactured by cvs2svn to create branch 'mono-1-0'.
[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         [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."};
54
55                 private static DateTimeFormatInfo theInvariantDateTimeFormatInfo;
56
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;
79
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;
87
88                 public DateTimeFormatInfo()
89                 {
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";
102
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."
108
109                         // Actually, no predefined culture has different values
110                         // than those default values.
111
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'";
115
116                         _FirstDayOfWeek = DayOfWeek.Sunday;
117                         _Calendar = new GregorianCalendar();
118                         _CalendarWeekRule = CalendarWeekRule.FirstDay;
119
120                         _AbbreviatedDayNames = INVARIANT_ABBREVIATED_DAY_NAMES;
121                         _DayNames = INVARIANT_DAY_NAMES;
122                         _AbbreviatedMonthNames = INVARIANT_ABBREVIATED_MONTH_NAMES;
123                         _MonthNames = INVARIANT_MONTH_NAMES;
124                 }
125                                 
126                 // LAMESPEC: this is not in ECMA specs
127                 public static DateTimeFormatInfo GetInstance(IFormatProvider provider)
128                 {
129                         if (provider != null) {
130                                 DateTimeFormatInfo dtfi;
131                                 dtfi = (DateTimeFormatInfo)provider.GetFormat(typeof(DateTimeFormatInfo));
132                                 if (dtfi != null)
133                                         return dtfi;
134                         }
135                         
136                         return CurrentInfo;
137                 }
138
139                 public bool IsReadOnly {
140                         get {
141                                 return readOnly;
142                         }
143                 }
144
145                 public static DateTimeFormatInfo ReadOnly(DateTimeFormatInfo dtfi)
146                 {
147                         DateTimeFormatInfo copy = (DateTimeFormatInfo)dtfi.Clone();
148                         copy.readOnly = true;
149                         return copy;
150                 }                       
151
152                 public object Clone () 
153                 {
154                         DateTimeFormatInfo clone = (DateTimeFormatInfo) MemberwiseClone();
155                         // clone is not read only
156                         clone.readOnly = false;
157                         return clone;
158                 }
159
160                 public object GetFormat(Type formatType)
161                 {
162                         return (formatType == GetType()) ? this : null;
163                 }
164
165                 [MonoTODO]
166                 public string GetAbbreviatedEraName(int era)
167                 {
168                         if (era < _Calendar.Eras.Length || era >= _Calendar.Eras.Length)
169                                 throw new ArgumentOutOfRangeException();
170                         notImplemented();
171                         //FIXME: implement me
172                         return null;
173                 }
174
175                 public string GetAbbreviatedMonthName(int month)
176                 {
177                         if (month < 1 || month > 13) throw new ArgumentOutOfRangeException();
178                         return _AbbreviatedMonthNames[month-1];
179                 }
180
181                 [MonoTODO]
182                 public int GetEra(string eraName)
183                 {
184                         if (eraName == null) throw new ArgumentNullException();
185                         eraName = eraName.ToUpper();
186                         notImplemented();
187                         //FIXME: implement me
188                         return -1;
189                 }
190
191                 [MonoTODO]
192                 public string GetEraName(int era)
193                 {
194 //                      if (era < _Calendar.Eras.Length || era >= _Calendar.Eras.Length)
195 //                              throw new ArgumentOutOfRangeException();
196                         try {
197                                 return INVARIANT_ERA_NAMES[era - 1];
198                         }
199                         catch {
200                                 //FIXME: implement me
201                                 notImplemented();
202                                 return null;
203                         }
204                 }
205
206                 public string GetMonthName(int month)
207                 {
208                         if (month < 1 || month > 13) throw new ArgumentOutOfRangeException();
209                         return _MonthNames[month-1];
210                 }
211
212                 public string[] AbbreviatedDayNames
213                 {
214                         get
215                         {
216                                 return (string[]) _AbbreviatedDayNames.Clone();
217                         }
218                         set
219                         {
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();
224                         }
225                 }
226
227                 public string[] AbbreviatedMonthNames
228                 {
229                         get
230                         {
231                                 return (string[]) _AbbreviatedMonthNames.Clone();
232                         }
233                         set
234                         {
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();
239                         }
240                 }
241
242                 public string[] DayNames
243                 {
244                         get
245                         {
246                                 return (string[]) _DayNames.Clone();
247                         }
248                         set
249                         {
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();
254                         }
255                 }
256
257                 public string[] MonthNames
258                 {
259                         get
260                         {
261                                 return (string[]) _MonthNames.Clone();
262                         }
263                         set
264                         {
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();
269                         }
270                 }
271
272                 public string AMDesignator
273                 {
274                         get
275                         {
276                                 return _AMDesignator;
277                         }
278                         set
279                         {
280                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
281                                 if (value == null) throw new ArgumentNullException();
282                                 _AMDesignator = value;
283                         }
284                 }
285
286                 public string PMDesignator
287                 {
288                         get
289                         {
290                                 return _PMDesignator;
291                         }
292                         set
293                         {
294                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
295                                 if (value == null) throw new ArgumentNullException();
296                                 _PMDesignator = value;
297                         }
298                 }
299
300                 public string DateSeparator
301                 {
302                         get
303                         {
304                                 return _DateSeparator;
305                         }
306                         set
307                         {
308                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
309                                 if (value == null) throw new ArgumentNullException();
310                                 _DateSeparator = value;
311                         }
312                 }
313
314                 public string TimeSeparator
315                 {
316                         get
317                         {
318                                 return _TimeSeparator;
319                         }
320                         set
321                         {
322                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
323                                 if (value == null) throw new ArgumentNullException();
324                                 _TimeSeparator = value;
325                         }
326                 }
327
328                 public string LongDatePattern
329                 {
330                         get
331                         {
332                                 return _LongDatePattern;
333                         }
334                         set
335                         {
336                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
337                                 if (value == null) throw new ArgumentNullException();
338                                 _LongDatePattern = value;
339                         }
340                 }
341
342                 public string ShortDatePattern
343                 {
344                         get
345                         {
346                                 return _ShortDatePattern;
347                         }
348                         set
349                         {
350                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
351                                 if (value == null) throw new ArgumentNullException();
352                                 _ShortDatePattern = value;
353                         }
354                 }
355
356                 public string ShortTimePattern
357                 {
358                         get
359                         {
360                                 return _ShortTimePattern;
361                         }
362                         set
363                         {
364                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
365                                 if (value == null) throw new ArgumentNullException();
366                                 _ShortTimePattern = value;
367                         }
368                 }
369
370                 public string LongTimePattern
371                 {
372                         get
373                         {
374                                 return _LongTimePattern;
375                         }
376                         set
377                         {
378                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
379                                 if (value == null) throw new ArgumentNullException();
380                                 _LongTimePattern = value;
381                         }
382                 }
383
384                 public string MonthDayPattern
385                 {
386                         get
387                         {
388                                 return _MonthDayPattern;
389                         }
390                         set
391                         {
392                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
393                                 if (value == null) throw new ArgumentNullException();
394                                 _MonthDayPattern = value;
395                         }
396                 }
397
398                 public string YearMonthPattern
399                 {
400                         get
401                         {
402                                 return _YearMonthPattern;
403                         }
404                         set
405                         {
406                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
407                                 if (value == null) throw new ArgumentNullException();
408                                 _YearMonthPattern = value;
409                         }
410                 }
411
412                 public string FullDateTimePattern
413                 {
414                         get
415                         {
416                                 if(_FullDateTimePattern!=null) {
417                                         return _FullDateTimePattern;
418                                 } else {
419                                         return(_LongDatePattern + " " + _LongTimePattern);
420                                 }
421                         }
422                         set
423                         {
424                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
425                                 if (value == null) throw new ArgumentNullException();
426                                 _FullDateTimePattern = value;
427                         }
428                 }
429
430                 public static DateTimeFormatInfo CurrentInfo
431                 {
432                         get
433                         {
434                                 return Thread.CurrentThread.CurrentCulture.DateTimeFormat;
435                         }
436                 }
437
438                 public static DateTimeFormatInfo InvariantInfo
439                 {
440                         get
441                         {
442                                 if (theInvariantDateTimeFormatInfo == null) {
443                                         theInvariantDateTimeFormatInfo = 
444                                                 DateTimeFormatInfo.ReadOnly(new DateTimeFormatInfo());
445                                         theInvariantDateTimeFormatInfo.FillInvariantPatterns ();
446                                 }
447                                 return theInvariantDateTimeFormatInfo;
448                         }
449                 }
450
451                 // LAMESPEC: this is not in ECMA specs
452                 public DayOfWeek FirstDayOfWeek
453                 {
454                         get
455                         {
456                                 return _FirstDayOfWeek;
457                         }
458                         set
459                         {
460                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
461                                 if ((int) value < 0 || (int) value > 6) throw new ArgumentOutOfRangeException();
462                                 _FirstDayOfWeek = value;
463                         }
464                 }
465
466                 // LAMESPEC: this is not in ECMA specs
467                 public Calendar Calendar
468                 {
469                         get
470                         {
471                                 return _Calendar;
472                         }
473                         set
474                         {
475                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
476                                 if (value == null) throw new ArgumentNullException();
477                                 _Calendar = value;
478                         }
479                 }
480
481                 public CalendarWeekRule CalendarWeekRule
482                 {
483                         get
484                         {
485                                 return _CalendarWeekRule;
486                         }
487                         set
488                         {
489                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
490                                 _CalendarWeekRule = value;
491                         }
492                 }
493
494                 // LAMESPEC: this is not in ECMA specs
495                 public string RFC1123Pattern
496                 {
497                         get
498                         {
499                                 return _RFC1123Pattern;
500                         }
501                 }
502
503                 // LAMESPEC: this is not in ECMA specs
504                 public string SortableDateTimePattern
505                 {
506                         get
507                         {
508                                 return _SortableDateTimePattern;
509                         }
510                 }
511
512                 // LAMESPEC: this is not in ECMA specs
513                 public string UniversalSortableDateTimePattern
514                 {
515                         get
516                         {
517                                 return _UniversalSortableDateTimePattern;
518                         }
519                 }
520                 
521                 // LAMESPEC: this is not in ECMA specs
522                 [MonoTODO ("Not complete depending on GetAllDateTimePatterns(char)")]
523                 public string[] GetAllDateTimePatterns()
524                 {
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);
565
566                         return al.ToArray (typeof (string)) as string [];
567                 }
568
569                 // LAMESPEC: this is not in ECMA specs
570                 [MonoTODO ("We need more culture data in locale-builder")]
571                 public string[] GetAllDateTimePatterns (char format)
572                 {
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};
639                         }
640                         throw new ArgumentException ("Format specifier was invalid.");
641                 }
642
643                 // LAMESPEC: this is not in ECMA specs
644                 public string GetDayName(DayOfWeek dayofweek)
645                 {
646                         int index = (int) dayofweek;
647                         if (index < 0 || index > 6) throw new ArgumentOutOfRangeException();
648                         return _DayNames[index];
649                 }
650
651                 // LAMESPEC: this is not in ECMA specs
652                 public string GetAbbreviatedDayName(DayOfWeek dayofweek)
653                 {
654                         int index = (int) dayofweek;
655                         if (index < 0 || index > 6) throw new ArgumentOutOfRangeException();
656                         return _AbbreviatedDayNames[index];
657                 }
658
659                 private void FillInvariantPatterns ()
660                 {
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"
669                         };
670                         _MonthDayPatterns = new string [] {"MMMM dd"};
671                         _YearMonthPatterns = new string [] {"yyyy MMMM"};
672                 }
673
674                 private string [] PopulateCombinedList (string [] dates, string [] times)
675                 {
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;
683                         }
684                         return null;
685                 }
686
687                 private static void notImplemented()
688                 {
689                         throw new Exception("Not implemented");
690                 }
691         }
692 }