2005-08-30 Sebastien Pouliot <sebastien@ximian.com>
[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                 public string GetAbbreviatedEraName (int era)
166                 {
167                         if (era < 0 || era >= _Calendar.AbbreviatedEraNames.Length)
168                                 throw new ArgumentOutOfRangeException ("era", era.ToString ());
169                         return _Calendar.AbbreviatedEraNames [era];
170                 }
171
172                 public string GetAbbreviatedMonthName(int month)
173                 {
174                         if (month < 1 || month > 13) throw new ArgumentOutOfRangeException();
175                         return _AbbreviatedMonthNames[month-1];
176                 }
177
178                 public int GetEra (string eraName)
179                 {
180                         if (eraName == null)
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)
187                                         return i;
188                         return -1;
189                 }
190
191                 public string GetEraName (int era)
192                 {
193                         if (era < 0 || era > _Calendar.EraNames.Length)
194                                 throw new ArgumentOutOfRangeException ("era", era.ToString ());
195                         return _Calendar.EraNames [era - 1];
196                 }
197
198                 public string GetMonthName(int month)
199                 {
200                         if (month < 1 || month > 13) throw new ArgumentOutOfRangeException();
201                         return _MonthNames[month-1];
202                 }
203
204                 public string[] AbbreviatedDayNames
205                 {
206                         get
207                         {
208                                 return (string[]) _AbbreviatedDayNames.Clone();
209                         }
210                         set
211                         {
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();
216                         }
217                 }
218
219                 public string[] AbbreviatedMonthNames
220                 {
221                         get
222                         {
223                                 return (string[]) _AbbreviatedMonthNames.Clone();
224                         }
225                         set
226                         {
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();
231                         }
232                 }
233
234                 public string[] DayNames
235                 {
236                         get
237                         {
238                                 return (string[]) _DayNames.Clone();
239                         }
240                         set
241                         {
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();
246                         }
247                 }
248
249                 public string[] MonthNames
250                 {
251                         get
252                         {
253                                 return (string[]) _MonthNames.Clone();
254                         }
255                         set
256                         {
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();
261                         }
262                 }
263
264                 public string AMDesignator
265                 {
266                         get
267                         {
268                                 return _AMDesignator;
269                         }
270                         set
271                         {
272                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
273                                 if (value == null) throw new ArgumentNullException();
274                                 _AMDesignator = value;
275                         }
276                 }
277
278                 public string PMDesignator
279                 {
280                         get
281                         {
282                                 return _PMDesignator;
283                         }
284                         set
285                         {
286                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
287                                 if (value == null) throw new ArgumentNullException();
288                                 _PMDesignator = value;
289                         }
290                 }
291
292                 public string DateSeparator
293                 {
294                         get
295                         {
296                                 return _DateSeparator;
297                         }
298                         set
299                         {
300                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
301                                 if (value == null) throw new ArgumentNullException();
302                                 _DateSeparator = value;
303                         }
304                 }
305
306                 public string TimeSeparator
307                 {
308                         get
309                         {
310                                 return _TimeSeparator;
311                         }
312                         set
313                         {
314                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
315                                 if (value == null) throw new ArgumentNullException();
316                                 _TimeSeparator = value;
317                         }
318                 }
319
320                 public string LongDatePattern
321                 {
322                         get
323                         {
324                                 return _LongDatePattern;
325                         }
326                         set
327                         {
328                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
329                                 if (value == null) throw new ArgumentNullException();
330                                 _LongDatePattern = value;
331                         }
332                 }
333
334                 public string ShortDatePattern
335                 {
336                         get
337                         {
338                                 return _ShortDatePattern;
339                         }
340                         set
341                         {
342                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
343                                 if (value == null) throw new ArgumentNullException();
344                                 _ShortDatePattern = value;
345                         }
346                 }
347
348                 public string ShortTimePattern
349                 {
350                         get
351                         {
352                                 return _ShortTimePattern;
353                         }
354                         set
355                         {
356                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
357                                 if (value == null) throw new ArgumentNullException();
358                                 _ShortTimePattern = value;
359                         }
360                 }
361
362                 public string LongTimePattern
363                 {
364                         get
365                         {
366                                 return _LongTimePattern;
367                         }
368                         set
369                         {
370                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
371                                 if (value == null) throw new ArgumentNullException();
372                                 _LongTimePattern = value;
373                         }
374                 }
375
376                 public string MonthDayPattern
377                 {
378                         get
379                         {
380                                 return _MonthDayPattern;
381                         }
382                         set
383                         {
384                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
385                                 if (value == null) throw new ArgumentNullException();
386                                 _MonthDayPattern = value;
387                         }
388                 }
389
390                 public string YearMonthPattern
391                 {
392                         get
393                         {
394                                 return _YearMonthPattern;
395                         }
396                         set
397                         {
398                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
399                                 if (value == null) throw new ArgumentNullException();
400                                 _YearMonthPattern = value;
401                         }
402                 }
403
404                 public string FullDateTimePattern
405                 {
406                         get
407                         {
408                                 if(_FullDateTimePattern!=null) {
409                                         return _FullDateTimePattern;
410                                 } else {
411                                         return(_LongDatePattern + " " + _LongTimePattern);
412                                 }
413                         }
414                         set
415                         {
416                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
417                                 if (value == null) throw new ArgumentNullException();
418                                 _FullDateTimePattern = value;
419                         }
420                 }
421
422                 public static DateTimeFormatInfo CurrentInfo
423                 {
424                         get
425                         {
426                                 return Thread.CurrentThread.CurrentCulture.DateTimeFormat;
427                         }
428                 }
429
430                 public static DateTimeFormatInfo InvariantInfo
431                 {
432                         get
433                         {
434                                 if (theInvariantDateTimeFormatInfo == null) {
435                                         theInvariantDateTimeFormatInfo = 
436                                                 DateTimeFormatInfo.ReadOnly(new DateTimeFormatInfo());
437                                         theInvariantDateTimeFormatInfo.FillInvariantPatterns ();
438                                 }
439                                 return theInvariantDateTimeFormatInfo;
440                         }
441                 }
442
443                 // LAMESPEC: this is not in ECMA specs
444                 public DayOfWeek FirstDayOfWeek
445                 {
446                         get
447                         {
448                                 return _FirstDayOfWeek;
449                         }
450                         set
451                         {
452                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
453                                 if ((int) value < 0 || (int) value > 6) throw new ArgumentOutOfRangeException();
454                                 _FirstDayOfWeek = value;
455                         }
456                 }
457
458                 // LAMESPEC: this is not in ECMA specs
459                 public Calendar Calendar
460                 {
461                         get
462                         {
463                                 return _Calendar;
464                         }
465                         set
466                         {
467                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
468                                 if (value == null) throw new ArgumentNullException();
469                                 _Calendar = value;
470                         }
471                 }
472
473                 public CalendarWeekRule CalendarWeekRule
474                 {
475                         get
476                         {
477                                 return _CalendarWeekRule;
478                         }
479                         set
480                         {
481                                 if (IsReadOnly) throw new InvalidOperationException(MSG_READONLY);
482                                 _CalendarWeekRule = value;
483                         }
484                 }
485
486                 // LAMESPEC: this is not in ECMA specs
487                 public string RFC1123Pattern
488                 {
489                         get
490                         {
491                                 return _RFC1123Pattern;
492                         }
493                 }
494
495                 // LAMESPEC: this is not in ECMA specs
496                 public string SortableDateTimePattern
497                 {
498                         get
499                         {
500                                 return _SortableDateTimePattern;
501                         }
502                 }
503
504                 // LAMESPEC: this is not in ECMA specs
505                 public string UniversalSortableDateTimePattern
506                 {
507                         get
508                         {
509                                 return _UniversalSortableDateTimePattern;
510                         }
511                 }
512                 
513                 // LAMESPEC: this is not in ECMA specs
514                 [MonoTODO ("Not complete depending on GetAllDateTimePatterns(char)")]
515                 public string[] GetAllDateTimePatterns()
516                 {
517                         ArrayList al = new ArrayList ();
518                         foreach (string s in GetAllDateTimePatterns ('d'))
519                                 al.Add (s);
520                         foreach (string s in GetAllDateTimePatterns ('D'))
521                                 al.Add (s);
522                         foreach (string s in GetAllDateTimePatterns ('g'))
523                                 al.Add (s);
524                         foreach (string s in GetAllDateTimePatterns ('G'))
525                                 al.Add (s);
526                         foreach (string s in GetAllDateTimePatterns ('f'))
527                                 al.Add (s);
528                         foreach (string s in GetAllDateTimePatterns ('F'))
529                                 al.Add (s);
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
534                         // different.)
535                         foreach (string s in GetAllDateTimePatterns ('m'))
536                                 al.Add (s);
537                         foreach (string s in GetAllDateTimePatterns ('M'))
538                                 al.Add (s);
539                         foreach (string s in GetAllDateTimePatterns ('r'))
540                                 al.Add (s);
541                         foreach (string s in GetAllDateTimePatterns ('R'))
542                                 al.Add (s);
543                         foreach (string s in GetAllDateTimePatterns ('s'))
544                                 al.Add (s);
545                         foreach (string s in GetAllDateTimePatterns ('t'))
546                                 al.Add (s);
547                         foreach (string s in GetAllDateTimePatterns ('T'))
548                                 al.Add (s);
549                         foreach (string s in GetAllDateTimePatterns ('u'))
550                                 al.Add (s);
551                         foreach (string s in GetAllDateTimePatterns ('U'))
552                                 al.Add (s);
553                         foreach (string s in GetAllDateTimePatterns ('y'))
554                                 al.Add (s);
555                         foreach (string s in GetAllDateTimePatterns ('Y'))
556                                 al.Add (s);
557
558                         return al.ToArray (typeof (string)) as string [];
559                 }
560
561                 // LAMESPEC: this is not in ECMA specs
562                 [MonoTODO ("We need more culture data in locale-builder")]
563                 public string[] GetAllDateTimePatterns (char format)
564                 {
565                         string [] list;
566                         switch (format) {
567                         // Date
568                         case 'D':
569                                 if (_LongDatePatterns != null && _LongDatePatterns.Length > 0)
570                                         return _LongDatePatterns.Clone () as string [];
571                                 return new string [] {LongDatePattern};
572                         case 'd':
573                                 if (_ShortDatePatterns != null && _ShortDatePatterns.Length > 0)
574                                         return _ShortDatePatterns.Clone () as string [];
575                                 return new string [] {ShortDatePattern};
576                         // Time
577                         case 'T':
578                                 if (_LongTimePatterns != null && _LongTimePatterns.Length > 0)
579                                         return _LongTimePatterns.Clone () as string [];
580                                 return new string [] {LongTimePattern};
581                         case 't':
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.
588                         case 'G':
589                                 list = PopulateCombinedList (_ShortDatePatterns, _LongTimePatterns);
590                                 if (list != null && list.Length > 0)
591                                         return list;
592                                 return new string [] {ShortDatePattern + ' ' + LongTimePattern};
593                         case 'g':
594                                 list = PopulateCombinedList (_ShortDatePatterns, _ShortTimePatterns);
595                                 if (list != null && list.Length > 0)
596                                         return list;
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.)
600                         case 'U':
601                         case 'F':
602                                 list = PopulateCombinedList (_LongDatePatterns, _LongTimePatterns);
603                                 if (list != null && list.Length > 0)
604                                         return list;
605                                 return new string [] {LongDatePattern + ' ' + LongTimePattern};
606                         case 'f':
607                                 list = PopulateCombinedList (_LongDatePatterns, _ShortTimePatterns);
608                                 if (list != null && list.Length > 0)
609                                         return list;
610                                 return new string [] {LongDatePattern + ' ' + ShortTimePattern};
611                         // MonthDay
612                         case 'm':
613                         case 'M':
614                                 if (_MonthDayPatterns != null && _MonthDayPatterns.Length > 0)
615                                         return _MonthDayPatterns.Clone () as string [];
616                                 return new string [] {MonthDayPattern};
617                         // YearMonth
618                         case 'Y':
619                         case 'y':
620                                 if (_YearMonthPatterns != null && _YearMonthPatterns.Length > 0)
621                                         return _YearMonthPatterns.Clone () as string [];
622                                 return new string [] {YearMonthPattern};
623                         // RFC1123
624                         case 'r':
625                         case 'R':
626                                 return new string [] {RFC1123Pattern};
627                         case 's':
628                                 return new string [] {SortableDateTimePattern};
629                         case 'u':
630                                 return new string [] {UniversalSortableDateTimePattern};
631                         }
632                         throw new ArgumentException ("Format specifier was invalid.");
633                 }
634
635                 // LAMESPEC: this is not in ECMA specs
636                 public string GetDayName(DayOfWeek dayofweek)
637                 {
638                         int index = (int) dayofweek;
639                         if (index < 0 || index > 6) throw new ArgumentOutOfRangeException();
640                         return _DayNames[index];
641                 }
642
643                 // LAMESPEC: this is not in ECMA specs
644                 public string GetAbbreviatedDayName(DayOfWeek dayofweek)
645                 {
646                         int index = (int) dayofweek;
647                         if (index < 0 || index > 6) throw new ArgumentOutOfRangeException();
648                         return _AbbreviatedDayNames[index];
649                 }
650
651                 private void FillInvariantPatterns ()
652                 {
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 [] {
657                                 "HH:mm",
658                                 "hh:mm tt",
659                                 "H:mm",
660                                 "h:mm tt"
661                         };
662                         _MonthDayPatterns = new string [] {"MMMM dd"};
663                         _YearMonthPatterns = new string [] {"yyyy MMMM"};
664                 }
665
666                 private string [] PopulateCombinedList (string [] dates, string [] times)
667                 {
668                         if (dates != null && times != null) {
669                                 string [] list = new string [dates.Length * times.Length];
670                                 int i = 0;
671                                 foreach (string d in dates)
672                                         foreach (string t in times)
673                                                 list [i++] = d + ' ' + t;
674                                 return list;
675                         }
676                         return null;
677                 }
678         }
679 }