1package Math::Calc::Units::Convert::Date; 2use base 'Math::Calc::Units::Convert::Base'; 3use Time::Local qw(timegm); 4use strict; 5use vars qw(%units %pref %ranges %total_unit_map); 6 7my $min_nice_time = timegm(0, 0, 0, 1, 0, 1975-1900); 8my $max_nice_time = timegm(0, 0, 0, 1, 0, 2030-1900); 9 10%units = (); 11%pref = ( default => 1 ); 12%ranges = ( timestamp => [ $min_nice_time, $max_nice_time ] ); 13 14sub major_pref { 15 return 2; 16} 17 18# sub major_variants {} 19 20# sub variants {} 21 22sub canonical_unit { return 'timestamp'; } 23 24sub unit_map { 25 my ($self) = @_; 26 if (keys %total_unit_map == 0) { 27 %total_unit_map = (%{$self->SUPER::unit_map()}, %units); 28 } 29 return \%total_unit_map; 30} 31 32sub get_ranges { 33 return \%ranges; 34} 35 36sub get_prefs { 37 return \%pref; 38} 39 40use vars qw(@MonthNames); 41BEGIN { @MonthNames = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec); } 42sub construct { 43 my ($self, $constructor, $args) = @_; 44 45 # Allow timestamp(1000347142) or timestamp() for the current time 46 if ($constructor eq 'timestamp') { 47 $args = time if $args eq ''; 48 return [ $args, { 'timestamp' => 1 } ]; 49 } 50 51 return unless $constructor eq 'date'; 52 53 # Accept a very limited range of formats. 54 55 # Always assume GMT if not given. Currently, do not handle timezones. 56 $args =~ s/\s+GMT\s+$//; 57 58 my ($Mon, $d, $y, $h, $m, $s, $tz, $M); 59 $tz = 'GMT'; 60 61 # Format 1: [Weekday] Mon DD HH:MM:SS [Timezone] YYYY 62 # (as returned by gmtime and the 'date' command) 63 # The weekday is ignored if given. The timezone is currently ignored. 64 if ($args =~ /^((?:\w\w\w\s+)?) 65 (\w\w\w)\s* 66 (\d+)\s+ 67 (\d+):(\d+)[:.](\d+)\s+ 68 (\w+)?\s* 69 (\d\d\d\d)$/x) 70 { 71 (undef, $Mon, $d, $h, $m, $s, $tz, $y) = ($1, $2, $3, $4, $5, $6, $7, $8); 72 73 # Format 2: Mon DD YYYY 74 } elsif ($args =~ /^(\w\w\w)[\s-]* 75 (\d+)[,\s-]+ 76 (\d\d\d\d)$/x) 77 { 78 ($Mon, $d, $y) = ($1, $2, $3); 79 80 # Format 3: YYYY-MM-DD HH:MM:SS 81 } elsif ($args =~ /^(\d\d\d\d)-(\d+)-(\d+)\s+ 82 (\d+):(\d+)[:.](\d+)$/x) 83 { 84 ($y, $M, $d, $h, $m, $s) = ($1, $2, $3, $4, $5, $6); 85 $M--; 86 87 # Format 4: YYYY-MM-DD 88 } elsif ($args =~ /^(\d\d\d\d)-(\d+)-(\d+)$/) { 89 ($y, $M, $d) = ($1, $2, $3); 90 $M--; 91 } else { 92 die "Unparseable date string '$args'"; 93 } 94 95 $h ||= 0; 96 $m ||= 0; 97 $s ||= 0; 98 99 if (defined $Mon) { 100 $M = 0; 101 foreach (@MonthNames) { 102 last if lc($_) eq lc($Mon); 103 $M++; 104 } 105 die "Unparseable month '$Mon'" if $M > 11; 106 } 107 108 if (defined($tz) && $tz ne 'GMT') { 109 warn "Timezones not supported. Assuming GMT.\n"; 110 } 111 112 my $timestamp = timegm($s, $m, $h, $d, $M, $y-1900); 113 die "Date '$args' is out of range" if $timestamp == -1; 114 return [ $timestamp, { 'timestamp' => 1 } ]; 115} 116 117sub render { 118 my ($self, $mag, $name, $power) = @_; 119 return "\@$mag" if $power != 1; 120 return "\@$mag" if $mag < $min_nice_time; 121 return "\@$mag" if $mag > $max_nice_time; 122 return gmtime($mag) . " (\@$mag)"; 123} 124 1251; 126