Author: autarch
Date: 2009-02-19 19:14:48 +0100 (Thu, 19 Feb 2009)
New Revision: 25445
Modified:
docs/Perl6/Spec/S32-setting-library/Temporal.pod
Log:
This is a very drastic revision (hopefully this won't turn into a revert war ;)
Here's the changes in summary:
removed all references to ...
Locales, including eras, which come from a locale - this is a vast and
complicated domain
Alternate calendars - also vast and complicated
String parsing of any sort - ditto, see the pattern here? ;)
Format specifiers - this could come from locales (CLDR specifies this)
or strftime, but again, it's more complicated than is needed
Comparing dates or times to durations - this just doesn't make
sense. Is 2009-02-23 greater or less than 5 days?
Any sort of date or time math
Added iso8601 output for every role, and made that the
stringification. ISO8601 is unambiguous world-wide, easy to read, and
easy to output.
Renamed Temporal::Instant to Temporal::DateTime
Got rid of Temporal::Subsecond and just made Temporal::Time allow for
sub-second resolutions. Not sure if this is best done with an
$.attosecond attribute or as a decimal number.
Renamed Temporal::Timezone to Temporal::TimeZone::Observance. The
latter is a simple thing which represents the offset, isdst flag, and
short name for a given local time. This information should be
available on all supported platforms. TimeZones themselves are
complicated and very much platform-dependent. Better to leave this as
a separate CPAN6 distro.
Got rid of all mutating operators on everything. The built-ins should
be immutable for simplicity.
Added numification overloading for Temporal::DateTime, which gives us
comparison for free.
Modified: docs/Perl6/Spec/S32-setting-library/Temporal.pod
===================================================================
--- docs/Perl6/Spec/S32-setting-library/Temporal.pod 2009-02-19 17:45:07 UTC
(rev 25444)
+++ docs/Perl6/Spec/S32-setting-library/Temporal.pod 2009-02-19 18:14:48 UTC
(rev 25445)
@@ -15,9 +15,10 @@
Moritz Lenz <[email protected]>
Tim Nelson <[email protected]>
Daniel Ruoso <[email protected]>
+ Dave Rolsky <[email protected]>
Date: 19 Mar 2009 extracted from S29-functions.pod and S16-IO.pod
Last Modified: 19 Feb 2009
- Version: 1
+ Version: 2
The document is a draft.
@@ -31,8 +32,7 @@
=item gmtime
- our Time multi gmtime ( Time $time? )
- our Time multi method gmtime ( Time $time: )
+ our Temporal::DateTime multi gmtime ( Num $epoch? = time() )
Identical to:
@@ -40,179 +40,160 @@
=item localtime
- our Time multi localtime ( Time $time?, Time::Zone $tz? )
- our Time multi method localtime ( Time $time: Time::Zone $tz? )
+ our Temporal::DateTime multi localtime ( Num $epoch? = time() )
-Returns a time object whose default timezone is C<$tz> (or the system's
-default timezone if none is provided).
+These functions take an epoch value and return a C<Temporal::DateTime>
+object. For C<localtime> the time zone is taken from the local
+system. For C<gmtime> the time zone is aways UTC.
-If used as a function, and no time is provided, the current time is used.
+If no time is provided, the current time is used.
-Note that no matter what, C<$time>'s concept of "its timezone" is discarded
-in favor of something new.
-
=item time
- our Time multi time()
+ our Num time()
-Returns a C<Time> object. There are a number of uses for this
-object, all of which can be found in the documentation for C<Time>.
+Returns an epoch value for the current time.
-There is, by default, no timezone associated with this Time object, so
-whatever default the system has will take over if timezone-specific
-data is accessed.
-
=back
=head1 Roles
+The intent behind these classes is to provide an absolutely minimal,
+but still useful, set of core behavior. The assumption is that the
+core will ship with a simple set of classes so that C<gmtime> and
+C<localtime> have something to return.
+
=head2 Temporal::Date
-You probably want to use the Temporal::Instant object instead.
+You probably want to use the Temporal::DateTime object instead.
role Temporal::Date {
- has Int $.year;
- has Int $.month;
- has Int $.day; # Day of month
- has Int $.dayofweek;
- has Int $.era; # BC, AD, etc, depending on locale
- has Str $.defaultformat; # A CLDR-formatted string, for use with
toString();
+ my subset Month of Int where { 1 <= $^a <= 12 };
+ my subset Day of Int where { 1 <= $^a <= 31 };
+ my subset DayOfWeek of Int where { 1 <= $^a <= 7 };
- method toString($format => $.defaultformat);
+ has Int $.year;
+ has Month $.month = 1;
+ has Day $.day = 1;
- multi method Temporal::Instant infix:<+>(Temporal::Date $self,
Temporal::Time $other);
- multi method Temporal::Instant infix:<+>(Temporal::Date $self,
Temporal::Duration $other);
+ # This can be cached internally, but it's a calculated value,
+ # not an attribute.
+ method day-of-week () returns DayOfWeek;
- multi method infix:{'<=>'}(Temporal::Date $self, Temporal::Date $other);
- multi method infix:{'<=>'}(Temporal::Date $self, Temporal::Duration
$other);
-}
+ # These always return the long English names
+ method month-name () returns Str; # "January"
+ method day-name () returns Str; # "Tuesday"
-Example:
+ # returns the date formatted in ISO8601 style - 2008-01-25
+ method iso8601 () returns Str
+ { [ self.year, self.month, self.date ].join('-') };
-$date = new Date('2002/01/01');
-$date.month.name(); # January
-$date.month.name('short'); # Jan
+ method infix:{'~'} return Str { self.iso8601 };
-$format will naturally need to allow for eras.
+ multi method infix:{'<=>'} (Temporal::Date $self, Temporal::Date
$other) {
+ $self.year <=> $other.year
+ ||
+ $self.month <=> $other.month
+ ||
+ $self.day <=> $other.day;
+ }
+}
-=over
+Example:
-=item
+$date = Date.new( :year(2008), :month(1), :day(25) );
+$date.month(); # 1
- method toString($format = 'YYYY/MM/DD');
-
-$format contains things like YYYY/MM/DD or whatever.
-
-=back
-
=head2 Temporal::Time
-You probably want to use the Temporal::Instant object instead.
+You probably want to use the Temporal::DateTime object instead.
role Temporal::Time {
- has $.hour;
- has $.minute;
- has $.second;
+ my subset Hour of Int where { 0 <= $^a <= 23 };
+ my subset Minute of Int where { 0 <= $^a <= 59 };
+ my subset Second of Int where { 0 <= $^a <= 60 };
+ my subset Attosecond of Int where { 0 <= $^a <= 10**18 };
- method toString($format?);
- # This can't be right; how do we specify this
- multi method infix:{'<=>'}(Temporal::Time $self, Temporal::Time $other);
- multi method infix:{'<=>'}(Temporal::Time $self, Temporal::Duration
$other);
-}
+ has Hour $.hour = 0;
+ has Minute $.minute = 0;
+ has Second $.second = 0;
+ # 10^-18 - there's really no point in going any smaller (this
+ # is the smallest unit ever measured), but maybe it's better
+ # to make $.second a floating point value instead?
+ has Attosecond $.attosecond = 0;
-When created, recognises "today" as a possibility.
+ method fractional-second () { self.second / 10**18 }
-role Temporal::Timezone {
- has $.number;
+ method iso8601 () returns Str
+ { [ self.hour, self.minute, self.fractional-second ].join(':') }
- method name($format);
- method is_dst();
-}
+ method Str returns Str { self.iso8601() };
-role Temporal::Subsecond {
- has $.nanosecond;
+ multi method infix:{'<=>'} (Temporal::Time $self, Temporal::Time
$other) {
+ $self.hour <=> $other.hour
+ ||
+ $self.minute <=> $other.minute
+ ||
+ $self.second <=> $other.second
+ ||
+ $self.attosecond <=> $other.attosecond;
+ }
}
-=head1 Classes
+=head2 Temporal::TimeZone::Observance
-=head2 Temporal::Timezone
+role Temporal::TimeZone::Observance {
+ my subset Offset of Int where { -86400 < $^a < 86400 };
-=head2 Temporal::Instant
+ has Offset $.offset;
+ has Bool $.isdst;
+ has Str $.abbreviation; # CST, AST
-class Temporal::Instant
- does Temporal::Date
- does Temporal::Time
- does Temporal::Timezone
- does Temporal::Subsecond
-{
- has $.locale;
- has $.parser;
- has $.formatter; # Only for output formats
+ # The ISO8601 standard does not allow for offsets with
+ # sub-minute resolutions. In real-world practice, this is not
+ # an issue.
+ method iso8601 returns Str {
+ my $hours = self.offset.abs / 3600;
+ my $minutes = self.offset.abs % 3600;
- multi method Temporal::Instant infix:<+>(Temporal::Instant $self,
Duration $other);
+ return self.offset < 0 ?? '-' :: '+'
+ ~ $hours.fmt('%02d')
+ ~ $minutes.truncate.fmt('%02d');
+ }
- multi method infix:<->(Temporal::Instant $self, Duration $other);
- multi method infix:<->(Temporal::Instant $self, Duration $other);
-
- multi method infix:{'<=>'}(Temporal::Instant $self, Temporal::Instant
$other);
- multi method infix:{'<=>'}(Temporal::Instant $self, Duration $other);
-
- method new(:$String);
- method truncate(Str $to);
- method last(Str $type, Str $of);
- method toString($format?);
+ method Str returns Str { self.iso8601 }
}
-All formats are CLDR, although implementations may want to have another set of
functions
-that use the strftime functions instead.
+This is called an I<observance> because it represents the state of a
+time zone for a given instant. A real Temporal::TimeZone role would
+return an observance when given a particular datetime.
-=over
+We don't specify a proper C<Temporal::TimeZone> role because time
+zones are messy and complex. The system libraries are able to give us
+sufficient information to create an observance for a time, but are not
+able to give us proper time zone information.
-=item new
+=head2 Temporal::DateTime
- method new(Str :$String) # parser defaults to 'strptime' or something similar
- | (Str $parser, Str $String) # $parser = 'strptime'
- | (Str $parser, Int $Epoch) # $parser = 'epoch'
- | (Str $parser, Str $Timezone?) # $parser = 'today' [unless strptime
does this]
- ;
+role Temporal::DateTime {
+ has Temporal::Date $!date handles <year month day day-of-week>;
+ has Temporal::Time $!time handles <hour minute second
fractional-second>;
+ has Temporal::TimeZone::Observance $!timezone handles <offset isdst>;
-Tries to parse the date and time specified using $parser.
+ method iso8601 () returns Str
+ { self.date.is8601 ~ 'T' ~ self.time.iso8601 ~
self.timezone.iso8601 }
-If $Epoch is passed in instead, then it interprets the time as being in
seconds since the
-epoch (which is determined on a system-by-system basis).
+ method Str return Str { self.iso8601 }
-If $parser is 'today', then the current time is gotten. Timezone would be
useful for
-simulating eg. gmtime().
+ # This involves a whole bunch of code - see Perl 5's
+ # Time::Local
+ method epoch returns Num { ... }
-=item truncate
+ method Int returns Int { self.epoch.truncate }
-Can be used to truncate a function to the current day, or whatever.
-
-=item last
-
- $date.last('day', of => 'month');
-
-=back
-
-=head2 Temporal::Duration
-
-class Temporal::Duration
- does Temporal::Date
- does Temporal::Time
- does Temporal::Subsecond
-{
+ method Num returns Num { self.epoch }
}
-=head2 Temporal::Recurring
-
-This class specifies when a repetitive action (eg. a cron job) happens.
-
-class Temporal::Recurring {
-...
-}
-
-Should allow creation from the format that cron uses (ie. */5 * * * * ).
-
=head1 Additions
Please post errors and feedback to perl6-language. If you are making