home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / perl_ste.zip / Date / Parse.pm < prev   
Text File  |  1997-01-02  |  6KB  |  293 lines

  1. # Date::Parse
  2. #
  3. # Copyright (c) 1995 Graham Barr. All rights reserved. This program is free
  4. # software; you can redistribute it and/or modify it under the same terms
  5. # as Perl itself.
  6.  
  7. package Date::Parse;
  8.  
  9. =head1 NAME
  10.  
  11. Date::Parse - Parse date strings into time values
  12.  
  13. =head1 SYNOPSIS
  14.  
  15.     use Date::Parse;
  16.     
  17.     $time = str2time($date);
  18.     
  19.     ($ss,$mm,$hh,$day,$month,$year,$zone) = strptime($date);
  20.  
  21. =head1 DESCRIPTION
  22.  
  23. C<Date::Parse> provides two routines for parsing date strings into time values.
  24.  
  25. =over 4
  26.  
  27. =item str2time(DATE [, ZONE])
  28.  
  29. C<str2time> parses C<DATE> and returns a unix time value, or undef upon failure.
  30. C<ZONE>, if given, specifies the timezone to assume when parsing if the
  31. date string does not specify a timezome.
  32.  
  33. =item strptime(DATE [, ZONE])
  34.  
  35. C<strptime> takes the same arguments as str2time but returns an array of
  36. values C<($ss,$mm,$hh,$day,$month,$year,$zone)>. Elements are only defined
  37. if they could be extracted from the date string. The C<$zone> element is
  38. the timezone offset in seconds from GMT. An empty array is returned upon
  39. failure.
  40.  
  41. =head1 MULTI-LANGUAGE SUPPORT
  42.  
  43. Date::Parse is capable of parsing dates in several languages, these are
  44. English, French, German and Italian. Changing the language is done via
  45. a static method call, for example
  46.  
  47.     Date::Parse->language('German');
  48.  
  49. will cause Date::Parse to attempt to parse any subsequent dates in German.
  50.  
  51. This is only a first pass, I am considering changing this to be
  52.  
  53.     $lang = Date::Language->new('German');
  54.     $lang->str2time("25 Jun 1996 21:09:55 +0100");
  55.  
  56. I am open to suggestions on this.
  57.  
  58. =head1 AUTHOR
  59.  
  60. Graham Barr <Graham.Barr@tiuk.ti.com>
  61.  
  62. =head1 REVISION
  63.  
  64. $Revision: 2.6 $
  65.  
  66. =head1 COPYRIGHT
  67.  
  68. Copyright (c) 1995 Graham Barr. All rights reserved. This program is free
  69. software; you can redistribute it and/or modify it under the same terms
  70. as Perl itself.
  71.  
  72. =cut
  73.  
  74. require 5.000;
  75. use strict;
  76. use vars qw($VERSION @ISA @EXPORT);
  77. use Time::Local;
  78. use Carp;
  79. use Time::Zone;
  80. use Exporter;
  81.  
  82. @ISA = qw(Exporter);
  83. @EXPORT = qw(&strtotime &str2time &strptime);
  84.  
  85. $VERSION = sprintf("%d.%02d", q$Revision: 2.6 $ =~ m#(\d+)\.(\d+)#);
  86.  
  87. my %month = (
  88.     january        => 0,
  89.     february    => 1,
  90.     march        => 2,
  91.     april        => 3,
  92.     may        => 4,
  93.     june        => 5,
  94.     july        => 6,
  95.     august        => 7,
  96.     september    => 8,
  97.     sept        => 8,
  98.     october        => 9,
  99.     november    => 10,
  100.     december    => 11,
  101.     );
  102.  
  103. my %day = (
  104.     sunday        => 0,
  105.     monday        => 1,
  106.     tuesday        => 2,
  107.     tues        => 2,
  108.     wednesday    => 3,
  109.     wednes        => 3,
  110.     thursday    => 4,
  111.     thur        => 4,
  112.     thurs        => 4,
  113.     friday        => 5,
  114.     saturday    => 6,
  115.     );
  116.  
  117. my @suf = (qw(th st nd rd th th th th th th)) x 3;
  118. @suf[11,12,13] = qw(th th th);
  119.  
  120. #Abbreviations
  121.  
  122. map { $month{substr($_,0,3)} = $month{$_} } keys %month;
  123. map { $day{substr($_,0,3)}   = $day{$_} }   keys %day;
  124.  
  125. my $strptime = <<'ESQ';
  126.  my %month = map { lc $_ } %$mon_ref;
  127.  my $daypat = join("|", map { lc $_ } keys %$day_ref);
  128.  my $monpat = join("|", keys %month);
  129.  my $sufpat = join("|", map { lc $_ } @$suf_ref);
  130.  
  131.  my %ampm = (
  132.     am => 0,
  133.     pm => 12
  134.     );
  135.  
  136.  # allow map am +. a.m.
  137.  map { my($z) = $_; $z =~ s#(\w)#$1\.#g; $ampm{$z} = $ampm{$_} } keys %ampm;
  138.  
  139.  my($AM, $PM) = (0,12);
  140.  
  141. sub
  142. {
  143.  
  144.  my $dtstr = lc shift;
  145.  my $merid = 24;
  146.  
  147.  my($year,$month,$day,$hh,$mm,$ss,$zone) = (undef) x 7;
  148.  
  149.  $zone = tz_offset(shift)
  150.     if(@_);
  151.  
  152.  while(1) { last unless($dtstr =~ s#\([^\(\)]*\)# #o) }
  153.  
  154.  $dtstr =~ s#(\A|\n|\Z)# #sog;
  155.  
  156.  # ignore day names
  157.  $dtstr =~ s#([\d\w\s])[\.\,]\s#$1 #sog;
  158.  $dtstr =~ s#($daypat)\s*(den\s)?# #o;
  159.  # Time: 12:00 or 12:00:00 with optional am/pm
  160.   
  161.  if($dtstr =~ s#[:\s](\d\d?):(\d\d)(:(\d\d)(?:\.\d+)?)?\s*([ap]\.?m\.?)?\s# #o)
  162.   {
  163.    ($hh,$mm,$ss) = ($1,$2,$4 || 0);
  164.    $merid = $ampm{$5} if($5);
  165.   }
  166.  
  167.  # Time: 12 am
  168.   
  169.  elsif($dtstr =~ s#\s(\d\d?)\s*([ap]\.?m\.?)\s# #o)
  170.   {
  171.    ($hh,$mm,$ss) = ($1,0,0);
  172.    $merid = $ampm{$2};
  173.   }
  174.   
  175.  # Date: 12-June-96 (using - . or /)
  176.   
  177.  if($dtstr =~ s#\s(\d\d?)([\-\./])($monpat)(\2(\d\d+))?\s# #o)
  178.   {
  179.    ($month,$day) = ($month{$3},$1);
  180.    $year = $5
  181.         if($5);
  182.   }
  183.   
  184.  # Date: 12-12-96 (using '-', '.' or '/' )
  185.   
  186.  elsif($dtstr =~ s#\s(\d\d*)([\-\./])(\d\d?)(\2(\d\d+))?\s# #o)
  187.   {
  188.    ($month,$day) = ($1 - 1,$3);
  189.    if($5)
  190.     {
  191.      $year = $5;
  192.      # Possible match for 1995-01-24 (short mainframe date format);
  193.      ($year,$month,$day) = ($1, $3 - 1, $5)
  194.             if($month > 12);
  195.     }
  196.   }
  197.  elsif($dtstr =~ s#\s(\d+)\s*($sufpat)?\s*($monpat)# #o)
  198.   {
  199.    ($month,$day) = ($month{$3},$1);
  200.   }
  201.  elsif($dtstr =~ s#($monpat)\s*(\d+)\s*($sufpat)?\s# #o)
  202.   {
  203.    ($month,$day) = ($month{$1},$2);
  204.   }
  205.  
  206.  # Date: 961212
  207.  
  208.  elsif($dtstr =~ s#\s(\d\d)(\d\d)(\d\d)\s# #o)
  209.   {
  210.    ($year,$month,$day) = ($1,$2-1,$3);
  211.   }
  212.  
  213.  $year = $1
  214.     if(!defined($year) && $dtstr =~ s#\s(\d{2}(\d{2})?)[\s\.,]# #o);
  215.  
  216.  # Zone
  217.  
  218.  if($dtstr =~ s#\s"?(\w{3,})\s# #o) 
  219.   {
  220.    $zone = tz_offset($1);
  221.    return ()
  222.     unless(defined $zone);
  223.   }
  224.  elsif($dtstr =~ s#\s(([\-\+])\d\d?)(\d\d)\s# #o)
  225.   {
  226.    my $m = $2 . $3;
  227.    $zone = 60 * ($m + (60 * $1));
  228.   }
  229.  
  230.  return ()
  231.     if($dtstr =~ /\S/o);
  232.  
  233.  $hh += 12
  234.     if(defined $hh && $merid == $PM);
  235.  
  236.  $year -= 1900
  237.     if(defined $year && $year > 1900);
  238.  
  239.  return ($ss,$mm,$hh,$day,$month,$year,$zone);
  240. }
  241. ESQ
  242.  
  243. use vars qw($day_ref $mon_ref $suf_ref $obj);
  244.  
  245. sub gen_parser
  246. {
  247.  local($day_ref,$mon_ref,$suf_ref,$obj) = @_;
  248.  
  249.  if($obj)
  250.   {
  251.    my $obj_strptime = $strptime;
  252.    substr($obj_strptime,index($strptime,"sub")+6,0) = <<'ESQ';
  253.  shift; # package
  254. ESQ
  255.    return eval "$obj_strptime";
  256.   }
  257.  
  258.  eval "$strptime";
  259.  
  260. }
  261.  
  262. *strptime = gen_parser(\%day,\%month,\@suf);
  263.  
  264. sub str2time
  265. {
  266.  my @t = strptime(@_);
  267.  
  268.  return undef
  269.     unless @t;
  270.  
  271.  my($ss,$mm,$hh,$day,$month,$year,$zone) = @t;
  272.  my @lt  = localtime(time);
  273.  
  274.  $hh    ||= 0;
  275.  $mm    ||= 0;
  276.  $ss    ||= 0;
  277.  
  278.  $month = $lt[4]
  279.     unless(defined $month);
  280.  
  281.  $day  = $lt[3]
  282.     unless(defined $day);
  283.  
  284.  $year = ($month > $lt[4]) ? ($lt[5] - 1) : $lt[5]
  285.     unless(defined $year);
  286.  
  287.  return defined $zone ? timegm($ss,$mm,$hh,$day,$month,$year) - $zone
  288.                       : timelocal($ss,$mm,$hh,$day,$month,$year);
  289. }
  290.  
  291. 1;
  292.  
  293.