This and other RFCs are available on the web at
  http://dev.perl.org/rfc/

=head1 TITLE 

Replace localtime() and gmtime() with date() and gmtdate()

=head1 VERSION

   Maintainer: Nathan Wiger <[EMAIL PROTECTED]>
   Date: 05 Aug 2000
   Last-Modified: 11 Aug 2000
   Version: 2
   Status: Developing
   Mailing List: [EMAIL PROTECTED]
   Number: 48

=head1 ABSTRACT

Currently, Perl uses the C library C<localtime()> and C<gmtime()>
functions for date access. However, because of many problems, these
should be replaced with two new functions, C<date()> and
C<gmtdate()> that will be called as follows:

   $object  =  date;     # object with accessor functions (new)
   print "$object";      # scalar ctime date, same as current
   @array   =  date;     # array of date/time values (new order)
   %hash    =  date;     # hash of date/time values (new)

The new C<date()> function will return time adjusted for the local
timezone. The C<gmtdate()> function will return time in GMT. In a scalar
context, an object is always returned. This object is then converted to
a string on-demand via RFC 49.

=head1 DESCRIPTION

=head2 Overview

In the past, Perl has provided access to date and time information
through the C library C<localtime()> and C<gmtime()> functions.
Unfortunately, these functions have several "really bad things" about
them:

   1. some values are 0-indexed while others are 1-indexed
   2. they return massive lists as their only interface
   3. minute and second values aren't 0-padded
   4. the year has to have 1900 added to it to be correct.

While some of these are perhaps understandable, that last one just plain
doesn't make I<any> sense.

With Perl 6 we have the chance to fix this. While some have suggested
merely changing what C<localtime()> and C<gmtime()> return, this is a
bad idea because:

   1. Many Perl scripts already use it
   2. Many C programmers are familiar with its stupidity

As such, we should replace these functions with versions that work the
way that we want them to. The new names will indicate that these are
"not the same old time functions", and that you'd better read the docs.

=head2 Proposed Syntax

The new functions would have several different, highly-flexible calling
forms. The functions were split up because:

   $date = gmtdate;

Is much clearer than, say, something like this:

   $date = date undef, undef, 1;   # what's the 1 do?

However, this point is still open for debate. Since the only difference
is the timezone returned, from here on down I'll use C<date()> to refer
to both new functions.

The new syntax of C<date()> is proposed as:

   $|@|%return  =  date [ $time ], [ $format ];

If C<$time> is not specified, then the current return value from
C<time()> is used (just like C<localtime()>).

The optional C<$format> affects the format of the date returned. By
default, a ctime-formatted string is used, like C<localtime>.
Actually, what it does is call the object function C<setformat()>
with the format, which in turn determines what calls to the C<date()>
object member function look like. See below.

The C<$format> specifier is the same one used in C<POSIX strftime()>,
allowing complete date formatting with having to import the C<POSIX>
module.

Depending on the context within which C<date()> is called, many
different things are returned:

   # Get some various local date stuff
   $object  =  date;            # scalar ctime date, same as now
   $object  =  date time, '%m/%d/%Y';  # scalar date per format
   $object  =  date $time;      # relative to time $time
   print "$object";             # scalar date string per format   

   @array   =  date;            # array of date/time values
   %hash    =  date;            # hash of values

   # Access GMT information
   $object  =  gmtdate time, '%H:%M'; # return time in GMT

=head2 Return Values

The return values are dependent on the context within which C<date()> is
called. For all contexts, the following are the values and their ranges:

   $hour  =  0 .. 24  
   $min   =  00 .. 59   # 0-padded
   $sec   =  00 .. 59   # 0-padded
   $fsec  =  0 .. 1     # fractional seconds per hw clock

   $mon   =  1 .. 12    # hooray!
   $mday  =  1 .. 31 
   $year  =  1 .. 9999  # 4-digit! 

   $wday  =  1 .. 7     # 1 == Sunday, 7 == Saturday
   $yday  =  1 .. 366

   $isdst =  1 or undef;  # daylight savings?
   $isgmt =  1 or undef;  # is GMT?
   $tz    =  [depends on your system, this "eats people"]

I'm still a little uneasy about C<$wday> starting with 1 == Sunday, just
because Monday seems like the first day of the week to me. But I'm not
the one writing the calendars, and it seems silly to only have one value
that's 0-indexed. Oh, well. :-)

=head3 STRING Context

In a C<STRING> (not scalar) context, a single ctime-formatted date
string is returned, consistent with the current usage of C<localtime()>.
Unless the optional C<$format> is included, in which case the format of
this string is changed accordingly.

In order to emulate a string, a call is made to the date object's
builtin C<STRING> function, which prints out a date string. See below
for details.

=head3 LIST Context

A list of date/time values is returned. The ordering and format of these
values has been radically changed to reflect what most of us probably
view as "ordinary":

   ($year, $mon, $mday, $hour, $min, $sec, $fsec,
    $wday, $yday, $isdst, $isgmt, $tz) = date;

This ordering follows the predictable pattern of being in increasing
granularity and so should be easy to remember. Just think of a
computer-esque timestamp:

   2000/11/4 12:03:09

Note that the month, day, and year are not 0-padded. If you want a
padded date, perhaps as a file backup suffix, you'll have to say:

   $backup_suffix = date time, '%Y%m%d%H%M%S';

Which would return something like "20001104120309" (actually, it would
return an object with the appropriate default format so that, when
stringified, it would yield the above result).

=head3 HASH Context

A hash of all the above values is returned. These are named the same as
the variables above. So,

   %date = date;

Would return a hash with these values (assuming the same date shown
above):

   $date{year} = 2000;
   $date{mon}  = 11;      # also $date{month}
   $date{mday} = 4;       # also $date{day}
   $date{hour} = 12;
   $date{min}  = 03;      # also $date{minutes}    
   $date{sec}  = 09;      # also $date{seconds}
   $date{fsec} = 0.429107412089712;   # up to hw resolution
   $date{wday} = 2;       # also $date{weekday}
   $date{yday} = 331;     # also $date{yearday}
   $date{isdst}= undef;
   $date{isgmt}= undef;
   $date{tz}   = 'PST';   # or maybe 'US/Pacific', or ...

=head3 SCALAR Context

In an C<SCALAR> context, an object is returned. This is somewhat adapted
from C<Time::Object> and Larry's own comments, but with several key
differences. The ones noted with ** are incompatible with
C<Time::Object>.

   $t = date;            # create date object

   "$t"                  # calls $t->STRING, same as $t->date
   $t->year
   $t->mon               # also available as $t->month **
   $t->mday              # also available as $t->day **
   $t->hour
   $t->min               # also available as $t->minutes **
   $t->sec               # also available as $t->seconds **
   $t->fsec              # fractional seconds
   $t->fsecres           # fsec resolution (num of digits for hw)
   $t->wday              # also available as $t->weekday
   $t->yday              # also available as $t->yearday
   $t->isdst
   $t->isgmt
   $t->tz                # timezone (also $t->timezone)
   $t->tzoffset          # timezone offset in seconds ($t->tzsec?)
   $t->time              # number of seconds since the epoch, so it
                         # contains what time() was when you called
                         # date() 

These functions are object-specific:

   $t->date              # Tue Feb 29 01:23:45 2000 (depending on 
                         # default format set by $t->setformat)
   $t->date(FORMAT)      # Return a temporarily-modified date,
                         # without affecting the default format.
   $t->setformat(FORMAT) # Set default format which determines what
                         # calls to $t->date (stringified $t) look like
                         # This is called on object creation

These functions are separate for an important reason:

   print $t->date('%H:%M');    # prints out hours and minutes
   print "$t";                 # without touching default format

   print $t->setformat('%Y');  # prints out year  (undef instead?)
   print "$t";                 # but now so does this

The C<set> prefix was explicitly added to make it obvious this sets
something (rather than just formatting the date like strftime). In fact,
we may want to make it so setformat returns undef just so it's not
misused.

Many functions were deemed of dubious quality/excessive bloat and were
all removed from the RFC. Note that you can get to any extra data by
calling $t->date with the correct format. So,

   print $t->date('%y');

Will give you the two-digit year.

=head2 Date Arithmetic

Date arithmetic has been axed from this proposal. Before you get too
upset, I had discussions with several people and became convinced that
this is something too difficult and bloated to stick in core. An
external module would be much better suited to this. We can still make
sure this is included with the core distribution.

=head1 IMPLEMENTATION

Slash and burn C<localtime()> and C<gmtime()>. Actually, we should
probably move them to C<Time::Local> or some other place and keep them
available, since some people like pain.

Nonetheless, C<localtime()> and C<gmtime()> SHOULD BE REMOVED FROM CORE
and placed in a module. Perl 6 should support ONE date/time
specification natively.

Extensive date calculations, including reverse date calculations, should
be left to an external module.

The 'mday' and 'mon' fields should be renamed 'day' and 'month', in my
opinion, rather than simply adding duplicate names for this information.

=head1 CHANGES

   1. Removed custom timezone determination. Sorry, better
      for a module.
   2. Split C<date> into C<date> and C<gmtdate> to mirror
      current functions.
   3. Removed many extraneous functions from object.
   4. Changed C<$obj->date> method to accept a C<FORMAT>.
   5. Added provisions for use of C<$obj->STRING> to change
      date object into string on-demand.
   6. Added fractional seconds (fsec).
   7. Changed return order in LIST context
   8. Reverted to GMT from UTC since most systems are internally
      maintained in GMT, not UTC.
   9. Axed date arithmetic

=head1 REFERENCES

Matt Sergeant's great Time::Object CPAN module

Larry Wall's post of 8 Jan 2000 on deprecating localtime:
http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2000-01/msg00241.html

RFC 49: Objects should have builtin stringifying STRING method 

=head1 ACKNOWLEDGEMENTS

Jonathan Scott Duff, Tim Jenness, Johan Vromans, and perl6-language for
great feedback.

Russ Allbery and John Tobey for suggesting parts to slice-and-dice.


Reply via email to