Sponsoring website: Emergency Boot Kit



Is that Script Y2k Compatible?
and
All about Time and Date Functions in Perl


      If you're seeing 100's where you previously had a two-digit year, then your script definitely has a "y2k problem."   The first thing you should do is search for any lines containing either "localtime" or "gmtime" which are almost always part of these array statements (often found in subroutines dealing with dates or times):

($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
				or
  ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime(time);
Note the occurrences of the sixth element, "$year" elsewhere in your script!   Many script authors used "$year" without any further logic as being equivalent to a two-digit representation of the year. They took advantage of the fact that the results were conveniently the same for every year between 1900 and 1999. But we're no longer living in the 20th century!  For the next nine years, you can have the correct two-digit year by adding the following correction somewhere after the array statements for "localtime" or "gmtime" (as shown above) and before "$year" is used as a two-digit year in your program:
       $ydif = $year - 100;
       $year = "0$ydif";
      If you require a more extensive correction (one that outputs the correct digits for years previous to 2000 and after 2009), then please send me an email.


An alternative for displaying the present date with a two-digit year is to use the POSIX module's strftime function. Here's an example:
which would produce a display similar to this: Thu, 17 Feb 00.


The following material is either taken directly from the Perl Documentation (as noted) or based upon it, and should be quite helpful in dealing with all time and date function problems in general:

From PerlFAQ 4:
-----------------

 Does Perl have a year 2000 problem?  Is Perl Y2K compliant?

    Short answer: No, Perl does not have a Year 2000 problem. Yes,
    Perl is Y2K compliant (whatever that means).  The programmers
    you've hired to use it, however, probably are not.

    Long answer: The question belies a true understanding of the
    issue. Perl is just as Y2K compliant as your pencil--no more,
    and no less.  Can you use your pencil to write a non-Y2K-
    compliant memo? Of course you can.  Is that the pencil's
    fault?  Of course it isn't.

    The date and time functions supplied with perl (gmtime and
    localtime) supply adequate information to determine the year
    well beyond 2000 (it won't be until 2038 that trouble strikes
    for 32-bit machines). The year returned by these functions
    when used in an array context is the year minus 1900. For
    years between 1910 and 1999 this *happens* to be a 2-digit
    decimal number. To avoid the year 2000 problem simply do not
    treat the year as a 2-digit number. It isn't.

    When gmtime() and localtime() are used in scalar context they
    return a timestamp string that contains a fully-expanded year.
    For example, `$timestamp = gmtime(1005613200)' sets
    $timestamp to "Tue Nov 13 01:00:00 2001".  There's no year
    2000 problem here.

    That doesn't mean that Perl can't be used to create non-Y2K
    compliant programs.  It can.  But so can your pencil.  It's
    the fault of the user, not the language.

 ---------------------------------------------------------------

 Data: Dates

  How do I find the week-of-the-year/day-of-the-year?

    The day of the year is in the array returned by localtime():

        $day_of_year = (localtime(time()))[7];

    or more legibly (in perl version 5.004 or higher):

        use Time::localtime;
        $day_of_year = localtime(time())->yday;

    The Date::Calc module from CPAN has a lot of date calculation
    functions, including day of the year, week of the year, and so
    on. Note that not all businesses consider ``week 1'' to be the
    same; for example, American businesses often consider the first
    week with a Monday in it to be Work Week #1, despite ISO 8601,
    which considers WW1 to be the first week with a Thursday in it.

  How can I compare two dates and find the difference?

        If you're storing your dates as epoch seconds then simply
    subtract one from the other.  If you've got a structured date
    (distinct year, day, month, hour, minute, second values) then
    use one of the Date::Manip and  Date::Calc modules from CPAN.

  How can I take a string and turn it into epoch seconds?

    If it's a regular enough string that it always has the same
    format, you can split it up and pass the parts to `timelocal' in
    the standard Time::Local module. Otherwise, you should look into
    the Date::Calc and Date::Manip modules from CPAN.

  How can I find the Julian Day?

    Neither Date::Manip nor Date::Calc deal with Julian days.
    Instead, there is an example of Julian date calculation that
    should help you in Time::JulianDay (part of the Time-modules
    bundle) which can be found at:
    http://www.perl.com/CPAN/modules/by-module/Time/.

  How do I find yesterday's date?

    The `time()' function returns the current time in seconds since
    the epoch. Take one day off that:

        $yesterday = time() - ( 24 * 60 * 60 );

    Then you can pass this to `localtime()' and get the individual
    year, month, day, hour, minute, seconds values.

From Perlfunc.pod or the POSIX.pod:
--------------------------------------
 
 time
       Returns the number of non-leap seconds since whatever time
       the system considers to be the epoch (that's 00:00:00,
       January 1, 1904 for MacOS, and 00:00:00 UTC, January 1,
       1970 for most other systems). Suitable for feeding to
       `gmtime()' and `localtime()'.
      
 ------------------
 
 localtime EXPR
      Converts a time as returned by the time function to a
      9-element array with the time analyzed for the local
      time zone.  Typically used as follows:

      #  0    1    2     3     4    5     6     7     8
      ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
                                                 localtime(time);

      All array elements are numeric, and come straight out of
      a struct tm. In particular this means that `$mon' has the
      range `0..11' and `$wday' has the range `0..6' with Sunday
      as day `0'.  Also, `$year' is the number of years since
      1900, that is, `$year' is `123' in year 2023, and *not*
      simply the last two digits of the year.  If you assume it
      is, then you create non-Y2K-compliant programs--and you
      wouldn't want to do that, would you?
	 
      If EXPR is omitted, the function uses the current time
      (`localtime(time)').

      In a scalar context, localtime returns the ctime(3) value.
      For example, printing out the scalar variable $now from
      $now = localtime; has the form: "Wed Oct 12 14:54:34 1999"
      You can also print it out by using a statement like this:
      print "\n\n The time is: ",scalar(localtime),"\n";

      This scalar value is a Perl builtin, not locale dependent;
      see the perllocale manpage. Read about the `Time::Local'
      module, and the strftime(3) and mktime(3) functions which
      are available via the POSIX module. To get somewhat similar
      but locale dependent date strings, set up your locale
      environment variables appropriately (please see the
      perllocale manpage) and try for example:

      use POSIX qw(strftime);
      $now_string = strftime("%a %b %d %H:%M:%S %Y", localtime);
      print "\n\n Date/Time are now: $now_string";

      The output should be similar to: 
       Date/Time are now: Thu Feb 17 11:42:07 2000.

      The parentheses, ( ), after strftime above are optional.
      Note that the `%a' and `%b', the "short forms" for the day
      of the week and the month of the year, may not necessarily
      be three characters wide. (Also, the original documentation
      incorrectly had an "%e" instead of the "%d" shown above.)
       
 ------------------
 
 gmtime EXPR
         Converts a time as returned by the time function to a
         9-element array with the time localized for the standard
         Greenwich time zone. Typically used as follows:

         #  0    1    2     3     4    5     6     7     8
         ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
                                                     gmtime(time);

       [ Same comments follow as found in "localtime EXPR" above! ]

 ------------------

 NAME
    Time::Local - efficiently compute time from local and GMT time

 SYNOPSIS
        $time = timelocal($sec,$min,$hours,$mday,$mon,$year);
        $time = timegm($sec,$min,$hours,$mday,$mon,$year);

 DESCRIPTION
    These routines are quite efficient and yet are always guaranteed
    to agree with localtime() and gmtime(), the most notable points
    being that year is year-1900 and month is 0..11. We manage this
    by caching the start times of any months we've seen before. If
    we know the start time of the month, we can always calculate any
    time within the month. The start times themselves are guessed by
    successive approximation starting at the current time, since
    most dates seen in practice are close to the current date.
    Unlike algorithms that do a binary search (calling gmtime once
    for each bit of the time value, resulting in 32 calls), this
    algorithm calls it at most 6 times, and usually only once or
    twice. If you hit the month cache, of course, it doesn't call it
    at all.

    timelocal is implemented using the same cache. We just assume
    that we're translating a GMT time, and then fudge it when we're
    done for the timezone and daylight savings arguments. The
    timezone is determined by examining the result of localtime(0)
    when the package is initialized. The daylight savings offset is
    currently assumed to be one hour.

    Both routines return -1 if the integer limit is hit. I.e., for
    dates after the 1st of January, 2038 on most machines.

    Note: Use the variable name $hour not $hours (as given in the
    original documentation) in order to be consistent with the 
    variable name $hour in the localtime() and gmtime() functions.

 -------------------
 NAME
    Time::localtime - by-name interface to Perl's built-in
    localtime() function

 SYNOPSIS
     use Time::localtime;
     printf "Year is %d\n", localtime->year() + 1900;

     $now = ctime();   or try this at the Command-Line prompt:
     C:\Perl\bin>perl -e "use Time::localtime; print scalar(ctime());"
     which displayed: Thu Feb 17 14:06:00 2000 for me.

     use Time::localtime;
     use File::stat;
     [ $file = "drive:\\pathway\\anyvalidfilename"; ]  or for example:
     $file = "C:/pathway/test.pl"; and then I used
     $date_string = ctime(stat($file)->mtime); and
     print "$file was last modified at: $date_string";   to display:
     test.pl was last modified at: Thu Jan 27 08:47:36 2000

 DESCRIPTION
    This module's default exports override the core localtime()
    function, replacing it with a version that returns "Time::tm"
    objects. This object has methods that return the similarly named
    structure field name from the C's tm structure from time.h;
    namely sec, min, hour, mday, mon, year, wday, yday, and isdst.

    You may also import all the structure fields directly into your
    namespace as regular variables using the :FIELDS import tag.
    (Note that this still overrides your core functions.) Access
    these fields as variables named with a preceding `tm_' in front
    [of] their method names. Thus, `$tm_obj->mday()' corresponds to
    $tm_mday if you import the fields.

    The ctime() function provides a way of getting at the scalar
    sense of the original CORE::localtime() function.

    To access this functionality without the core overrides, pass
    the `use' an empty import list, and then access function[s]
    with their full[y] qualified names.  On the other hand, the 
    built-ins are still available via the `CORE::' pseudo-package.

 NOTE
    While this class is currently implemented using the Class::Struct
    module to build a struct-like class, you shouldn't rely upon this.


 -------------------

 NAME
    POSIX - Perl interface to IEEE Std 1003.1
                [ Note: This is just a fraction of the Perl
                        Documentation on POSIX functions! ]
 SYNOPSIS
        use POSIX;
        use POSIX qw(setsid);

 DESCRIPTION    [ Merely a brief summary here before describing
                  some of the POSIX time/date functions! ]

    The POSIX module permits you to access all (or nearly all) the
    standard POSIX 1003.1 identifiers. Many of these identifiers
    have been given Perl-ish interfaces. All functions are only
    exported if you ask for them explicitly.  Most likely people
    will prefer to use the fully-qualified function names.


 ctime   This is identical to the C function `ctime()'.


 mktime  Convert date/time info to a calendar time.

   Synopsis:

     mktime(sec, min, hour, mday, mon, year, wday=0, yday=0, isdst=0)

     The month (`mon'), weekday (`wday'), and yearday (`yday') begin
     at zero.  I.e., January is 0, not 1; Sunday is 0, not 1; January
     1st is 0, not 1. The year (`year') is given in years since 1900.
     I.e., The year 1995 is 95, but the year 2001 is 101.  Consult
     your system's `mktime()' manpage for details about these and the
     other arguments.  Use this before calling strftime in a program.

     Returns `undef' on failure.

     Calendar time for December 23, 1999, at 10:30AM may be found
     using:
     use POSIX qw(mktime);
     $time_t = mktime ( 0, 30, 10, 23, 11, 99 );   and 
     print "\n\n \$time_t = $time_t \n"; which will display:
      $time_t = 945973800 on your screen.

     The process can then be reversed to find the weekday too using:
     print "\n\n Date = ", POSIX::ctime($time_t),"\n";   which displays:
      Date = Thu Dec 23 10:30:00 1999

     If you try using this line at the Command prompt:
     C:\>perl -e "use POSIX; print scalar(POSIX::mktime(0,0,0,1,0,100));"
     you'll find that the beginning of the new year 2000 was at time:
     C:\>946713600 or Sat Jan 01 00:00:00 2000


 strftime   Convert date and time information to string.
            Returns the string.

   Synopsis:

     strftime(format, sec, min, hour, mday, mon, year, wday = -1,
                                                yday = -1, isdst = -1)

     The month (`mon'), weekday (`wday'), and yearday (`yday') begin
     at zero.  I.e., January is 0, not 1; Sunday is 0, not 1; January
     1st is 0, not 1. The year (`year') is given in years since 1900.
     I.e., the year 1995 is 95; the year 2001 is 101.  Consult your
     system's `strftime()' manpage for details about these and other
     arguments.  The given arguments are made consistent by calling
     `mktime()' before calling your system's `strftime()' function.

     Most of the time you can exclude the elements with a "-1" even
     if you wish to display the day of the week; both strftime and
     mktime() will calculate that for you given the day of the month,
     the month and the year.  We must, however, include some kind of
     data for the first three elements (sec, min, hour) even though
     you may not be displaying the time (just use zeros in this case).
     format may include either A or a, B or b, d, Y or y, H, M or S;
     (the time normally being displayed as %H:%M:%S) in any order or
     combination.  For example:

     use POSIX;
     $str = POSIX::strftime("%A, %B %d, %Y", 0, 0, 0, 12, 2, 101);
     print " $str\n";     will display:
      Monday, March 12, 2001




Here's a link to a humorous must read page about Y2K compliance:
http://language.perl.com/news/y2k.html


 

Please USE Your Browser's BACK BUTTON . . . . . or

Go Back to The Starman's Perl Pages