Removed /usr/local from CDPATH
[clearscm.git] / lib / DateUtils.pm
1 =pod
2
3 =head1 NAME $RCSfile: DateUtils.pm,v $
4
5 Simple date/time utilities
6
7 =head1 VERSION
8
9 =over
10
11 =item Author
12
13 Andrew DeFaria <Andrew@ClearSCM.com>
14
15 =item Revision
16
17 $Revision: 1.32 $
18
19 =item Created
20
21 Thu Jan  5 11:06:49 PST 2006
22
23 =item Modified
24
25 $Date: 2013/02/21 05:01:17 $
26
27 =back
28
29 =head1 SYNOPSIS
30
31 Simple date and time utilities for often used date/time functionality.
32
33   my $ymd = YMD;
34   my $ymdhm = YMDHM;
35   my $timestamp = timestamp;
36
37 =head1 DESCRIPTION
38
39 Often you just want to simply and quickly get date or date and time in
40 a YMD or YMDHM format. Note the YMDHM format defined here is YMD\@H:M
41 and is not well suited for a filename. The timestamp routine returns
42 YMD_HM.
43
44 =head1 ROUTINES
45
46 The following routines are exported:
47
48 =cut
49
50 package DateUtils;
51
52 use strict;
53 use warnings;
54
55 use base 'Exporter';
56
57 use Carp;
58 use Time::Local;
59
60 use Display;
61 use Utils;
62
63 our @EXPORT = qw(
64   Add
65   Age
66   Compare
67   DateToEpoch
68   EpochToDate
69   FormatDate
70   FormatTime
71   MDY
72   SQLDatetime2UnixDatetime
73   SubtractDays
74   Today2SQLDatetime
75   UnixDatetime2SQLDatetime
76   UTCTime
77   YMD
78   YMDHM
79   YMDHMS
80   timestamp
81   ymdhms
82   MDYHMS2SQLDatetime
83 );
84
85 my @months = (
86   31, # January
87   28, # February
88   31, # March
89   30, # April
90   31, # May
91   30, # June
92   31, # July
93   31, # August
94   30, # September
95   31, # October
96   30, # November
97   31  # Descember
98 );
99
100 my $SECS_IN_MIN  = 60;
101 my $SECS_IN_HOUR = $SECS_IN_MIN * 60; 
102 my $SECS_IN_DAY  = $SECS_IN_HOUR * 24;
103
104 # Forwards
105 sub Today2SQLDatetime();
106 sub DateToEpoch($);
107 sub EpochToDate($);
108
109 sub ymdhms(;$) {
110   my ($time) = @_;
111
112   $time ||= time;
113
114   my (
115     $sec,
116     $min,
117     $hour,
118     $mday,
119     $mon,
120     $year,
121     $wday,
122     $yday,
123     $isdst
124   ) = localtime ($time);
125
126   # Adjust month
127   $mon++;
128
129   # Adjust year
130   $year += 1900;
131
132   # Zero preface month, day, hour and minute
133   $mon  = '0' . $mon  if $mon  < 10;
134   $mday = '0' . $mday if $mday < 10;
135   $hour = '0' . $hour if $hour < 10;
136   $min  = '0' . $min  if $min  < 10;
137   $sec  = '0' . $sec  if $sec  < 10;
138
139   return $year, $mon, $mday, $hour, $min, $sec;
140 } # ymdhms
141
142 sub julian($$$) {
143   my ($year, $month, $day) = @_;
144
145   my $days = 0;
146   my $m    = 1;
147
148   for (@months) {
149     last if $m >= $month;
150     $m++;
151     $days += $_;
152   } # for
153
154   return $days + $day;
155 } # julian
156
157 sub _is_leap_year($) {
158   my ($year) = @_;
159
160   return 0 if $year % 4;
161   return 1 if $year % 100;
162   return 0 if $year % 400;
163
164   return 1; 
165 } # _is_leap_year
166
167 sub Add($%) {
168   my ($datetime, %parms) = @_;
169
170 =pod
171
172 =head2 Add ($datetime, %parms)
173
174 Add to a datetime
175
176 Parameters:
177
178 =for html <blockquote>
179
180 =over
181
182 =item $datetime
183
184 Datetime in SQLDatetime format to manipulate.
185
186 =item %parms
187
188 Hash of parms. Acceptable values are of the following format:
189
190  seconds => $seconds
191  minutes => $minutes
192  hours   => $hours
193  days    => $days
194  month   => $month
195  
196 Note that month will simply increment the month number, adjusting for overflow
197 of year if appropriate. Therefore a date of 2/28/2001 would increase by 1 month
198 to yield 3/28/2001. And, unfortunately, an increase of 1 month to 1/30/2011 
199 would incorrectly yeild 2/30/2011!
200
201 =back
202
203 =for html </blockquote>
204
205 Returns:
206
207 =for html <blockquote>
208
209 =over
210
211 =item New datetime
212
213 =back
214
215 =for html </blockquote>
216
217 =cut
218
219   my @validKeys = (
220     'seconds',
221     'minutes',
222     'hours',
223     'days',
224     'months',
225   );
226
227   for (keys %parms) {
228     unless (InArray ($_, @validKeys)) {
229       croak "Invalid key in DateUtils::Add: $_";
230     } # unless
231   } # for
232
233   my $epochTime = DateToEpoch $datetime;
234
235   my $amount = 0;
236
237   $parms{seconds} ||= 0;
238   $parms{minutes} ||= 0;
239   $parms{hours}   ||= 0;
240   $parms{days}    ||= 0;
241
242   $amount += $parms{days}    * $SECS_IN_DAY;
243   $amount += $parms{hours}   * $SECS_IN_HOUR;
244   $amount += $parms{minutes} * $SECS_IN_MIN;
245   $amount += $parms{seconds};
246
247   $epochTime += $amount;
248
249   $datetime = EpochToDate $epochTime;
250
251   if ($parms{month}) {
252     my $years  = $parms{month} / 12;
253     my $months = $parms{month} % 12;
254
255     my $month = substr $datetime, 5, 2;
256
257     $years += ($month + $months) / 12;
258     substr ($datetime, 5, 2) = ($month + $months) % 12;
259
260     substr ($datetime, 0, 4) = substr ($datetime, 0, 4) + $years;
261   } # if
262
263   return $datetime;
264 } # Add
265
266 sub Age($) {
267   my ($timestamp) = @_;
268
269 =pod
270
271 =head2 Age ($timestamp)
272
273 Determines how old something is given a timestamp
274
275 Parameters:
276
277 =for html <blockquote>
278
279 =over
280
281 =item $timestamp:
282
283 Timestamp to age from (Assumed to be earlier than today)
284
285 =back
286
287 =for html </blockquote>
288
289 Returns:
290
291 =for html <blockquote>
292
293 =over
294
295 =item Number of days between $timestamp and today
296
297 =back
298
299 =for html </blockquote>
300
301 =cut
302
303   my $today      = Today2SQLDatetime;
304   my $today_year = substr $today, 0, 4;
305   my $month      = substr $today, 5, 2;
306   my $day        = substr $today, 8, 2;
307   my $today_days = julian $today_year, $month, $day;
308
309   my $timestamp_year = substr $timestamp, 0, 4;
310   $month             = substr $timestamp, 5, 2;
311   $day               = substr $timestamp, 8, 2;
312   my $timestamp_days = julian $timestamp_year, $month, $day;
313
314   if ($timestamp_year > $today_year or
315       ($timestamp_days > $today_days and $timestamp_year == $today_year)) {
316     return;
317   } else {
318     my $leap_days = 0;
319
320     for (my $i = $timestamp_year; $i < $today_year; $i++) {
321       $leap_days++ if $i % 4 == 0;
322     } # for
323
324     $today_days += 365 * ($today_year - $timestamp_year) + $leap_days;
325     return $today_days - $timestamp_days;
326   } # if
327 } # Age
328
329 sub Compare($$) {
330   my ($date1, $date2) = @_;
331
332 =pod
333
334 =head2 Compare ($date1, $date2)
335
336 Compares two datetimes returning -1 if $date1 < $date2, 0 if equal or 1 if
337 $date1 > $date2
338
339 Parameters:
340
341 =for html <blockquote>
342
343 =over
344
345 =item $date1
346
347 Date 1 to compare
348
349 =item $date2
350
351 Date 2 to compare
352
353 =back
354
355 =for html </blockquote>
356
357 Returns:
358
359 =for html <blockquote>
360
361 =over
362
363 =item -1 if $date1 < $date2, 0 if equal or 1 if $date1 > $date2
364
365 =back
366
367 =for html </blockquote>
368
369 =cut
370
371   return DateToEpoch ($date1) <=> DateToEpoch ($date2);
372 } # Compare
373
374 sub DateToEpoch($) {
375   my ($date) = @_;
376
377 =pod
378
379 =head2 DateToEpoch ($datetime)
380
381 Converts a datetime to epoch
382
383 Parameters:
384
385 =for html <blockquote>
386
387 =over
388
389 =item $datetime
390
391 Datetime to convert to an epoch
392
393 =back
394
395 =for html </blockquote>
396
397 Returns:
398
399 =for html <blockquote>
400
401 =over
402
403 =item $epoch
404
405 =back
406
407 =for html </blockquote>
408
409 =cut
410
411   my $year    = substr $date,  0, 4;
412   my $month   = substr $date,  5, 2;
413   my $day     = substr $date,  8, 2;
414   my $hour    = substr $date, 11, 2;
415   my $minute  = substr $date, 14, 2;
416   my $seconds = substr $date, 17, 2;
417
418   my $days;
419
420   for (my $i = 1970; $i < $year; $i++) {
421     $days += _is_leap_year ($i) ? 366 : 365;
422   } # for
423
424   my @monthDays = (
425     0,
426     31, 
427     59,
428     90,
429     120,
430     151,
431     181,
432     212,
433     243,
434     273,
435     304,
436     334,
437   );
438
439   $days += $monthDays[$month - 1];
440
441   $days++ if _is_leap_year ($year) and $month > 2;
442
443   $days += $day - 1;
444
445   return ($days   * $SECS_IN_DAY)
446        + ($hour   * $SECS_IN_HOUR)
447        + ($minute * $SECS_IN_MIN)
448        + $seconds;
449 } # DateToEpoch
450
451 sub EpochToDate($) {
452   my ($epoch) = @_;
453
454 =pod
455
456 =head2 EpochToDate ($epoch)
457
458 Converts an epoch to a datetime
459
460 Parameters:
461
462 =for html <blockquote>
463
464 =over
465
466 =item $epoch
467
468 Epoch to convert to a datetime
469
470 =back
471
472 =for html </blockquote>
473
474 Returns:
475
476 =for html <blockquote>
477
478 =over
479
480 =item $datetime
481
482 =back
483
484 =for html </blockquote>
485
486 =cut
487
488   my ($month, $day, $hour, $minute, $seconds);
489
490   my $year         = 1970;
491   my $leapYearSecs = 366 * $SECS_IN_DAY;
492   my $yearSecs     = $leapYearSecs - $SECS_IN_DAY;
493
494   while () {
495     my $amount = _is_leap_year ($year) ? $leapYearSecs : $yearSecs;
496
497     last if $amount > $epoch;
498
499     $epoch -= $amount;
500     $year++;
501   } # while
502
503   my $leapYearAdjustment = _is_leap_year ($year) ? 1 : 0;
504
505   if ($epoch >= (334 + $leapYearAdjustment) * $SECS_IN_DAY) {
506     $month = '12';
507     $epoch -= (334 + $leapYearAdjustment) * $SECS_IN_DAY;
508   } elsif ($epoch >= (304 + $leapYearAdjustment) * $SECS_IN_DAY) {
509     $month = '11';
510     $epoch -= (304 + $leapYearAdjustment) * $SECS_IN_DAY;
511   } elsif ($epoch >= (273 + $leapYearAdjustment) * $SECS_IN_DAY) {
512     $month = '10';
513     $epoch -= (273 + $leapYearAdjustment) * $SECS_IN_DAY;
514   } elsif ($epoch >= (243 + $leapYearAdjustment) * $SECS_IN_DAY) {
515     $month = '09';
516     $epoch -= (243 + $leapYearAdjustment) * $SECS_IN_DAY;
517   } elsif ($epoch >= (212 + $leapYearAdjustment) * $SECS_IN_DAY) {
518     $month = '08';
519     $epoch -= (212 + $leapYearAdjustment) * $SECS_IN_DAY;
520   } elsif ($epoch >= (181 + $leapYearAdjustment) * $SECS_IN_DAY) {
521     $month = '07';
522     $epoch -= (181 + $leapYearAdjustment) * $SECS_IN_DAY;
523   } elsif ($epoch >= (151 + $leapYearAdjustment) * $SECS_IN_DAY) {
524     $month = '06';
525     $epoch -= (151 + $leapYearAdjustment) * $SECS_IN_DAY;
526   } elsif ($epoch >= (120 + $leapYearAdjustment) * $SECS_IN_DAY) {
527     $month = '05';
528     $epoch -= (120 + $leapYearAdjustment) * $SECS_IN_DAY;
529   } elsif ($epoch >= (90 + $leapYearAdjustment) * $SECS_IN_DAY) {
530     $month = '04';
531     $epoch -= (90 + $leapYearAdjustment) * $SECS_IN_DAY;
532   } elsif ($epoch >= (59 + $leapYearAdjustment) * $SECS_IN_DAY) {
533     $month = '03';
534     $epoch -= (59 + $leapYearAdjustment) * $SECS_IN_DAY;
535   } elsif ($epoch >= 31 * $SECS_IN_DAY) {
536     $month = '02';
537     $epoch -= 31 * $SECS_IN_DAY;
538   } else {
539     $month = '01';
540   } # if
541
542   $day     = int (($epoch / $SECS_IN_DAY) + 1);
543   $epoch   = $epoch % $SECS_IN_DAY;
544   $hour    = int ($epoch / $SECS_IN_HOUR);
545   $epoch   = $epoch % $SECS_IN_HOUR;
546   $minute  = int ($epoch / $SECS_IN_MIN);
547   $seconds = $epoch % $SECS_IN_MIN;
548
549   $day     = "0$day"     if $day     < 10;
550   $hour    = "0$hour"    if $hour    < 10;
551   $minute  = "0$minute"  if $minute  < 10;
552   $seconds = "0$seconds" if $seconds < 10;
553
554   return "$year-$month-$day $hour:$minute:$seconds";
555 } # EpochToDate
556
557 sub UTCTime($) {
558   my ($datetime) = @_;
559
560 =pod
561
562 =head2 UTCTime ($epoch)
563
564 Converts an epoch to UTC Time
565
566 Parameters:
567
568 =for html <blockquote>
569
570 =over
571
572 =item $epoch
573
574 Epoch to convert to a datetime
575
576 =back
577
578 =for html </blockquote>
579
580 Returns:
581
582 =for html <blockquote>
583
584 =over
585
586 =item $datetime
587
588 =back
589
590 =for html </blockquote>
591
592 =cut
593
594   my @localtime = localtime;
595   my ($sec, $min, $hour, $mday, $mon, $year) = gmtime (
596     DateToEpoch ($datetime) - (timegm (@localtime) - timelocal (@localtime))
597   );
598
599   $year += 1900;
600   $mon++;
601
602   $sec  = '0' . $sec  if $sec  < 10;
603   $min  = '0' . $min  if $min  < 10;
604   $hour = '0' . $hour if $hour < 10;
605   $mon  = '0' . $mon  if $mon  < 10;
606   $mday = '0' . $mday if $mday < 10;
607
608   return "$year-$mon-${mday}T$hour:$min:${sec}Z";  
609 } # UTCTime
610
611 sub UTC2Localtime($) {
612   my ($utcdatetime) = @_;
613
614   # If the field does not look like a UTC time then just return it.
615   return $utcdatetime unless $utcdatetime =~ /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z/;
616
617   $utcdatetime =~ s/T/ /;
618   $utcdatetime =~ s/Z//;
619
620   my @localtime = localtime;
621
622   return EpochToDate(
623     DateToEpoch ($utcdatetime) + (timegm (@localtime) - timelocal (@localtime))
624   );
625 } # UTC2Localtime
626
627 sub FormatDate($;$) {
628   my ($date, $separator) = @_;
629
630 =pod
631
632 =head2 FormatDate ($date, $separator)
633
634 Formats date
635
636 Parameters:
637
638 =for html <blockquote>
639
640 =over
641
642 =item $date:
643
644 Date in YYYYMMDD
645
646 =tiem $separator
647
648 If specified, indicates that $date has separators (e.g. 2021-07-04).
649
650 =back
651
652 =for html </blockquote>
653
654 Returns:
655
656 =for html <blockquote>
657
658 =over
659
660 =item Returns a date in MM/DD/YYYY format
661
662 =back
663
664 =for html </blockquote>
665
666 =cut
667
668   unless ($separator) {
669     return substr($date, 4, 2) . '/'
670          . substr($date, 6, 2) . '/'
671          . substr($date, 0, 4);
672   } else {
673     return substr($date, 5, 2)
674          . '/'
675          . substr($date, 8, 2)
676          . '/' 
677          . substr($date, 0, 4);
678   } # if
679 } # FormatDate
680
681 sub FormatTime($) {
682   my ($time) = @_;
683
684 =pod
685
686 =head2 FormatTime ($time)
687
688 Formats Time
689
690 Parameters:
691
692 =for html <blockquote>
693
694 =over
695
696 =item $time:
697
698 Time in in HH:MM format (24 hour format)
699
700 =back
701
702 =for html </blockquote>
703
704 Returns:
705
706 =for html <blockquote>
707
708 =over
709
710 =item Time in HH:MM [Am|Pm] format
711
712 =back
713
714 =for html </blockquote>
715
716 =cut
717
718   my $hours   = substr $time, 0, 2;
719   my $minutes = substr $time, 3, 2;
720   my $AmPm    = $hours > 12 ? "Pm" : "Am";
721
722   $hours = $hours - 12 if $hours > 12;
723
724   $hours = "0$hours" if length $hours == 1;
725
726   return "$hours:$minutes $AmPm";
727 } # FormatTime
728
729 sub MDY(;$) {
730   my ($time) = @_;
731
732 =pod
733
734 =head2 MDY ($time)
735
736 Returns MM/DD/YYYY for $time
737
738 Parameters:
739
740 =for html <blockquote>
741
742 =over
743
744 =item $time:
745
746 Time in Unix time format (Default: current time)
747
748 =back
749
750 =for html </blockquote>
751
752 Returns:
753
754 =for html <blockquote>
755
756 =over
757
758 =item Date in MM/DD/YYYY
759
760 =back
761
762 =for html </blockquote>
763
764 =cut
765
766   my ($year, $mon, $mday) = ymdhms $time;
767
768   return "$mon/$mday/$year";
769 } # MDY
770
771 sub SQLDatetime2UnixDatetime($) {
772   my ($sqldatetime) = @_;
773
774 =pod
775
776 =head2 SQLDatetime2UnixDatetime ($sqldatetime)
777
778 Converts an SQL formatted date to a Unix (localtime) formatted date)
779
780 Parameters:
781
782 =for html <blockquote>
783
784 =over
785
786 =item $sqldatetime:
787
788 Date and time stamp in SQL format
789
790 =back
791
792 =for html </blockquote>
793
794 Returns:
795
796 =for html <blockquote>
797
798 =over
799
800 =item Returns a Unix formated date and time (a la localtime)
801
802 =back
803
804 =for html </blockquote>
805
806 =cut
807
808   my %months = (
809     "01" => "Jan",
810     "02" => "Feb",
811     "03" => "Mar",
812     "04" => "Apr",
813     "05" => "May",
814     "06" => "Jun",
815     "07" => "Jul",
816     "08" => "Aug",
817     "09" => "Sep",
818     "10" => "Oct",
819     "11" => "Nov",
820     "12" => "Dec"
821   );
822
823   my $year  = substr $sqldatetime, 0, 4;
824   my $month = substr $sqldatetime, 5, 2;
825   my $day   = substr $sqldatetime, 8, 2;
826   my $time  = FormatTime (substr $sqldatetime, 11);
827
828   return $months{$month} . " $day, $year \@ $time";
829 } # SQLDatetime2UnixDatetime
830
831 sub SubtractDays($$) {
832   my ($timestamp, $nbr_of_days) = @_;
833
834 =pod
835
836 =head2 SubtractDays ($timestamp, $nbr_of_days)
837
838 Subtracts $nbr_of_days from $timestamp
839
840 Parameters:
841
842 =for html <blockquote>
843
844 =over
845
846 =item $timestamp:
847
848 Timestamp to subtract days from
849
850 =back
851
852 =over
853
854 =item $nbr_of_days:
855
856 =back
857
858 Number of days to subtract from $timestamp
859
860 =for html </blockquote>
861
862 Returns:
863
864 =for html <blockquote>
865
866 =over
867
868 =item SQL format date $nbr_of_days ago
869
870 =back
871
872 =for html </blockquote>
873
874 =cut
875
876   my $year  = substr $timestamp, 0, 4;
877   my $month = substr $timestamp, 5, 2;
878   my $day   = substr $timestamp, 8, 2;
879
880   # We are not properly accounting for leap days but this is just a rough
881   # estimate anyway
882   if ($nbr_of_days > 365) {
883     $year -= int $nbr_of_days / 365;
884
885     $nbr_of_days = $nbr_of_days % 365;
886   } # if
887
888   # Convert to Julian
889   my $days = julian $year, $month, $day;
890
891   # Subtract $nbr_of_days
892   $days -= $nbr_of_days;
893
894   # Compute $days_in_year
895   my $days_in_year;
896
897   # Adjust if crossing year boundary
898   if ($days <= 0) {
899     $year--;
900     $days_in_year = (($year % 4) == 0) ? 366 : 365;
901     $days = $days_in_year + $days;
902   } else {
903     $days_in_year = (($year % 4) == 0) ? 366 : 365;
904   } # if
905
906   # Convert back
907   $month = 0;
908
909   while ($days > 28) {
910     # If remaining days is less than the current month then last
911     last if ($days <= $months[$month]);
912
913     # Subtract off the number of days in this month
914     $days -= $months[$month++];
915   } # while
916
917   # Prefix month with 0 if necessary
918   $month++;
919   if ($month < 10) {
920     $month = "0" . $month;
921   } # if
922
923   # Prefix days with  0 if necessary
924   if ($days == 0) {
925     $days = "01";
926   } elsif ($days < 10) {
927     $days = "0" . $days;
928   } # if
929
930   return $year . "-" . $month . "-" . $days . substr $timestamp, 10;
931 } # SubtractDays
932
933 sub Today2SQLDatetime() {
934
935 =pod
936
937 =head2 Today2SQLDatetime ($datetime)
938
939 Returns today's date in an SQL format
940
941 Parameters:
942
943 =for html <blockquote>
944
945 =over
946
947 =item None
948
949 =back
950
951 =for html </blockquote>
952
953 Returns:
954
955 =for html <blockquote>
956
957 =over
958
959 =item SQL formated time stamp for today
960
961 =back
962
963 =for html </blockquote>
964
965 =cut
966
967   return UnixDatetime2SQLDatetime(scalar localtime);
968 } # Today2SQLDatetime
969
970 sub UnixDatetime2SQLDatetime($) {
971   my ($datetime) = @_;
972
973 =pod
974
975 =head2 UnixDatetime2SQLDatetime ($datetime)
976
977 Converts a Unix (localtime) date/time stamp to an SQL formatted
978 date/time stamp
979
980 Parameters:
981
982 =for html <blockquote>
983
984 =over
985
986 =item $datetime:
987
988 Unix formated date time stamp
989
990 =back
991
992 =for html </blockquote>
993
994 Returns:
995
996 =for html <blockquote>
997
998 =over
999
1000 =item SQL formated time stamp
1001
1002 =back
1003
1004 =for html </blockquote>
1005
1006 =cut
1007
1008   my $orig_datetime = $datetime;
1009   my %months = (
1010     Jan => '01',
1011     Feb => '02',
1012     Mar => '03',
1013     Apr => '04',
1014     May => '05',
1015     Jun => '06',
1016     Jul => '07',
1017     Aug => '08',
1018     Sep => '09',
1019     Oct => '10',
1020     Nov => '11',
1021     Dec => '12',
1022   );
1023
1024   # Some mailers neglect to put the leading day of the week field in.
1025   # Check for this and compensate.
1026   my $dow = substr $datetime, 0, 3;
1027
1028   if ($dow ne 'Mon' and
1029       $dow ne 'Tue' and
1030       $dow ne 'Wed' and
1031       $dow ne 'Thu' and
1032       $dow ne 'Fri' and
1033       $dow ne 'Sat' and
1034       $dow ne 'Sun') {
1035     $datetime = 'XXX, ' . $datetime;
1036   } # if
1037
1038   # Some mailers have day before month. We need to correct this
1039   my $day = substr $datetime, 5, 2;
1040
1041   if ($day =~ /\d /) {
1042     $day      = '0' . (substr $day, 0, 1);
1043     $datetime = (substr $datetime, 0, 5) . $day . (substr $datetime, 6);
1044   } # if
1045
1046   if ($day !~ /\d\d/) {
1047     $day = substr $datetime, 8, 2;
1048   } # if
1049
1050   # Check for 1 digit date
1051   if ((substr $day, 0, 1) eq ' ') {
1052     $day      = '0' . (substr $day, 1, 1);
1053     $datetime = (substr $datetime, 0, 8) . $day . (substr $datetime, 10);
1054   } elsif ((substr $day, 1, 1) eq ' ') {
1055     $day      = '0' . (substr $day, 0, 1);
1056     $datetime = (substr $datetime, 0, 8) . $day . (substr $datetime, 9);
1057   } # if
1058
1059   my $year = substr $datetime, 20, 4;
1060
1061   if ($year !~ /\d\d\d\d/) {
1062     $year = substr $datetime, 12, 4;
1063     if ($year !~ /\d\d\d\d/) {
1064       $year = substr $datetime, 12, 2;
1065     } #if
1066   } # if
1067
1068   # Check for 2 digit year. Argh!
1069   if (length $year == 2 or (substr $year, 2, 1) eq ' ') {
1070     $year     = '20' . (substr $year, 0, 2);
1071     $datetime = (substr $datetime, 0, 12) . '20' . (substr $datetime, 12);
1072   } # if
1073
1074   my $month_name = substr $datetime, 4, 3;
1075
1076   unless ($months{$month_name}) {
1077     $month_name = substr $datetime, 8, 3;
1078   } # unless
1079
1080   my $month = $months{$month_name};
1081   my $time  = substr $datetime, 11, 8;
1082
1083   if ($time !~ /\d\d:\d\d:\d\d/) {
1084     $time = substr $datetime, 17, 8
1085   } # if
1086
1087   unless ($year) {
1088     warning "Year undefined for $orig_datetime\nReturning today's date";
1089     return Today2SQLDatetime;
1090   } # unless
1091
1092   unless ($month) {
1093     warning "Month undefined for $orig_datetime\nReturning today's date";
1094     return Today2SQLDatetime;
1095   } # unless
1096
1097   unless ($day) {
1098     warning "Day undefined for $orig_datetime\nReturning today's date";
1099     return Today2SQLDatetime;
1100   } # unless
1101
1102   unless ($time) {
1103     warning "Time undefined for $orig_datetime\nReturning today's date";
1104     return Today2SQLDatetime;
1105   } # unless
1106
1107   return "$year-$month-$day $time";
1108 } # UnixDatetime2SQLDatetime
1109
1110 sub YMD(;$) {
1111   my ($time) = @_;
1112
1113 =pod
1114
1115 =head2 YMD ($time)
1116
1117 Returns the YMD in a format of YYYYMMDD
1118
1119 Parameters:
1120
1121 =for html <blockquote>
1122
1123 =over
1124
1125 =item $time:
1126
1127 Time to convert to YYYYMMDD (Default: Current time)
1128
1129 =back
1130
1131 =for html </blockquote>
1132
1133 Returns:
1134
1135 =for html <blockquote>
1136
1137 =over
1138
1139 =item Date in YYYYMMDD format
1140
1141 =back
1142
1143 =for html </blockquote>
1144
1145 =cut
1146
1147   my ($year, $mon, $mday) = ymdhms $time;
1148
1149   return "$year$mon$mday";
1150 } # YMD
1151
1152 sub YMDHM(;$) {
1153   my ($time) = @_;
1154
1155 =pod
1156
1157 =head2 YMDHM ($time)
1158
1159 Returns the YMD in a format of YYYYMMDD@HH:MM
1160
1161 Parameters:
1162
1163 =for html <blockquote>
1164
1165 =over
1166
1167 =item $time:
1168
1169 Time to convert to YYYYMMDD@HH:MM (Default: Current time)
1170
1171 =back
1172
1173 =for html </blockquote>
1174
1175 Returns:
1176
1177 =for html <blockquote>
1178
1179 =over
1180
1181 =item Date in YYYYMMDD@HH:MM format
1182
1183 =back
1184
1185 =for html </blockquote>
1186
1187 =cut
1188
1189   my ($year, $mon, $mday, $hour, $min) = ymdhms $time;
1190
1191   return "$year$mon$mday\@$hour:$min";
1192 } # YMDHM
1193
1194 sub YMDHMS(;$) {
1195   my ($time) = @_;
1196
1197 =pod
1198
1199 =head2 YMDHMS ($time)
1200
1201 Returns the YMD in a format of YYYYMMDD@HH:MM:SS
1202
1203 Parameters:
1204
1205 =for html <blockquote>
1206
1207 =over
1208
1209 =item $time:
1210
1211 Time to convert to YYYYMMDD@HH:MM:SS (Default: Current time)
1212
1213 =back
1214
1215 =for html </blockquote>
1216
1217 Returns:
1218
1219 =for html <blockquote>
1220
1221 =over
1222
1223 =item Date in YYYYMMDD@HH:MM:SS format
1224
1225 =back
1226
1227 =for html </blockquote>
1228
1229 =cut
1230
1231   my ($year, $mon, $mday, $hour, $min, $sec) = ymdhms $time;
1232
1233   return "$year$mon$mday\@$hour:$min:$sec";
1234 } # YMDHMS
1235
1236 sub timestamp(;$) {
1237   my ($time) = @_;
1238
1239 =pod
1240
1241 =head2 timestamp ($time)
1242
1243 Returns the YMD in a format of YYYYMMDD_HHMM
1244
1245 Parameters:
1246
1247 =for html <blockquote>
1248
1249 =over
1250
1251 =item $time:
1252
1253 Time to convert to YYYYMMDD_HHMMSS (Default: Current time)
1254
1255 =for html </blockquote>
1256
1257 Returns:
1258
1259 =for html <blockquote>
1260
1261 =over
1262
1263 =item Date in YYYYMMDD_HHMMSS format
1264
1265 =back
1266
1267 =for html </blockquote>
1268
1269 =cut
1270
1271   my ($year, $mon, $mday, $hour, $min, $sec) = ymdhms $time;
1272
1273   return "$year$mon${mday}_$hour$min$sec";
1274 } # timestamp
1275
1276 1;
1277
1278 =head2 DEPENDENCIES
1279
1280 =head3 Perl Modules
1281
1282 =for html <p><a href="/php/scm_man.php?file=lib/Display.pm">Display</a></p>
1283
1284 =head1 INCOMPATABILITIES
1285
1286 None yet...
1287
1288 =head1 BUGS AND LIMITATIONS
1289
1290 There are no known bugs in this module.
1291
1292 Please report problems to Andrew DeFaria <Andrew@ClearSCM.com>.
1293
1294 =head1 LICENSE AND COPYRIGHT
1295
1296 This Perl Module is freely available; you can redistribute it and/or
1297 modify it under the terms of the GNU General Public License as
1298 published by the Free Software Foundation; either version 2 of the
1299 License, or (at your option) any later version.
1300
1301 This Perl Module is distributed in the hope that it will be useful,
1302 but WITHOUT ANY WARRANTY; without even the implied warranty of
1303 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1304 General Public License (L<http://www.gnu.org/copyleft/gpl.html>) for more
1305 details.
1306
1307 You should have received a copy of the GNU General Public License
1308 along with this Perl Module; if not, write to the Free Software Foundation,
1309 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1310 reserved.
1311
1312 =cut