source: Scheduling/trunk/cs/bsdx0200GUISourceCode/FMDateTime.cs@ 843

Last change on this file since 843 was 843, checked in by Sam Habiel, 14 years ago

Some refactoring of code into DAL.cs for Data Access.
Addition of Fileman date code (not used yet).
Removal of .config and .xml file from bin/Release/
Removal of BMXNet20.dll to replace with BMXNet21.dll

File size: 27.7 KB
Line 
1/*
2 * Copyright (C) 2004-2009 Medsphere Systems Corporation
3 * All rights reserved.
4 *
5 * This source code contains the intellectual property
6 * of its copyright holder(s), and is made available
7 * under a license. If you do not know the terms of
8 * the license, please stop and do not read further.
9 *
10 * Please read LICENSES for detailed information about
11 * the license this source code file is available under.
12 * Questions should be directed to legal@medsphere.com
13 *
14 *
15 * Licensed under AGPL v3.
16 *
17 *
18
19 Mods by Sam Habiel to use in Scheduling GUI.
20 */
21
22
23using System;
24using System.Globalization;
25using System.Text.RegularExpressions;
26
27namespace IndianHealthService.ClinicalScheduling
28{
29 public delegate void FMDateTimeHandler (FMDateTime time);
30 public delegate string FMDateStringHandler (string s);
31
32 [Serializable]
33 [System.Xml.Serialization.SoapType (Namespace="http://ws.medsphere.com")]
34 public class FMDateTime : IComparable, ICloneable
35 {
36 /* public properties */
37 [System.Xml.Serialization.SoapAttribute (Namespace="http://ws.medsphere.com")]
38 public DateTime DateTime {
39 get {
40 switch (Precision) {
41 case FMDateTimePrecision.YearOnly:
42 return new DateTime (Year, 1, 1);
43 case FMDateTimePrecision.YearMonthOnly:
44 return new DateTime (Year, Month, 1);
45 case FMDateTimePrecision.DateOnly:
46 return new DateTime (Year, Month, Day);
47 default:
48 return new DateTime (Year, Month, Day, Hour, Minute, Second);
49 }
50 }
51 }
52
53 public int Year {
54 get { return year; }
55 set { year = value; }
56 }
57
58 public int Month {
59 get { return month; }
60 set { month = value; }
61 }
62
63 public int Day {
64 get { return day; }
65 set { day = value; }
66 }
67
68 public int Hour {
69 get { return hour; }
70 set {
71 if (value > 24) {
72 throw new ArgumentException ("Hour cannot be greater than 24");
73 }
74
75 hour = value % 24;
76 }
77 }
78
79 public int Minute {
80 get { return minute; }
81 set {
82 if (value > 59) {
83 throw new ArgumentException ("Minute cannot be greater than 59");
84 }
85
86 minute = value;
87 }
88 }
89
90 public int Second {
91 get { return second; }
92 set {
93 if (value > 59) {
94 throw new ArgumentException ("Second cannot be greater than 59");
95 }
96
97 second = value;
98 }
99 }
100
101 public static FMDateTime ServerNow {
102 get { return FMDateTime.Create (DateTime.Now - server_offset); }
103 }
104
105 public string RelativeFMDateString {
106 get { return Raw; }
107 }
108
109 public string ShortHandString {
110 get {
111 if (Raw != null && date_format.IsMatch (Raw.Replace (" ", ""))) {
112 return Raw;
113 }
114 return ToString ();
115 }
116 }
117
118 public FMDateTime AtZero {
119 get {
120 FMDateTime d = (FMDateTime)this.Clone ();
121 d.Precision = FMDateTimePrecision.DateAndTime;
122 d.Hour = 0;
123 d.Minute = 0;
124 d.Second = 0;
125 return d;
126 }
127 }
128
129 public FMDateTime AtMidnight {
130 get {
131 FMDateTime d = (FMDateTime)this.Clone ();
132 d.Precision = FMDateTimePrecision.DateAndTime;
133 d.Hour = 23;
134 d.Minute = 59;
135 d.Second = 59;
136 return d;
137 }
138 }
139
140 public FMDateTime DateOnly {
141 get {
142 FMDateTime d = (FMDateTime)this.Clone ();
143 if (Precision != FMDateTimePrecision.DateAndTime) {
144 return d;
145 }
146 d.Precision = FMDateTimePrecision.DateOnly;
147 d.Hour = d.Minute = d.Second = 0;
148 return d;
149 }
150 }
151
152 public string FMDateString {
153 get {
154 switch (Precision) {
155 case FMDateTimePrecision.YearOnly:
156 return String.Format ("{0:000}", year - 1700);
157 case FMDateTimePrecision.YearMonthOnly:
158 return String.Format ("{0:000}{1:00}", year - 1700, month);
159 case FMDateTimePrecision.DateOnly:
160 return String.Format ("{0:000}{1:00}{2:00}", year - 1700, month, day);
161 case FMDateTimePrecision.DateAndTime:
162 default:
163 if (second > 0) {
164 return String.Format ("{0:000}{1:00}{2:00}.{3:00}{4:00}{5:00}",
165 year - 1700, month, day, hour, minute, second);
166 } else {
167 return String.Format ("{0:000}{1:00}{2:00}.{3:00}{4:00}",
168 year - 1700, month, day, hour, minute);
169 }
170 }
171 }
172 }
173
174 /* public fields */
175 public FMDateTimePrecision Precision;
176
177 [NonSerialized]
178 public static FMDateStringHandler ValidationMethod;
179
180 public static FMDateTime MinValue; // 1/1/1700
181 public static FMDateTime MaxValue; // 12/31/2699 12:59 PM
182
183 /* public methods */
184 static FMDateTime ()
185 {
186 // This is the equivalent of the FMDateTime string '0000101'
187 // We do this manually to avoid parsing overhead here.
188 MinValue = new FMDateTime (); // 1/1/1700
189 MinValue.Hour = MinValue.Minute = MinValue.Second = 0;
190 MinValue.Day = MinValue.Month = 1;
191 MinValue.Year = 1700;
192 MinValue.Precision = FMDateTimePrecision.DateOnly;
193
194 // This is the equivalent of the FMDateTime string '9991231.235959'
195 // We do this manually to avoid parsing overhead here.
196 MaxValue = new FMDateTime (); // 12/31/2699 12:59 PM
197 MaxValue.Hour = 23;
198 MaxValue.Minute = 59;
199 MaxValue.Second = 59;
200 MaxValue.Day = 31;
201 MaxValue.Month = 12;
202 MaxValue.Year = 2699;
203 MaxValue.Precision = FMDateTimePrecision.DateAndTime;
204 }
205
206 public FMDateTime ()
207 {
208 }
209
210 public FMDateTime(DateTime d)
211 : this(d, FMDateTimePrecision.DateAndTime)
212 {
213 }
214
215 public FMDateTime(DateTime d, FMDateTimePrecision precision)
216 {
217 if (d > MaxValue.DateTime || d < MinValue.DateTime)
218 return;
219
220 this.Precision = precision;
221 this.Year = d.Year;
222 this.Month = d.Month;
223 this.Day = d.Day;
224 this.Hour = d.Hour;
225 this.Minute = d.Minute;
226 this.Second = d.Second;
227 }
228
229 public static FMDateTime Create (DateTime d, FMDateTimePrecision precision)
230 {
231 if (d > MaxValue.DateTime || d < MinValue.DateTime) {
232 return null;
233 }
234
235 FMDateTime f = new FMDateTime ();
236 f.Precision = precision;
237 f.Year = d.Year;
238 f.Month = d.Month;
239 f.Day = d.Day;
240 f.Hour = d.Hour;
241 f.Minute = d.Minute;
242 f.Second = d.Second;
243
244 return f;
245 }
246
247 public static FMDateTime Create (DateTime d)
248 {
249 return Create (d, FMDateTimePrecision.DateAndTime);
250 }
251
252 public static FMDateTime Parse (string str)
253 {
254 return Parse (str, FMDateTime.ValidationMethod);
255 }
256
257 public static FMDateTime Parse (string str,
258 FMDateStringHandler validation_method)
259 {
260 if (validation_method == null) {
261 throw new ArgumentNullException ("You must pass in a valid validation_method");
262 }
263
264 if (str == null) {
265 return null;
266 }
267
268 FMDateTime date = null;
269
270 str = str.Trim ();
271 if (str == "0" || str == String.Empty) {
272 return null;
273 }
274
275 if (str.IndexOf ("@") != -1) {
276 date = new FMDateTime ();
277
278 // string has a date and time part
279 string[] tokens = str.Split (new char[] {'@'}, 2);
280 if (ParseDatePart (tokens[0], ref date)
281 || ParseUsingDateTime (tokens[0], ref date)
282 || (validation_method != null
283 && ParseInternalFormat (validation_method (tokens[0]), ref date))) {
284 // Its been decided that if you have an
285 // invalid time part, that the entire
286 // string is invalid
287 if (!ParseTimePart (tokens[1], true, ref date)) {
288 return null;
289 }
290
291 date.Raw = str;
292 return date;
293 } else {
294 // Account for @0600
295 date = FMDateTime.ServerNow;
296 if (!ParseTimePart (tokens[1], true, ref date)) {
297 return null;
298 }
299 return date;
300 }
301 }
302
303 if (ParseDatePart (str, ref date)) {
304 date.Raw = str;
305 return date;
306 }
307
308 if (ParseTimePart (str, false, ref date)) {
309 FMDateTime now = ServerNow;
310 date.Year = now.Year;
311 date.Month = now.Month;
312 date.Day = now.Day;
313 return date;
314 }
315
316 if (ParseUsingDateTime (str, ref date)) {
317 return date;
318 }
319
320 if (ParseInternalFormat (str, ref date)) {
321 return date;
322 }
323
324 if (validation_method != null) {
325 if (ParseInternalFormat (validation_method (str), ref date)) {
326 return date;
327 }
328 return null;
329 }
330
331 if (date == null) {
332 Console.WriteLine ("WARNING: FMDateTime failed parsing '{0}'", str);
333 }
334
335 return date;
336 }
337
338 public static FMDateTime Parse (string str, FMDateTimePrecision precision)
339 {
340 FMDateTime date = FMDateTime.Parse (str);
341 if (date != null) {
342 date.Precision = precision;
343 }
344
345 return date;
346 }
347
348 public void PopulateFrom12HrTime (int hour, int minute, int second, bool is_pm)
349 {
350 if (hour < 12 && is_pm) {
351 hour += 12;
352 } else if (hour == 12 && !is_pm) {
353 hour = 0;
354 }
355
356 Hour = hour;
357 Minute = minute;
358 Second = second;
359 }
360
361 public bool IsFutureDate
362 {
363 get {
364 return (CompareTo (Precision, FMDateTime.ServerNow, FMDateTime.ServerNow.Precision) > 0);
365 }
366 }
367
368 public bool IsPastDate
369 {
370 get {
371 return (CompareTo (Precision, FMDateTime.ServerNow, FMDateTime.ServerNow.Precision) < 0);
372 }
373 }
374
375 public static void UpdateServerNow (FMDateTime server_now)
376 {
377 if (server_now != null) {
378 server_offset = (DateTime.Now - server_now.DateTime);
379 }
380 }
381
382 public override string ToString ()
383 {
384 switch (Precision) {
385 case FMDateTimePrecision.YearOnly:
386 return DateTime.ToString ("yyyy");
387 case FMDateTimePrecision.YearMonthOnly:
388 return DateTime.ToString ("Y");
389 case FMDateTimePrecision.DateOnly:
390 return DateTime.ToString ("d");
391 default:
392 return DateTime.ToString ("G");
393 }
394 }
395
396 public static string ToString (FMDateTime date)
397 {
398 if (date != null) {
399 return date.ToString ();
400 }
401 return String.Empty;
402 }
403
404 public string ToString (string format)
405 {
406 return DateTime.ToString (format);
407 }
408
409 public static string ToString (FMDateTime date, string format)
410 {
411 if (date != null) {
412 return date.ToString (format);
413 }
414 return String.Empty;
415 }
416
417 public string ToDateString ()
418 {
419 return DateTime.ToString ("d");
420 }
421
422 public static string ToDateString (FMDateTime date)
423 {
424 if (date != null) {
425 return date.ToDateString ();
426 }
427 return String.Empty;
428 }
429
430 public string ToTimeString ()
431 {
432 return DateTime.ToString ("t");
433 }
434
435 public static string ToTimeString (FMDateTime date)
436 {
437 if (date != null) {
438 return date.ToTimeString ();
439 }
440 return String.Empty;
441 }
442
443 public static string ToFMDateString (FMDateTime date)
444 {
445 if (date != null) {
446 return date.FMDateString;
447 }
448 return String.Empty;
449 }
450
451 /**
452 * Compares this FMDateTime instance with given FMDateTimePrecision this_p to dt
453 * using the given FMDateTimePrecision p.
454 */
455 public int CompareTo (FMDateTimePrecision this_p, FMDateTime dt, FMDateTimePrecision dt_p)
456 {
457 int r;
458 FMDateTimePrecision save_this_p = Precision;
459 FMDateTimePrecision save_dt_p = dt.Precision;
460 Precision = this_p;
461 dt.Precision = dt_p;
462 r = DateTime.CompareTo (dt.DateTime);
463 Precision = save_this_p;
464 dt.Precision = save_dt_p;
465 return r;
466 }
467
468 /**
469 * Implementation of IComparable interface.
470 */
471 public int CompareTo (object o)
472 {
473 if (o == null) {
474 return 1;
475 } else if (o is FMDateTime) {
476 FMDateTime f = (FMDateTime)o;
477 int r = DateTime.CompareTo (f.DateTime);
478 if (r == 0) {
479 // special cases of DateTime comparison:
480 // 1900 and January,1900 and 01/01/1900 are all
481 // represented as 01/01/1900
482 // TODAY@0 and TODAY are both represented as TODAY@0
483 // these are the cases where precision has the last word
484 if (Precision < f.Precision) {
485 r = -1;
486 } else if (Precision > f.Precision) {
487 r = 1;
488 }
489 }
490 return r;
491 } else if (o is DateTime) {
492 DateTime d = (DateTime)o;
493 return DateTime.CompareTo (d);
494 }
495
496 throw new ArgumentException ("Value is not a DateTime or FMDateTime.");
497 }
498
499 public static int Compare (FMDateTime a, FMDateTime b)
500 {
501 if (a == null && b == null) {
502 return 0;
503 } else if (a != null && b != null) {
504 return a.CompareTo (b);
505 /* We sort the non-null item before the null one for the mixed case */
506 } else if (a == null) {
507 return -1;
508 } else if (b == null) {
509 return 1;
510 }
511
512 // This code path really has no way of being hit.
513 return 0;
514 }
515
516 public override bool Equals (object o)
517 {
518 if (o == null) {
519 return false;
520 } else if (o is FMDateTime) {
521 FMDateTime f = (FMDateTime)o;
522
523 if (f.Precision != Precision) {
524 return false;
525 }
526
527 switch (Precision) {
528 case FMDateTimePrecision.YearOnly:
529 return Year == f.Year;
530 case FMDateTimePrecision.YearMonthOnly:
531 return Year == f.Year && Month == f.Month;
532 case FMDateTimePrecision.DateOnly:
533 return Year == f.Year && Month == f.Month && Day == f.Day;
534 case FMDateTimePrecision.DateAndTime:
535 default:
536 return Year == f.Year && Month == f.Month && Day == f.Day
537 && Hour == f.Hour && Minute == f.Minute && Second == f.Second;
538 }
539 }
540
541 throw new ArgumentException ("Value is not a FMDateTime.");
542 }
543
544 public override int GetHashCode ()
545 {
546 return (int)Precision + year + month + day + hour + minute + second;
547 }
548
549 /**
550 * This gets a hash code based upon the FMDateTime precision, so that
551 * an object can be stored based on DateOnly, for example, and if you
552 * try to look it up later using a different FMDateTime object that
553 * has the same date, but may have different time. Seconds are
554 * intentionally never factored into this hash code, even for DateAndTime
555 * cases. If you want to factor in seconds as well, just use GetHashCode().
556 *
557 * @return An integer hash code.
558 */
559 public int GetPrecisionAwareHashCode ()
560 {
561 int hash_code = (int)Precision;
562
563 switch (Precision)
564 {
565 case FMDateTimePrecision.YearOnly:
566 hash_code += year;
567 break;
568 case FMDateTimePrecision.YearMonthOnly:
569 hash_code += year;
570 hash_code += month;
571 break;
572 case FMDateTimePrecision.DateOnly:
573 hash_code += year;
574 hash_code += month;
575 hash_code += day;
576 break;
577 case FMDateTimePrecision.DateAndTime:
578 default:
579 hash_code += year;
580 hash_code += month;
581 hash_code += day;
582 hash_code += hour;
583 hash_code += minute;
584 break;
585 }
586
587 return hash_code;
588 }
589
590 public object Clone ()
591 {
592 FMDateTime d = new FMDateTime ();
593 d.Precision = Precision;
594 d.Year = year;
595 d.Month = month;
596 d.Day = day;
597 d.Hour = hour;
598 d.Minute = minute;
599 d.Second = second;
600 return d;
601 }
602
603 public static bool operator == (FMDateTime a, FMDateTime b)
604 {
605 object obj_a = (object)a;
606 object obj_b = (object)b;
607
608 if (obj_a == null && obj_b == null) {
609 return true;
610 } else if (obj_a != null && obj_b != null) {
611 return a.Equals (b);
612 } else {
613 return false;
614 }
615 }
616
617 public static bool operator != (FMDateTime a, FMDateTime b)
618 {
619 return !(a == b);
620 }
621
622 public static bool operator > (FMDateTime a, FMDateTime b)
623 {
624 if (a == null) {
625 throw new ArgumentException ("Left hand argument to comparison cannot be null.");
626 }
627
628 return (a.CompareTo (b) > 0);
629 }
630
631 public static bool operator >= (FMDateTime a, FMDateTime b)
632 {
633 if (a == null) {
634 throw new ArgumentException ("Left hand argument to comparison cannot be null.");
635 }
636
637 return (a.CompareTo (b) >= 0);
638 }
639
640 public static bool operator < (FMDateTime a, FMDateTime b)
641 {
642 if (a == null) {
643 throw new ArgumentException ("Left hand argument to comparison cannot be null.");
644 }
645
646 return (a.CompareTo (b) < 0);
647 }
648
649 public static bool operator <= (FMDateTime a, FMDateTime b)
650 {
651 if (a == null) {
652 throw new ArgumentException ("Left hand argument to comparison cannot be null.");
653 }
654
655 return (a.CompareTo (b) <= 0);
656 }
657
658 public static implicit operator FMDateTime (DateTime d)
659 {
660 return FMDateTime.Create (d);
661 }
662
663 /* protected properties */
664 protected string Raw;
665
666 /* private properties */
667 private static Calendar CurrentCalendar {
668 get { return CultureInfo.CurrentCulture.Calendar; }
669 }
670
671 /* private fields */
672 private int year, month, day, hour, minute, second;
673
674 // We do this here so we can lazy load the compiled regexes.
675 private static Regex internal_format {
676 get {
677 if (priv_internal_format == null) {
678 priv_internal_format = new Regex (@"^(\d{3})(\d{2})?(\d{2})?(\.(\d{1,2})?(\d{1,2})?(\d{1,2})?)?$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
679 }
680
681 return priv_internal_format;
682 }
683 }
684 private static Regex priv_internal_format;
685
686 private static Regex date_format {
687 get {
688 if (priv_date_format == null) {
689 priv_date_format = new Regex (@"^(t(oday)?|n(ow)?)(([+-])(\d+)(w)?)?$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
690 }
691
692 return priv_date_format;
693 }
694 }
695 private static Regex priv_date_format;
696
697 private static Regex time_format {
698 get {
699 if (priv_time_format == null) {
700 priv_time_format = new Regex (@"^(\d{1,2})(:(\d{2}))?(:(\d{2}))?(\s*)(AM|PM)?$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
701 }
702
703 return priv_time_format;
704 }
705 }
706 private static Regex priv_time_format;
707
708 private static TimeSpan server_offset = new TimeSpan ();
709
710 /* private methods */
711 private static bool ParseDatePart (string str, ref FMDateTime date)
712 {
713 FMDateTime orig_date = date;
714
715 string clean = str.Replace (" ", "");
716
717 // see if it matches (t|today|now) +/- some number
718 if (!date_format.IsMatch (clean)) {
719 return false;
720 }
721
722 Match m = date_format.Match (clean);
723 if (m != null) {
724 if (date == null) {
725 date = new FMDateTime ();
726 }
727
728 // be safe about dates like T-99999999
729 try {
730 int modifier = 0;
731 if (m.Groups[5].Value != String.Empty) {
732 int sign_bit = 1;
733 if (m.Groups[5].Value == "-") {
734 sign_bit = -1;
735 }
736
737 // Convert will bomb if the modifier
738 // won't fit into an int (it's invalid
739 // anyway)
740 modifier = sign_bit * Convert.ToInt32 (m.Groups[6].Value);
741 }
742
743 DateTime dt = ServerNow.DateTime;
744 if (m.Groups[7].Value.ToLower () == "w") {
745 dt = CurrentCalendar.AddWeeks (dt, modifier);
746 } else {
747 dt = CurrentCalendar.AddDays (dt, modifier);
748 }
749
750 date.Day = dt.Day;
751 date.Month = dt.Month;
752 date.Year = dt.Year;
753
754 if (m.Groups[1].Value.ToLower ().StartsWith ("n")) {
755 date.Precision = FMDateTimePrecision.DateAndTime;
756 date.Hour = dt.Hour;
757 date.Minute = dt.Minute;
758 date.Second = dt.Second;
759 } else {
760 date.Precision = FMDateTimePrecision.DateOnly;
761 date.Hour = date.Minute = date.Second = 0;
762 }
763 } catch {
764 date = orig_date;
765 return false;
766 }
767
768 return true;
769 }
770
771 date = orig_date;
772 return false;
773 }
774
775 private static bool ParseTimePart (string str, bool try_int_parse, ref FMDateTime date)
776 {
777 int time;
778 str = str.ToUpper ();
779 if (str == "NOON") {
780 if (date == null) {
781 date = new FMDateTime ();
782 }
783
784 date.Hour = 12;
785 date.Minute = date.Second = 0;
786
787 date.Precision = FMDateTimePrecision.DateAndTime;
788
789 return true;
790 } else if (str == "MID" || str == "MIDNIGHT") {
791 if (date == null) {
792 date = new FMDateTime ();
793 }
794
795 date.Hour = 23;
796 date.Minute = 59;
797 date.Second = 59;
798
799 date.Precision = FMDateTimePrecision.DateAndTime;
800
801 return true;
802 } else if (time_format.IsMatch (str)) {
803 Match m = time_format.Match (str);
804 if (m == null) {
805 return false;
806 }
807
808 int hour, minute, second;
809 int.TryParse(m.Groups[1].Value, out hour);
810 int.TryParse(m.Groups[3].Value, out minute);
811 int.TryParse(m.Groups[5].Value, out second);
812
813 if (m.Groups[7].Value == "PM") {
814 hour += 12;
815 }
816
817 if (hour == 24 && minute == 0 && second == 0) {
818 hour = 23;
819 minute = second = 59;
820 }
821
822 if (!ValidateTime (hour, minute, second)) {
823 return false;
824 }
825
826 if (date == null) {
827 date = new FMDateTime ();
828 }
829
830 date.Hour = hour;
831 date.Minute = minute;
832 date.Second = second;
833 date.Precision = FMDateTimePrecision.DateAndTime;
834
835 return true;
836 } else if (try_int_parse && int.TryParse(str, out time)) {
837
838 int hour, minute, second;
839 if (time <= 2359) {
840 hour = time / 100;
841 minute = time - (hour * 100);
842 second = 0;
843 } else if (time <= 235959) {
844 hour = time / 10000;
845 minute = (time - (hour * 10000)) / 100;
846 second = time - ((time / 100) * 100);
847 } else {
848 return false;
849 }
850
851 if (hour == 24 && minute == 0 && second == 0) {
852 hour = 23;
853 minute = second = 59;
854 }
855
856 if (!ValidateTime (hour, minute, second)) {
857 return false;
858 }
859
860 if (date == null) {
861 date = new FMDateTime ();
862 }
863
864 date.Hour = hour;
865 date.Minute = minute;
866 date.Second = second;
867 date.Precision = FMDateTimePrecision.DateAndTime;
868
869 return true;
870 }
871
872 return false;
873 }
874
875 private static bool ParseUsingDateTime (string str, ref FMDateTime date)
876 {
877 // we need to use DateTime.Parse to allow
878 // roundtripping of our ToString () methods
879
880 // LAMESPEC: There isn't any way to find out whether a
881 // DateTime contains a time part, or just a date part
882 // after calling Parse, so we have to specifically call
883 // ParseExact on a few known formats
884 try {
885 string[] formats = new string[] {
886 "yyyy"
887 };
888
889 DateTime d = DateTime.ParseExact (str, formats, null,
890 DateTimeStyles.AllowWhiteSpaces);
891 if (date == null) {
892 date = new FMDateTime ();
893 }
894
895 date.Year = d.Year;
896 date.Precision = FMDateTimePrecision.YearOnly;
897 return true;
898 } catch (FormatException) {
899 }
900
901 try {
902 string[] formats = new string[] {
903 "Y"
904 };
905
906 DateTime d = DateTime.ParseExact (str, formats, null,
907 DateTimeStyles.AllowWhiteSpaces);
908 if (date == null) {
909 date = new FMDateTime ();
910 }
911
912 date.Year = d.Year;
913 date.Month = d.Month;
914 date.Precision = FMDateTimePrecision.YearMonthOnly;
915 return true;
916 } catch (FormatException) {
917 }
918
919 try {
920 string[] formats = new string[] {
921 "d", "MM/dd/yy"
922 };
923
924 DateTime d = DateTime.ParseExact (str, formats, null,
925 DateTimeStyles.AllowWhiteSpaces);
926 if (date == null) {
927 date = new FMDateTime ();
928 }
929
930 date.Year = d.Year;
931 date.Month = d.Month;
932 date.Day = d.Day;
933 date.Precision = FMDateTimePrecision.DateOnly;
934 return true;
935 } catch (FormatException) {
936 }
937
938 try {
939 string[] formats = new string[] {
940 "g", "G", "MM/dd/yy hh:mm tt",
941 "MM/dd/yy h:mm tt"
942 };
943
944 DateTime d = DateTime.ParseExact (str, formats, null,
945 DateTimeStyles.AllowWhiteSpaces);
946 if (date == null) {
947 date = new FMDateTime ();
948 }
949
950 date.Year = d.Year;
951 date.Month = d.Month;
952 date.Day = d.Day;
953
954 date.Hour = d.Hour;
955 date.Minute = d.Minute;
956 date.Second = d.Second;
957
958 date.Precision = FMDateTimePrecision.DateAndTime;
959 return true;
960 } catch (FormatException) {
961 }
962
963 /* XXX: Disabiling this for now, since it sucks incredibly
964 // first try parsing date & time
965 try {
966 string[] date_time_formats = new string[] {
967 "dddd*, MMMM* dd, yyyy HH*:mm* tt*", "f",
968 "dddd*, MMMM* dd, yyyy HH*:mm*:ss* tt*", "F",
969 "MM/dd/yyyy HH*:mm* tt*", "g",
970 "MM/dd/yyyy HH*:mm*:ss* tt*", "G",
971 "dddd*, MMMM* dd, yyyy HH*:mm*:ss* tt*", "U"
972 };
973
974 DateTime d = DateTime.ParseExact (str, date_time_formats, null,
975 DateTimeStyles.AllowWhiteSpaces);
976 date.Year = d.Year;
977 date.Month = d.Month;
978 date.Day = d.Day;
979 date.Hour = d.Hour;
980 date.Minute = d.Minute;
981 date.Second = d.Second;
982 date.Precision = FMDateTimePrecision.DateAndTime;
983 return true;
984 } catch { }
985
986 // fall back on just parsing a date
987 try {
988 string[] date_formats = new string[] {
989 "d", "D", "m", "M", "y", "Y"
990 };
991
992 DateTime d = DateTime.ParseExact (str, date_formats, null,
993 DateTimeStyles.AllowWhiteSpaces);
994 date.Year = d.Year;
995 date.Month = d.Month;
996 date.Day = d.Day;
997 date.Precision = FMDateTimePrecision.DateOnly;
998 return true;
999 } catch { }
1000
1001 // if nothing else, try a couple of time formats
1002 try {
1003 string[] time_formats = new string[] {
1004 "HH*:mm* tt*", "t",
1005 "HH*:mm*:ss* tt*", "T"
1006 };
1007
1008 DateTime d = DateTime.ParseExact (str, time_formats, null,
1009 DateTimeStyles.AllowWhiteSpaces);
1010 date = FMDateTime.ServerNow;
1011 date.Hour = d.Hour;
1012 date.Minute = d.Minute;
1013 date.Second = d.Second;
1014 date.Precision = FMDateTimePrecision.DateAndTime;
1015 return true;
1016 } catch { }
1017 */
1018
1019 return false;
1020 }
1021
1022 private static bool ParseInternalFormat (string str, ref FMDateTime date)
1023 {
1024 FMDateTime orig_date = date;
1025
1026 if (internal_format.IsMatch (str)) {
1027 Match m = internal_format.Match (str);
1028 if (m != null && m.Groups.Count == 8) {
1029 int year, month, day, hour, minute, second;
1030
1031 int.TryParse(m.Groups[1].Value, out year);
1032 year += 1700;
1033
1034 int.TryParse(m.Groups[2].Value, out month);
1035 int.TryParse(m.Groups[3].Value, out day);
1036 int.TryParse(m.Groups[5].Value, out hour);
1037 int.TryParse(m.Groups[6].Value, out minute);
1038 int.TryParse(m.Groups[7].Value, out second);
1039
1040 // 1 digit hours apparently have just
1041 // had the trailing 0 dropped. Go figure.
1042 if (m.Groups[5].Value.Length == 1) {
1043 hour *= 10;
1044 }
1045
1046 // 1 digit minutes do too
1047 if (m.Groups[6].Value.Length == 1) {
1048 minute *= 10;
1049 }
1050
1051 // 1 digit seconds aren't to be left out
1052 if (m.Groups[7].Value.Length == 1) {
1053 second *= 10;
1054 }
1055
1056 if (!ValidateYear (year)) {
1057 return false;
1058 }
1059
1060 if (date == null) {
1061 date = new FMDateTime ();
1062 }
1063
1064 date.Year = year;
1065
1066 date.Precision = FMDateTimePrecision.YearOnly;
1067 if (m.Groups[5].Value != String.Empty
1068 && month > 0 && day > 0 && hour > 0) {
1069 if (!ValidateDate (year, month, day)
1070 || !ValidateTime (hour, minute, second)) {
1071 date = orig_date;
1072 return false;
1073 }
1074
1075 date.Month = month;
1076 date.Day = day;
1077 date.Hour = hour;
1078 date.Minute = minute;
1079 date.Second = second;
1080
1081 date.Precision = FMDateTimePrecision.DateAndTime;
1082 } else if (m.Groups[3].Value != String.Empty
1083 && month > 0 && day > 0) {
1084 if (!ValidateDate (year, month, day)) {
1085 date = orig_date;
1086 return false;
1087 }
1088
1089 date.Month = month;
1090 date.Day = day;
1091
1092 date.Precision = FMDateTimePrecision.DateOnly;
1093 } else if (m.Groups[2].Value != String.Empty
1094 && month > 0) {
1095 if (!ValidateYearMonth (year, month)) {
1096 date = orig_date;
1097 return false;
1098 }
1099
1100 date.Month = month;
1101
1102 date.Precision = FMDateTimePrecision.YearMonthOnly;
1103 }
1104
1105 return true;
1106 }
1107 }
1108
1109 return false;
1110 }
1111
1112 private static bool ValidateYear (int year)
1113 {
1114 // Sadly, we can't use MaxValue and MinValue due to
1115 // this function being used in the
1116 // parsing and initialization of those values
1117 if (year < 1700 || year > 2699) {
1118 return false;
1119 }
1120
1121 return true;
1122 }
1123
1124 private static bool ValidateYearMonth (int year, int month)
1125 {
1126 if (!ValidateYear (year)) {
1127 return false;
1128 }
1129
1130 int num_months = CurrentCalendar.GetMonthsInYear (year);
1131 if (month < 1 || month > num_months) {
1132 return false;
1133 }
1134
1135 return true;
1136 }
1137
1138 private static bool ValidateDate (int year, int month, int day)
1139 {
1140 if (!ValidateYearMonth (year, month)) {
1141 return false;
1142 }
1143
1144 int num_days = CurrentCalendar.GetDaysInMonth (year, month);
1145 if (day < 1 || day > num_days) {
1146 return false;
1147 }
1148
1149 return true;
1150 }
1151
1152 private static bool ValidateTime (int hour, int minute, int second)
1153 {
1154 if (hour < 0 || hour > 24) {
1155 return false;
1156 }
1157
1158 if (minute < 0 || minute > 59) {
1159 return false;
1160 }
1161
1162 if (second < 0 || second > 59) {
1163 return false;
1164 }
1165
1166 if (hour == 24 && (minute > 0 || second > 0)) {
1167 return false;
1168 }
1169
1170 return true;
1171 }
1172 }
1173
1174 public enum FMDateTimePrecision {
1175 YearOnly,
1176 YearMonthOnly,
1177 DateOnly,
1178 DateAndTime
1179 }
1180}
Note: See TracBrowser for help on using the repository browser.