|
| 1 | +=begin pod :tag<perl6> |
| 2 | +
|
| 3 | +=TITLE Date and time functions |
| 4 | +
|
| 5 | +=SUBTITLE Processing date and time in Perl 6 |
| 6 | +
|
| 7 | +X<|Date and time functions> |
| 8 | +
|
| 9 | +Perl 6 includes several classes that deal with temporal information: L<Date>, L<DateTime>, L<Instant> and L<Duration>. The three first are I<dateish>, so they mix in the L<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>. |
| 10 | +
|
| 11 | +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 an 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: |
| 12 | +
|
| 13 | +=begin code |
| 14 | +use v6; |
| 15 | +
|
| 16 | +sub MAIN( $path = ".", $extension = "p6" ) { |
| 17 | + my DateTime $right = DateTime.now; |
| 18 | + my %metadata; |
| 19 | + my %files-month; |
| 20 | + my %files-period; |
| 21 | + for dir($path).grep( / \.$extension $/ ) -> $file { |
| 22 | + CATCH { |
| 23 | + when X::Temporal { say "Date-related problem", .payload } |
| 24 | + when X::IO { say "File-related problem", .payload } |
| 25 | + default { .payload.say } |
| 26 | + } |
| 27 | + my Instant $modified = $file.modified; |
| 28 | + my Instant $accessed = $file.accessed; |
| 29 | + my Duration $duration = $accessed - $modified; |
| 30 | + my $age = $right - DateTime($accessed); |
| 31 | + my $time-of-day = $file.changed.DateTime.hh-mm-ss but Dateish; |
| 32 | + my $file-changed-date = $file.changed.Date; |
| 33 | + %metadata{$file} = %( modified => $modified, |
| 34 | + accessed => $accessed, |
| 35 | + age => $age, |
| 36 | + difference => $duration, |
| 37 | + changed-tod => $time-of-day, |
| 38 | + changed-date => $file-changed-date); |
| 39 | + %files-month{$file-changed-date.month}++; |
| 40 | + given $file-changed-date { |
| 41 | + when Date.new("2018-01-01")..^Date.new("2018-04-01") { %files-period<pre-grant>++} |
| 42 | + when Date.new("2018-04-01")..Date.new("2018-05-31") { %files-period<grant>++} |
| 43 | + default { %files-period<post-grant>++}; |
| 44 | + } |
| 45 | + } |
| 46 | +
|
| 47 | + %metadata.sort( { $^a.value<age> <=> $^b.value<age> } ).map: { |
| 48 | + say $^x.key, ", ", |
| 49 | + $^x.value<accessed modified age difference changed-tod changed-date>.join(", "); |
| 50 | + }; |
| 51 | + %files-month.keys.sort.map: { |
| 52 | + say "Month $^x → %files-month{$^x}" |
| 53 | + }; |
| 54 | +
|
| 55 | + %files-period.keys.map: { |
| 56 | + say "Period $^x → %files-period{$^x}" |
| 57 | + }; |
| 58 | +} |
| 59 | +
|
| 60 | +C<DateTime> is used in line 6 to contain the current date and time returned by L<C<now>|/routine/now>. |
| 61 | +
|
| 62 | +A CATCH phaser is declared in lines 11 to 15. Its main mission is to distinguish between C<DateTime>-related exceptions and other types. These kind of exception can arise from L<invalid formats|X::Temporal::InvalidFormat> or L<timezone clashes|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. |
| 63 | +
|
| 64 | +We use L<Instant>s in lines 16-17 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> declared in line 18 represent the time transcurred among two different C<Instant>s, and we will be using it to represent the age. |
| 65 | +
|
| 66 | +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. |
| 67 | +
|
| 68 | +X<|Date ranges> |
| 69 | +We will use the date in this variable to find out the period when the files were changed. |
| 70 | +
|
| 71 | + Date.new("2018-01-01")..^Date.new("2018-04-01") |
| 72 | +
|
| 73 | +creates a date L<Range> and C<$file-changed-date> is smart-matched against it. Dates can be used this way; in this case it creates a C<Range> that excludes its last element. |
| 74 | +
|
| 75 | +This very variable is also used to compute the month of the year when the file was modified. L<Date> is obviously C<Dateish> and then has the C<month> method to extract that property from it. |
| 76 | +
|
| 77 | +C<Duration> objects can be compared. This is used in |
| 78 | +
|
| 79 | + $^a.value<age> <=> $^b.value<age> |
| 80 | +
|
| 81 | +to sort the files by age. |
| 82 | +
|
| 83 | +
|
| 84 | +=end pod |
0 commit comments