=begin pod :kind("Language") :subkind("Language") :category("fundamental")

=TITLE Date and time functions

=SUBTITLE Processing date and time in Raku

X<|Date and time functions>

Raku includes several classes that deal with temporal information: L<Date|/type/Date>, L<DateTime|/type/DateTime>, L<Instant|/type/Instant> and L<Duration|/type/Duration>. The three first are I<dateish>, so they mix in the L<Dateish|/type/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 L<X::Temporal|/type/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 C<.>) with a particular extension (by default C<.p6>) 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:

=begin code
sub MAIN( $path = ".", $extension = "p6" ) {
    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}"
    };
}
=end code

C<DateTime> is used in line 2 to contain the current date and time returned by L<C<now>|/routine/now>.

A CATCH phaser is declared in lines 7 to 11. Its main mission is to distinguish between C<DateTime>-related exceptions and other types. These kind of exception can arise from L<invalid formats|/type/X::Temporal::InvalidFormat> or L<timezone clashes|/type/X::DateTime::TimezoneClash>. 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 L<Instant|/type/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 L<Duration|/type/Duration> declared in line 14 represent the time transcurred among two different C<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 I<dateish> traits. C<$time-of-day> contains the time of the day the file was changed; C<changed> will return an Instant, but it is converted into a Date (which is C<Dateish> while C<Instant> is not) and then the time of day is extracted from that. C<$time-of-day> will have C< «Str+{Dateish}␤» > type.

X<|Date ranges>
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 L<Range|/type/Range> and C<$file-changed-date> is smartmatched against it. Dates can be used this way; in this case it creates a C<Range> that excludes its last element.

This very variable is also used to compute the month of the year when the file was modified. L<Date|/type/Date> is obviously C<Dateish> and then has the C<month> method to extract that property from it.

C<Duration> objects can be compared. This is used in

=for code :preamble<my %metadata>
%metadata.sort({
    $^a.value<age> <=> $^b.value<age>
});

to sort the files by age.


=end pod
