home *** CD-ROM | disk | FTP | other *** search
/ CD Actual Thematic 7: Programming / CDAT7.iso / Share / Editores / Perl5 / perl / lib / site / Date / DateCalcLib.pm < prev    next >
Encoding:
Perl POD Document  |  1997-08-10  |  25.7 KB  |  1,034 lines

  1.  
  2. #  Copyright (c) 1997 by Steffen Beyer. All rights reserved.
  3. #  This package is free software; you can redistribute it
  4. #  and/or modify it under the same terms as Perl itself.
  5.  
  6. package Date::DateCalcLib;
  7.  
  8. use strict;
  9. use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION);
  10.  
  11. require Exporter;
  12.  
  13. @ISA = qw(Exporter);
  14.  
  15. @EXPORT = qw();
  16.  
  17. @EXPORT_OK = qw( nth_wday_of_month_year decode_date_us decode_date_eu
  18. year_month_day_offset parse_date easter_sunday calendar );
  19.  
  20. %EXPORT_TAGS = (all => [@EXPORT_OK]);
  21.  
  22. $VERSION = '3.2';
  23.  
  24. use Carp;
  25.  
  26. use Date::DateCalc qw(:all);
  27.  
  28. sub nth_wday_of_month_year
  29. {
  30.     croak "Usage: (\$year,\$mm,\$dd) = nth_wday_of_month_year(\$nth,\$wday,\$month,\$year);"
  31.       if (@_ != 4);
  32.  
  33.     my($nth,$wday,$month,$year) = @_;
  34.     my($first,$offset);
  35.     my($yy,$mm,$dd);
  36.  
  37.     return()
  38.       if (($nth < 1) || ($nth > 5) ||
  39.           ($wday < 1) || ($wday > 7) ||
  40.           ($month < 1) || ($month > 12) ||
  41.           ($year < 1));
  42.  
  43.     $first = day_of_week($year,$month,1);
  44.  
  45.     $offset = $wday - $first;
  46.     $offset += 7 if ($offset < 0);
  47.     $offset += --$nth * 7;
  48.  
  49.     return()
  50.       unless (($yy,$mm,$dd) = calc_new_date($year,$month,1,$offset));
  51.  
  52.     return()
  53.       if ($mm != $month);
  54.  
  55.     return($yy,$mm,$dd);
  56. }
  57.  
  58. sub decode_date_us
  59. {
  60.     croak "Usage: (\$year,\$mm,\$dd) = decode_date_us(\$date);"
  61.       if (@_ != 1);
  62.  
  63.     my($buffer) = @_;
  64.     my($yy,$mm,$dd,$len);
  65.  
  66.     if ($buffer =~ /^[^A-Za-z0-9]*  ([A-Za-z]+)  [^A-Za-z0-9]*  0*(\d+)  \D*$/x)
  67.     {
  68.         ($mm,$buffer) = ($1,$2);
  69.         $mm = decode_month($mm);
  70.         unless ($mm > 0)
  71.         {
  72.             return(); # can't decode month!
  73.         }
  74.         $len = length($buffer);
  75.         if    ($len == 2)
  76.         {
  77.             $dd = substr($buffer,0,1);
  78.             $yy = substr($buffer,1,1);
  79.         }
  80.         elsif ($len == 3)
  81.         {
  82.             $dd = substr($buffer,0,1);
  83.             $yy = substr($buffer,1,2);
  84.         }
  85.         elsif ($len == 4)
  86.         {
  87.             $dd = substr($buffer,0,2);
  88.             $yy = substr($buffer,2,2);
  89.         }
  90.         elsif ($len == 5)
  91.         {
  92.             $dd = substr($buffer,0,1);
  93.             $yy = substr($buffer,1,4);
  94.         }
  95.         elsif ($len == 6)
  96.         {
  97.             $dd = substr($buffer,0,2);
  98.             $yy = substr($buffer,2,4);
  99.         }
  100.         else { return(); } # wrong number of digits!
  101.     }
  102.     elsif ($buffer =~ /^[^A-Za-z0-9]*  ([A-Za-z]+)  [^A-Za-z0-9]*  (\d+)  \D+  (\d+)  \D*$/x)
  103.     {
  104.         ($mm,$dd,$yy) = ($1,$2,$3);
  105.         $mm = decode_month($mm);
  106.         unless ($mm > 0)
  107.         {
  108.             return(); # can't decode month!
  109.         }
  110.     }
  111.     elsif ($buffer =~ /^\D*  0*(\d+)  \D*$/x)
  112.     {
  113.         $buffer = $1;
  114.         $len = length($buffer);
  115.         if    ($len == 3)
  116.         {
  117.             $mm = substr($buffer,0,1);
  118.             $dd = substr($buffer,1,1);
  119.             $yy = substr($buffer,2,1);
  120.         }
  121.         elsif ($len == 4)
  122.         {
  123.             $mm = substr($buffer,0,1);
  124.             $dd = substr($buffer,1,1);
  125.             $yy = substr($buffer,2,2);
  126.         }
  127.         elsif ($len == 5)
  128.         {
  129.             $mm = substr($buffer,0,1);
  130.             $dd = substr($buffer,1,2);
  131.             $yy = substr($buffer,3,2);
  132.         }
  133.         elsif ($len == 6)
  134.         {
  135.             $mm = substr($buffer,0,2);
  136.             $dd = substr($buffer,2,2);
  137.             $yy = substr($buffer,4,2);
  138.         }
  139.         elsif ($len == 7)
  140.         {
  141.             $mm = substr($buffer,0,1);
  142.             $dd = substr($buffer,1,2);
  143.             $yy = substr($buffer,3,4);
  144.         }
  145.         elsif ($len == 8)
  146.         {
  147.             $mm = substr($buffer,0,2);
  148.             $dd = substr($buffer,2,2);
  149.             $yy = substr($buffer,4,4);
  150.         }
  151.         else { return(); } # wrong number of digits!
  152.     }
  153.     elsif ($buffer =~ /^\D*  (\d+)  \D+  (\d+)  \D+  (\d+)  \D*$/x)
  154.     {
  155.         ($mm,$dd,$yy) = ($1,$2,$3);
  156.     }
  157.     else { return(); } # no match at all!
  158.  
  159.     if ($yy < 100) { $yy += 1900; }
  160.  
  161.     if (check_date($yy,$mm,$dd))
  162.     {
  163.         return($yy,$mm,$dd);
  164.     }
  165.     else { return(); } # not a valid date!
  166. }
  167.  
  168. sub decode_date_eu
  169. {
  170.     croak "Usage: (\$year,\$mm,\$dd) = decode_date_eu(\$date);"
  171.       if (@_ != 1);
  172.  
  173.     my($buffer) = @_;
  174.     my($yy,$mm,$dd,$len);
  175.  
  176.     if ($buffer =~ /^\D*  (\d+)  [^A-Za-z0-9]*  ([A-Za-z]+)  [^A-Za-z0-9]*  (\d+)  \D*$/x)
  177.     {
  178.         ($dd,$mm,$yy) = ($1,$2,$3);
  179.         $mm = decode_month($mm);
  180.         unless ($mm > 0)
  181.         {
  182.             return(); # can't decode month!
  183.         }
  184.     }
  185.     elsif ($buffer =~ /^\D*  0*(\d+)  \D*$/x)
  186.     {
  187.         $buffer = $1;
  188.         $len = length($buffer);
  189.         if    ($len == 3)
  190.         {
  191.             $dd = substr($buffer,0,1);
  192.             $mm = substr($buffer,1,1);
  193.             $yy = substr($buffer,2,1);
  194.         }
  195.         elsif ($len == 4)
  196.         {
  197.             $dd = substr($buffer,0,1);
  198.             $mm = substr($buffer,1,1);
  199.             $yy = substr($buffer,2,2);
  200.         }
  201.         elsif ($len == 5)
  202.         {
  203.             $dd = substr($buffer,0,1);
  204.             $mm = substr($buffer,1,2);
  205.             $yy = substr($buffer,3,2);
  206.         }
  207.         elsif ($len == 6)
  208.         {
  209.             $dd = substr($buffer,0,2);
  210.             $mm = substr($buffer,2,2);
  211.             $yy = substr($buffer,4,2);
  212.         }
  213.         elsif ($len == 7)
  214.         {
  215.             $dd = substr($buffer,0,1);
  216.             $mm = substr($buffer,1,2);
  217.             $yy = substr($buffer,3,4);
  218.         }
  219.         elsif ($len == 8)
  220.         {
  221.             $dd = substr($buffer,0,2);
  222.             $mm = substr($buffer,2,2);
  223.             $yy = substr($buffer,4,4);
  224.         }
  225.         else { return(); } # wrong number of digits!
  226.     }
  227.     elsif ($buffer =~ /^\D*  (\d+)  \D+  (\d+)  \D+  (\d+)  \D*$/x)
  228.     {
  229.         ($dd,$mm,$yy) = ($1,$2,$3);
  230.     }
  231.     else { return(); } # no match at all!
  232.  
  233.     if ($yy < 100) { $yy += 1900; }
  234.  
  235.     if (check_date($yy,$mm,$dd))
  236.     {
  237.         return($yy,$mm,$dd);
  238.     }
  239.     else { return(); } # not a valid date!
  240. }
  241.  
  242. sub year_month_day_offset
  243. {
  244.     croak "Usage: (\$year,\$mm,\$dd) = year_month_day_offset(\$year,\$mm,\$dd,\$y_offs,\$m_offs,\$d_offs);"
  245.       if (@_ != 6);
  246.  
  247.     my($year,$mm,$dd,$y_offset,$m_offset,$d_offset) = @_;
  248.     my($y_diff);
  249.  
  250.     $year     = int($year);
  251.     $mm       = int($mm);
  252.     $dd       = int($dd);
  253.  
  254.     $y_offset = int($y_offset);
  255.     $m_offset = int($m_offset);
  256.     $d_offset = int($d_offset);
  257.  
  258.     return()
  259.       unless (check_date($year,$mm,$dd));
  260.  
  261.     if ($d_offset != 0)
  262.     {
  263.         return()
  264.           unless (($year,$mm,$dd) = calc_new_date($year,$mm,$dd,$d_offset));
  265.     }
  266.  
  267.     $y_diff = 0;
  268.  
  269.     if ($m_offset != 0)
  270.     {
  271.         $mm += --$m_offset;       # "--" because $mm is in the range 1..12
  272.  
  273.         $y_diff = int($mm / 12);
  274.         $mm -= $y_diff * 12;
  275.  
  276.         if ($mm < 0) { $mm += 12; $y_diff--; }
  277.  
  278.         $mm++;                    # shift $mm back into the range 1..12
  279.     }
  280.  
  281.     $year += $y_diff + $y_offset;
  282.  
  283.     if ($year > 0)
  284.     {
  285.         if (($dd == 29) && ($mm == 2) && (!leap($year))) { $dd = 1; $mm = 3; }
  286.         return($year,$mm,$dd);
  287.     }
  288.     else { return(); }
  289. }
  290.  
  291. sub parse_date
  292. {
  293.     croak "Usage: (\$year,\$mm,\$dd) = parse_date(\$date);"
  294.       if (@_ != 1);
  295.  
  296.     my($date) = @_;
  297.     my($yy,$mm,$dd);
  298.     unless ($date =~ /\b([JFMASOND][aepuco][nbrynlgptvc])\s+([0123]??\d)\b/)
  299.     {
  300.         return();
  301.     }
  302.     $mm = $1;
  303.     $dd = $2;
  304.     unless ($date =~ /\b(19\d\d|20\d\d)\b/)
  305.     {
  306.         return();
  307.     }
  308.     $yy = $1;
  309.     $mm = decode_month($mm);
  310.     unless ($mm > 0)
  311.     {
  312.         return();
  313.     }
  314.     unless (check_date($yy,$mm,$dd))
  315.     {
  316.         return();
  317.     }
  318.     return($yy,$mm,$dd);
  319. }
  320.  
  321. sub easter_sunday  #  Gauss'sche Regel (Gauss' Rule)
  322. {
  323.     # Quelle / Source:
  324.  
  325.     # H. H. Voigt, "Abriss der Astronomie", Wissenschaftsverlag,
  326.     # Bibliographisches Institut, Seite 9.
  327.  
  328.     croak "Usage: (\$year,\$mm,\$dd) = easter_sunday(\$year);"
  329.       if (@_ != 1);
  330.  
  331.     my($year) = @_;
  332.     my($a,$b,$c,$d,$e,$m,$n);
  333.     my($mm,$dd);
  334.  
  335.     return()
  336.       if (($year < 1583) || ($year > 2299));
  337.  
  338.     if    ($year < 1700) { $m = 22; $n = 2; }
  339.     elsif ($year < 1800) { $m = 23; $n = 3; }
  340.     elsif ($year < 1900) { $m = 23; $n = 4; }
  341.     elsif ($year < 2100) { $m = 24; $n = 5; }
  342.     elsif ($year < 2200) { $m = 24; $n = 6; }
  343.     else                 { $m = 25; $n = 0; }
  344.  
  345.     $a = $year % 19;
  346.     $b = $year % 4;
  347.     $c = $year % 7;
  348.     $d = (19 * $a + $m) % 30;
  349.     $e = (2 * $b + 4 * $c + 6 * $d + $n) % 7;
  350.     $dd = 22 + $d + $e;
  351.     $mm = 3;
  352.  
  353.     if ($dd > 31)
  354.     {
  355.         $dd -= 31;  #  $dd = $d + $e - 9;
  356.         $mm++;
  357.     }
  358.  
  359.     if (($dd == 26) && ($mm == 4))
  360.     { $dd = 19; }
  361.  
  362.     if (($dd == 25) && ($mm == 4) && ($d == 28) && ($e == 6) && ($a > 10))
  363.     { $dd = 18; }
  364.  
  365.     return($year,$mm,$dd);
  366. }
  367.  
  368. # Carnival Monday / Rosenmontag / Veille du Mardi Gras  : Easter Sunday - 48
  369. # Mardi Gras / Karnevalsdienstag / Mardi Gras           : Easter Sunday - 47
  370. # Ash Wednesday / Aschermittwoch / Mercredi des Cendres : Easter Sunday - 46
  371. # Palm Sunday / Palmsonntag / Dimanche des Rameaux      : Easter Sunday - 7
  372. # Easter Friday / Karfreitag / Vendredi Saint           : Easter Sunday - 2
  373. # Easter Saturday / Ostersamstag / Samedi de Paques     : Easter Sunday - 1
  374. # Easter Monday / Ostermontag / Lundi de Paques         : Easter Sunday + 1
  375. # Ascension of Christ / Christi Himmelfahrt / Ascension : Easter Sunday + 39
  376. # Whitsunday / Pfingstsonntag / Dimanche de Pentecote   : Easter Sunday + 49
  377. # Whitmonday / Pfingstmontag / Lundi de Pentecote       : Easter Sunday + 50
  378. # Feast of Corpus Christi / Fronleichnam / Fete-Dieu    : Easter Sunday + 60
  379.  
  380. sub calendar
  381. {
  382.     croak "Usage: \$string = calendar(\$year,\$month);"
  383.       if (@_ != 2);
  384.  
  385.     my($year,$month) = @_;
  386.     my($first,$last);
  387.     my($i,$j);
  388.     my($cal);
  389.  
  390.     return()
  391.       if (($month < 1) || ($month > 12) || ($year < 1));
  392.  
  393.     $cal = center((month_name_tab($month) . ' ' . $year), 27);
  394.     $cal .= "\nMon Tue Wed Thu Fri Sat Sun\n";
  395.  
  396.     $first = day_of_week($year,$month,1);
  397.     $last = days_in_month($year,$month);
  398.  
  399.     $j = $first - 1;
  400.  
  401.     $cal .= ('    ' x $j);
  402.  
  403.     for ( $i = 1; $i <= $last; $i++, $j++ )
  404.     {
  405.         if ($j >= 7)
  406.         {
  407.             $j = 0;
  408.             $cal .= "\n";
  409.         }
  410.         $cal .= sprintf(" %2d ", $i);
  411.     }
  412.     $cal .= "\n";
  413.     return($cal);
  414. }
  415.  
  416. sub center
  417. {
  418.     my($string,$width) = @_;
  419.     my($length,$left,$right);
  420.  
  421.     $length = length($string);
  422.     return($string) if ($length >= $width);
  423.     $length = $width - $length;
  424.     $left = int($length / 2);
  425.     $right = $length - $left;
  426.     return( (' ' x $left) . $string . (' ' x $right) );
  427. }
  428.  
  429. 1;
  430.  
  431. __END__
  432.  
  433. =head1 NAME
  434.  
  435. Date::DateCalcLib - Date Calculations Library
  436.  
  437. Library of useful date calculation functions
  438.  
  439. =head1 SYNOPSIS
  440.  
  441. =over 4
  442.  
  443. =item *
  444.  
  445. C<use Date::DateCalcLib qw( nth_wday_of_month_year>
  446. C<decode_date_us decode_date_eu year_month_day_offset>
  447. C<parse_date easter_sunday calendar );>
  448.  
  449. =item *
  450.  
  451. C<use Date::DateCalcLib qw(:all);>
  452.  
  453. =item *
  454.  
  455. C<($year,$mm,$dd) = nth_wday_of_month_year($nth,$wday,$month,$year);>
  456.  
  457. =item *
  458.  
  459. C<($year,$mm,$dd) = decode_date_us($date);>
  460.  
  461. =item *
  462.  
  463. C<($year,$mm,$dd) = decode_date_eu($date);>
  464.  
  465. =item *
  466.  
  467. C<($year,$mm,$dd) = year_month_day_offset($year,$mm,$dd,$y_offs,$m_offs,$d_offs);>
  468.  
  469. =item *
  470.  
  471. C<($year,$mm,$dd) = parse_date(`/bin/date`);>
  472.  
  473. =item *
  474.  
  475. C<($year,$mm,$dd) = easter_sunday($year);>
  476.  
  477. =item *
  478.  
  479. C<$string = calendar($year,$month);>
  480.  
  481. =back
  482.  
  483. =head1 DESCRIPTION
  484.  
  485. This module expands the functionality of the "Date::DateCalc" module
  486. (see L<Date::DateCalc(3)> for more details), which is intended to be
  487. a rather basic set of tools, with functions for various special tasks
  488. like:
  489.  
  490. =over 4
  491.  
  492. =item *
  493.  
  494. calculating the n-th weekday for a given month and year
  495.  
  496. =item *
  497.  
  498. parsing dates in U.S. american and european format
  499.  
  500. =item *
  501.  
  502. calculating a new date with a year, month and/or day offset
  503.  
  504. =item *
  505.  
  506. parsing the current date or the submission date of an e-mail message
  507.  
  508. =item *
  509.  
  510. calculating easter sunday and all the related christian feast days
  511.  
  512. =item *
  513.  
  514. printing a calendar for a given month and year
  515.  
  516. =back
  517.  
  518. For a detailed description of each function, see below:
  519.  
  520. =over 4
  521.  
  522. =item *
  523.  
  524. C<use Date::DateCalcLib qw( nth_wday_of_month_year>
  525. C<decode_date_us decode_date_eu year_month_day_offset>
  526. C<parse_date easter_sunday calendar );>
  527.  
  528. Use this statement to make the functions of this module
  529. available in your module or script.
  530.  
  531. You can also use any subset of the functions listed above
  532. that you like by only including the names of the functions
  533. you actually need between the parentheses of the "qw()"
  534. operator above.
  535.  
  536. =item *
  537.  
  538. C<use Date::DateCalcLib qw(:all);>
  539.  
  540. Alternate and simpler way of importing ALL the functions
  541. exported by this module into your module or script.
  542.  
  543. =item *
  544.  
  545. C<($year,$mm,$dd) = nth_wday_of_month_year($nth,$wday,$month,$year);>
  546.  
  547. This function calculates the n-th weekday for a given month and year,
  548. for example the 3rd Thursday of a given month and year.
  549.  
  550. "C<$nth>" must be in the range 1 to 5 (for "the first" to "the fifth"),
  551. "C<$wday>" must be in the range 1 to 7 (1 = Monday, 7 = Sunday),
  552. "C<$month>" must (of course) be in the range 1 to 12 and "C<$year>"
  553. must be greater than zero.
  554.  
  555. The function returns an empty list if any of its parameters is illegal
  556. or if the requested date cannot be calculated (for instance, if there
  557. is no fifth "C<$wday>" in the given month and year!).
  558.  
  559. Example:
  560.  
  561. Suppose you have a meeting (of some user group, for instance) in regular
  562. intervals, let's say the first Friday of each month, and that you want to
  563. send a mail to all members saying: "Remember: Tomorrow is our user group's
  564. meeting!" on the day before.
  565.  
  566. Given the current date, you would go about this as follows:
  567.  
  568. Convert the current date into days using the function "calc_days()"
  569. of the "Date::DateCalc" module. We'll refer to this number as "the
  570. number of days of the current date" below.
  571.  
  572. Calculate the first Friday of the current month.
  573.  
  574. Convert the resulting date into days using the function "calc_days()"
  575. of the "Date::DateCalc" module.
  576.  
  577. See if the number of days of the current date *plus one* is the same
  578. as the number of days of the first Friday of the current month.
  579.  
  580. If so, send your mail!
  581.  
  582. If not, calculate the first Friday of the NEXT month (beware: if the
  583. month is equal to 12, you need to "wrap" it back to 1 and to increment
  584. the year number!).
  585.  
  586. (This is necessary because the first Friday of any given month could
  587. fall on the first day of that month, which means that the day before
  588. that (when you want to send your mail!) is in the PREVIOUS month!)
  589.  
  590. Convert the resulting date into days using the function "calc_days()"
  591. of the "Date::DateCalc" module.
  592.  
  593. See if the number of days of the current date *plus one* is the same
  594. as the number of days of the first Friday of the next month.
  595.  
  596. If so, send your mail!
  597.  
  598. If not, you're done for today!
  599.  
  600. (On a UNIX system, you would normally use a "cron" job running once
  601. every day to automatically carry out these calculations and to send
  602. the reminder mail.)
  603.  
  604. =item *
  605.  
  606. C<($year,$mm,$dd) = decode_date_us($date);>
  607.  
  608. Using this function, you can parse dates in almost any format,
  609. provided the date is given as "month - day - year".
  610.  
  611. (To decode dates in european format, i.e., dates given as
  612. "day - month - year", see the function "decode_date_eu()"
  613. in this module or the function "decode_date()" in the
  614. "Date::DateCalc" module.)
  615.  
  616. The day and the year must be given as numbers, the month may be
  617. specified either by a number or its name in English (however,
  618. only up to the 3 first characters are compared, any extra
  619. characters are ignored). The latter comparison is carried out
  620. in a case-insensitive manner.
  621.  
  622. If they uniquely identify the month, one or two letters are
  623. sufficient (e.g., "s" for september or "ja" for january).
  624.  
  625. The year may be abbreviated as well, for instance "97" instead
  626. of "1997". (Year numbers below 100 are incremented by 1900.)
  627.  
  628. Note that leading zeros are ignored for all numeric values
  629. (= contiguous strings of digits).
  630.  
  631. If the month given in the input string isn't numeric, any number of
  632. non-alphanumeric characters (i.e., all characters NOT in [A-Za-z0-9])
  633. may precede and follow the month, and any number of non-digits (i.e.,
  634. all characters NOT in [0-9]) may precede and follow the year.
  635.  
  636. If separating non-digits between the day and year are missing, the
  637. string of digits following the month is automatically mapped to the
  638. day and year depending on its length, as intuitively as possible, as
  639. follows:
  640.  
  641.         Length:        Mapping:
  642.           2              dy
  643.           3              dyy
  644.           4              ddyy
  645.           5              dyyyy
  646.           6              ddyyyy
  647.  
  648. If the month given in the input string is numeric, any number of
  649. non-digits may precede the month, separate the month from the day
  650. and the day from the year, and follow the year.
  651.  
  652. If separating non-digits are missing, the string of digits contained
  653. in the input string is automatically mapped to the month, day and year
  654. depending on its length, as intuitively as possible, as follows:
  655.  
  656.         Length:        Mapping:
  657.           3              mdy
  658.           4              mdyy
  659.           5              mddyy
  660.           6              mmddyy
  661.           7              mddyyyy
  662.           8              mmddyyyy
  663.  
  664. Example:
  665.  
  666. All the following strings will be recognized as "January 3rd 1964":
  667.  
  668.               1 3 64
  669.               1.3.64
  670.              01.03.64
  671.              01/03/64
  672.             Jan 3 1964
  673.          January 3rd, 1964
  674.             Jan 3. '64
  675.              Jan-3-64
  676.              Jan3.1964
  677.                ja364
  678.                1364
  679.  
  680. If no valid date can be derived from the input string, the function
  681. returns an empty list.
  682.  
  683. =item *
  684.  
  685. C<($year,$mm,$dd) = decode_date_eu($date);>
  686.  
  687. Using this function, you can parse dates in almost any format,
  688. provided the date is given as "day - month - year".
  689.  
  690. (To decode dates in U.S. american format, i.e., dates given
  691. as "month - day - year", see the function "decode_date_us()"
  692. in this module.)
  693.  
  694. The day and the year must be given as numbers, the month may be
  695. specified either by a number or its name in English (however,
  696. only up to the 3 first characters are compared, any extra
  697. characters are ignored). The latter comparison is carried out
  698. in a case-insensitive manner.
  699.  
  700. If they uniquely identify the month, one or two letters are
  701. sufficient (e.g., "s" for september or "ja" for january).
  702.  
  703. The year may be abbreviated as well, for instance "97" instead
  704. of "1997". (Year numbers below 100 are incremented by 1900.)
  705.  
  706. Note that this function is a little more flexible than the function
  707. "decode_date()" in the "Date::DateCalc" module since it allows any
  708. number of leading zeros for numeric values and any number of letters
  709. for the name of the month.
  710.  
  711. If the month given in the input string isn't numeric, any number of
  712. non-alphanumeric characters (i.e., all characters NOT in [A-Za-z0-9])
  713. may precede and follow the month (separating it from the day and the
  714. year), and any number of non-digits (i.e., all characters NOT in [0-9])
  715. may precede the day and follow the year.
  716.  
  717. If the month given in the input string is numeric, any number of
  718. non-digits may precede the day, separate the day from the month
  719. and the month from the year, and follow the year.
  720.  
  721. In the latter case, if separating non-digits are missing, the string
  722. of digits contained in the input string is automatically mapped to the
  723. day, month and year depending on its length, as intuitively as possible,
  724. as follows:
  725.  
  726.         Length:        Mapping:
  727.           3              dmy
  728.           4              dmyy
  729.           5              dmmyy
  730.           6              ddmmyy
  731.           7              dmmyyyy
  732.           8              ddmmyyyy
  733.  
  734. Example:
  735.  
  736. All the following strings will be recognized as "January 3rd 1964":
  737.  
  738.               3.1.64
  739.               3 1 64
  740.              03.01.64
  741.              03/01/64
  742.             3. Jan 1964
  743.           3 January 1964
  744.             3. Jan '64
  745.              03-Jan-64
  746.              3.Jan1964
  747.               3Jan64
  748.                3ja64
  749.                3164
  750.  
  751. If no valid date can be derived from the input string, the function
  752. returns an empty list.
  753.  
  754. =item *
  755.  
  756. C<($year,$mm,$dd) = year_month_day_offset($year,$mm,$dd,$y_offs,$m_offs,$d_offs);>
  757.  
  758. Many people have asked for a function to calculate a new date, starting
  759. with a given date and a year, month and/or day offset. So here it is!
  760.  
  761. Note that all parameters must be integers.
  762.  
  763. The function ensures this by applying the "int()" function to every
  764. parameter.
  765.  
  766. An empty list is returned if the given date or any (intermediate or
  767. final) result is invalid.
  768.  
  769. Note that the day offset is added first using the "calc_new_date()"
  770. function of the "Date::DateCalc" module (see L<Date::DateCalc(3)>).
  771.  
  772. Beware that an empty list is returned if this intermediate result
  773. is not a valid date!
  774.  
  775. After this, the month offset is added and finally the year offset
  776. (with a possible carry over from the month) is added.
  777.  
  778. Note that all three offsets may have any (integer) value (provided
  779. that all (intermediate or final) results are valid dates) and any
  780. sign (independently from each other!).
  781.  
  782. If the final result happens to be the 29th of February in a non-leap
  783. year, it is substituted by the 1st of March.
  784.  
  785. BEWARE that because the three offsets are always applied in the
  786. same order, and also because of the substitution mentioned above,
  787. the transformation calculated by this function is NOT REVERSIBLE,
  788. in general!
  789.  
  790. (Unlike the "calc_new_date()" function of the "Date::DateCalc" module!)
  791.  
  792. I.e.,
  793.  
  794.     ($year,$mm,$dd) =
  795.     year_month_day_offset(
  796.     year_month_day_offset($year,$mm,$dd, $y_offs,$m_offs,$d_offs),
  797.     -$y_offs,-$m_offs,-$d_offs);
  798.  
  799. will not, in general, return the original date!
  800.  
  801. In the formula above, in order to reverse the effect of the first call
  802. to "year_month_day_offset()", the offsets do not only need to have the
  803. opposite sign, but they would also need to be applied in reverse order
  804. in the second call to "year_month_day_offset()"!
  805.  
  806. =item *
  807.  
  808. C<($year,$mm,$dd) = parse_date($date);>
  809.  
  810. This function is a (special!) relative of the "decode_date_us()" and
  811. "decode_date_eu()" function.
  812.  
  813. In contrast to the "decode_date_us()" and "decode_date_eu()" function,
  814. however, the month is required to be a three-letter abbreviation of
  815. the month's name (in English).
  816.  
  817. Moreover, the month's name is required to be followed by the day's number,
  818. separated by whitespace.
  819.  
  820. Another restriction is that year numbers must lie in the range 1900 to 2099.
  821.  
  822. In compensation, the year number may come before or after the month/day
  823. pair.
  824.  
  825. This function is especially designed to parse dates returned by the UNIX
  826. "date" command:
  827.  
  828. =back
  829.  
  830. =over 4
  831.  
  832. =item
  833.  
  834. C<-   >Parse today's date:
  835.  
  836.     ($year,$mm,$dd) = parse_date(`/bin/date`);
  837.  
  838. =item
  839.  
  840. C<-   >Parse date of submission of an e-mail:
  841.  
  842.     while (<MAIL>)
  843.     {
  844.         if (/^From \S/)
  845.         {
  846.             ($year,$mm,$dd) = parse_date($_);
  847.             ...
  848.         }
  849.         ...
  850.     }
  851.  
  852. =item
  853.  
  854. The function returns an empty list if it can't extract a valid date
  855. from the input string.
  856.  
  857. =back
  858.  
  859. =over 4
  860.  
  861. =item *
  862.  
  863. C<($year,$mm,$dd) = easter_sunday($year);>
  864.  
  865. Calculates the date of easter sunday for years in the range 1583 to 2299
  866. using Gauss' Rule.
  867.  
  868. Returns an empty list for all arguments outside this range.
  869.  
  870. Other christian feast days depend on easter sunday and can be calculated
  871. using the function "calc_new_date()" of the "Date::DateCalc" module (see
  872. L<Date::DateCalc(3)> for more info) as follows:
  873.  
  874. =back
  875.  
  876. =over 4
  877.  
  878. =item
  879.  
  880. C<*   >Easter Sunday - 48
  881.  
  882.     ($year,$mm,$dd) = calc_new_date(easter_sunday($year),-48);
  883.  
  884.     Carnival Monday / Rosenmontag / Veille du Mardi Gras
  885.  
  886. =item
  887.  
  888. C<*   >Easter Sunday - 47
  889.  
  890.     ($year,$mm,$dd) = calc_new_date(easter_sunday($year),-47);
  891.  
  892.     Mardi Gras / Faschingsdienstag, Karnevalsdienstag / Mardi Gras
  893.  
  894. =item
  895.  
  896. C<*   >Easter Sunday - 46
  897.  
  898.     ($year,$mm,$dd) = calc_new_date(easter_sunday($year),-46);
  899.  
  900.     Ash Wednesday / Aschermittwoch / Mercredi des Cendres
  901.  
  902. =item
  903.  
  904. C<*   >Easter Sunday - 7
  905.  
  906.     ($year,$mm,$dd) = calc_new_date(easter_sunday($year),-7);
  907.  
  908.     Palm Sunday / Palmsonntag / Dimanche des Rameaux
  909.  
  910. =item
  911.  
  912. C<*   >Easter Sunday - 2
  913.  
  914.     ($year,$mm,$dd) = calc_new_date(easter_sunday($year),-2);
  915.  
  916.     Easter Friday / Karfreitag / Vendredi Saint
  917.  
  918. =item
  919.  
  920. C<*   >Easter Sunday - 1
  921.  
  922.     ($year,$mm,$dd) = calc_new_date(easter_sunday($year),-1);
  923.  
  924.     Easter Saturday / Ostersamstag / Samedi de Paques
  925.  
  926. =item
  927.  
  928. C<*   >Easter Sunday + 1
  929.  
  930.     ($year,$mm,$dd) = calc_new_date(easter_sunday($year),1);
  931.  
  932.     Easter Monday / Ostermontag / Lundi de Paques
  933.  
  934. =item
  935.  
  936. C<*   >Easter Sunday + 39
  937.  
  938.     ($year,$mm,$dd) = calc_new_date(easter_sunday($year),39);
  939.  
  940.     Ascension of Christ / Christi Himmelfahrt / Ascension
  941.  
  942. =item
  943.  
  944. C<*   >Easter Sunday + 49
  945.  
  946.     ($year,$mm,$dd) = calc_new_date(easter_sunday($year),49);
  947.  
  948.     Whitsunday / Pfingstsonntag / Dimanche de Pentecote
  949.  
  950. =item
  951.  
  952. C<*   >Easter Sunday + 50
  953.  
  954.     ($year,$mm,$dd) = calc_new_date(easter_sunday($year),50);
  955.  
  956.     Whitmonday / Pfingstmontag / Lundi de Pentecote
  957.  
  958. =item
  959.  
  960. C<*   >Easter Sunday + 60
  961.  
  962.     ($year,$mm,$dd) = calc_new_date(easter_sunday($year),60);
  963.  
  964.     Feast of Corpus Christi / Fronleichnam / Fete-Dieu
  965.  
  966. =back
  967.  
  968. =over 4
  969.  
  970. =item
  971.  
  972. For more information about easter sunday and how to calculate it,
  973. see also on USENET in news.answers
  974.  
  975.     Calendar FAQ, v. 1.6 (modified 26 Dec 1996) Part 1/3
  976.     Calendar FAQ, v. 1.6 (modified 26 Dec 1996) Part 2/3
  977.     Calendar FAQ, v. 1.6 (modified 26 Dec 1996) Part 3/3
  978.  
  979. or
  980.  
  981.     http://www.math.uio.no/faq/calendars/faq.html
  982.  
  983. or
  984.  
  985.     http://www.pip.dknet.dk/~pip10160/calendar.html
  986.  
  987. All authored by
  988.  
  989.     Claus Tondering <c-t@pip.dknet.dk>
  990.  
  991. =back
  992.  
  993. =over 4
  994.  
  995. =item *
  996.  
  997. C<$string = calendar($year,$month);>
  998.  
  999. This function returns a string containing a calendar for the given
  1000. month and year (which looks pretty much like the output of the UNIX
  1001. "cal" command).
  1002.  
  1003. The calendar is not printed directly but rather returned as a string
  1004. in order to make post-processing possible, i.e., like staggering multiple
  1005. month calendars together on one page to produce a calendar of a complete
  1006. year, or transforming the day numbers into hyperlinks for incorporation
  1007. of the calendar (with clickable day numbers) into an HTML page.
  1008.  
  1009. The function returns an empty list if the given month or year is invalid.
  1010.  
  1011. =back
  1012.  
  1013. =head1 SEE ALSO
  1014.  
  1015. Date::DateCalc(3).
  1016.  
  1017. =head1 VERSION
  1018.  
  1019. This man page documents "Date::DateCalcLib" version 3.2.
  1020.  
  1021. =head1 AUTHOR
  1022.  
  1023. Steffen Beyer <sb@sdm.de>.
  1024.  
  1025. =head1 COPYRIGHT
  1026.  
  1027. Copyright (c) 1997 by Steffen Beyer. All rights reserved.
  1028.  
  1029. =head1 LICENSE
  1030.  
  1031. This package is free software; you can redistribute it
  1032. and/or modify it under the same terms as Perl itself.
  1033.  
  1034.