Raku includes several classes that deal with temporal information: Date
, DateTime
, Instant
and Duration
. The three first are dateish, so they mix in the Dateish
role, which defines all methods and properties that classes that deal with date should assume. It also includes a class hierarchy of exceptions rooted in X::Temporal
.
We will try to illustrate these classes in the next (somewhat extended) example, which can be used to process all files in a directory (by default .
) with a particular extension (by default .raku
) in a directory, sort them according to their age, and compute how many files have been created per month and how many were modified in certain periods expressed in ranges of months:
sub MAIN( $path = ".", $extension = "raku" ) { my DateTime $right = DateTime.now; my %metadata; my %files-month; my %files-period; for dir($path).grep( / \.$extension $/ ) -> $file { CATCH { when X::Temporal { say "Date-related problem", .payload } when X::IO { say "File-related problem", .payload } default { .payload.say } } my Instant $modified = $file.modified; my Instant $accessed = $file.accessed; my Duration $duration = $accessed - $modified; my $age = $right - DateTime($accessed); my $time-of-day = $file.changed.DateTime.hh-mm-ss but Dateish; my $file-changed-date = $file.changed.Date; %metadata{$file} = %( modified => $modified, accessed => $accessed, age => $age, difference => $duration, changed-tod => $time-of-day, changed-date => $file-changed-date); %files-month{$file-changed-date.month}++; given $file-changed-date { when Date.new("2018-01-01")..^Date.new("2018-04-01") { %files-period<pre-grant>++} when Date.new("2018-04-01")..Date.new("2018-05-31") { %files-period<grant>++} default { %files-period<post-grant>++}; } } %metadata.sort( { $^a.value<age> <=> $^b.value<age> } ).map: { say $^x.key, ", ", $^x.value<accessed modified age difference changed-tod changed-date>.join(", "); }; %files-month.keys.sort.map: { say "Month $^x → %files-month{$^x}" }; %files-period.keys.map: { say "Period $^x → %files-period{$^x}" }; }
DateTime
is used in line 2 to contain the current date and time returned by now
.
A CATCH phaser is declared in lines 7 to 11. Its main mission is to distinguish between DateTime
-related exceptions and other types. These kinds of exception can arise from invalid formats or timezone clashes. Barring some corruption of the file attributes, both are impossible, but in any case they should be caught and separated from other types of exceptions.
We use Instant
s in lines 12-13 to represent the moment in which the files where accessed and modified. An Instant is measured in atomic seconds and is a very low-level description of a time event; however, the Duration
declared in line 14 represents the time transcurred among two different Instant
s and we will be using it to represent the age.
For some variables, we might be interested in dealing with them with some dateish traits. $time-of-day
contains the time of the day the file was changed; changed
will return an Instant, but it is converted into a Date (which is Dateish
while Instant
is not) and then the time of day is extracted from that. $time-of-day
will have «Str+{Dateish}»
type.
We will use the date in this variable to find out the period when the files were changed.
Date.new("2018-01-01")..^Date.new("2018-04-01")
creates a date Range
and $file-changed-date
is smartmatched against it. Dates can be used this way; in this case it creates a Range
that excludes its last element.
This very variable is also used to compute the month of the year when the file was modified. Date
is obviously Dateish
and then has the month
method to extract that property from it.
Duration
objects can be compared. This is used in
%metadata.sort({ $^a.value<age> <=> $^b.value<age> });
to sort the files by age.