| Filename | /home/s1/perl5/perlbrew/perls/perl-5.22.1/lib/site_perl/5.22.1/DateTime/Format/Alami.pm |
| Statements | Executed 63058 statements in 83.9ms |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 4000 | 3 | 1 | 66.8ms | 2.53s | DateTime::Format::Alami::CORE:match (opcode) |
| 1000 | 1 | 1 | 49.1ms | 2.84s | DateTime::Format::Alami::parse_datetime |
| 3000 | 1 | 1 | 35.2ms | 2.46s | DateTime::Format::Alami::a_dateymd |
| 3000 | 1 | 1 | 15.1ms | 961ms | DateTime::Format::Alami::a_today |
| 1000 | 1 | 1 | 3.50ms | 3.50ms | DateTime::Format::Alami::CORE:regcomp (opcode) |
| 1 | 1 | 1 | 2.12ms | 2.64ms | DateTime::Format::Alami::BEGIN@114 |
| 1 | 1 | 1 | 1.66ms | 14.8ms | DateTime::Format::Alami::BEGIN@384 |
| 1000 | 1 | 1 | 1.33ms | 1.33ms | DateTime::Format::Alami::_reset |
| 1 | 1 | 1 | 840µs | 884µs | DateTime::Format::Alami::BEGIN@9 |
| 1 | 1 | 1 | 35µs | 35µs | DateTime::Format::Alami::BEGIN@6 |
| 1 | 1 | 1 | 21µs | 21µs | DateTime::Format::Alami::new |
| 1 | 1 | 1 | 14µs | 34µs | DateTime::Format::Alami::BEGIN@487 |
| 1 | 1 | 1 | 14µs | 18µs | DateTime::Format::Alami::BEGIN@7 |
| 1 | 1 | 1 | 13µs | 30µs | DateTime::Format::Alami::BEGIN@163 |
| 1 | 1 | 1 | 12µs | 28µs | DateTime::Format::Alami::BEGIN@242 |
| 1 | 1 | 1 | 12µs | 20µs | DateTime::Format::Alami::BEGIN@8 |
| 1 | 1 | 1 | 12µs | 27µs | DateTime::Format::Alami::BEGIN@494 |
| 1 | 1 | 1 | 12µs | 144µs | DateTime::Format::Alami::BEGIN@11 |
| 1 | 1 | 1 | 12µs | 28µs | DateTime::Format::Alami::BEGIN@50 |
| 0 | 0 | 0 | 0s | 0s | DateTime::Format::Alami::_now_if_unset |
| 0 | 0 | 0 | 0s | 0s | DateTime::Format::Alami::_parse_dur |
| 0 | 0 | 0 | 0s | 0s | DateTime::Format::Alami::_reset_dur |
| 0 | 0 | 0 | 0s | 0s | DateTime::Format::Alami::_today_if_unset |
| 0 | 0 | 0 | 0s | 0s | DateTime::Format::Alami::a_date_time |
| 0 | 0 | 0 | 0s | 0s | DateTime::Format::Alami::a_dur_ago |
| 0 | 0 | 0 | 0s | 0s | DateTime::Format::Alami::a_dur_later |
| 0 | 0 | 0 | 0s | 0s | DateTime::Format::Alami::a_now |
| 0 | 0 | 0 | 0s | 0s | DateTime::Format::Alami::a_time |
| 0 | 0 | 0 | 0s | 0s | DateTime::Format::Alami::a_tomorrow |
| 0 | 0 | 0 | 0s | 0s | DateTime::Format::Alami::a_which_dow |
| 0 | 0 | 0 | 0s | 0s | DateTime::Format::Alami::a_yesterday |
| 0 | 0 | 0 | 0s | 0s | DateTime::Format::Alami::adur_dur |
| 0 | 0 | 0 | 0s | 0s | DateTime::Format::Alami::o_dayint |
| 0 | 0 | 0 | 0s | 0s | DateTime::Format::Alami::o_dow |
| 0 | 0 | 0 | 0s | 0s | DateTime::Format::Alami::o_dur |
| 0 | 0 | 0 | 0s | 0s | DateTime::Format::Alami::o_durwords |
| 0 | 0 | 0 | 0s | 0s | DateTime::Format::Alami::o_hour |
| 0 | 0 | 0 | 0s | 0s | DateTime::Format::Alami::o_minute |
| 0 | 0 | 0 | 0s | 0s | DateTime::Format::Alami::o_monthint |
| 0 | 0 | 0 | 0s | 0s | DateTime::Format::Alami::o_monthname |
| 0 | 0 | 0 | 0s | 0s | DateTime::Format::Alami::o_second |
| 0 | 0 | 0 | 0s | 0s | DateTime::Format::Alami::o_timedur |
| 0 | 0 | 0 | 0s | 0s | DateTime::Format::Alami::o_timedurwords |
| 0 | 0 | 0 | 0s | 0s | DateTime::Format::Alami::o_yearint |
| 0 | 0 | 0 | 0s | 0s | DateTime::Format::Alami::odur_dur |
| 0 | 0 | 0 | 0s | 0s | DateTime::Format::Alami::parse_datetime_duration |
| 0 | 0 | 0 | 0s | 0s | DateTime::Format::Alami::pdur_dur |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | package DateTime::Format::Alami; | ||||
| 2 | |||||
| 3 | 1 | 800ns | our $DATE = '2016-06-30'; # DATE | ||
| 4 | 1 | 300ns | our $VERSION = '0.11'; # VERSION | ||
| 5 | |||||
| 6 | 2 | 73µs | 1 | 35µs | # spent 35µs within DateTime::Format::Alami::BEGIN@6 which was called:
# once (35µs+0s) by Role::Tiny::_load_module at line 6 # spent 35µs making 1 call to DateTime::Format::Alami::BEGIN@6 |
| 7 | 2 | 39µs | 2 | 22µs | # spent 18µs (14+5) within DateTime::Format::Alami::BEGIN@7 which was called:
# once (14µs+5µs) by Role::Tiny::_load_module at line 7 # spent 18µs making 1 call to DateTime::Format::Alami::BEGIN@7
# spent 4µs making 1 call to strict::import |
| 8 | 2 | 40µs | 2 | 29µs | # spent 20µs (12+8) within DateTime::Format::Alami::BEGIN@8 which was called:
# once (12µs+8µs) by Role::Tiny::_load_module at line 8 # spent 20µs making 1 call to DateTime::Format::Alami::BEGIN@8
# spent 8µs making 1 call to warnings::import |
| 9 | 2 | 868µs | 2 | 927µs | # spent 884µs (840+44) within DateTime::Format::Alami::BEGIN@9 which was called:
# once (840µs+44µs) by Role::Tiny::_load_module at line 9 # spent 884µs making 1 call to DateTime::Format::Alami::BEGIN@9
# spent 44µs making 1 call to Log::Any::IfLOG::import |
| 10 | |||||
| 11 | 2 | 302µs | 2 | 277µs | # spent 144µs (12+133) within DateTime::Format::Alami::BEGIN@11 which was called:
# once (12µs+133µs) by Role::Tiny::_load_module at line 11 # spent 144µs making 1 call to DateTime::Format::Alami::BEGIN@11
# spent 133µs making 1 call to Role::Tiny::import |
| 12 | |||||
| 13 | 1 | 4µs | my @short_mons = qw(jan feb mar apr may jun jul aug sep oct nov dec); | ||
| 14 | 1 | 1µs | my @dow = qw(monday tuesday wednesday thursday friday saturday sunday); | ||
| 15 | |||||
| 16 | 1 | 3µs | 1 | 7µs | requires 'o_num'; # spent 7µs making 1 call to Role::Tiny::__ANON__[Role/Tiny.pm:86] |
| 17 | 1 | 1µs | 1 | 2µs | requires '_parse_num'; # spent 2µs making 1 call to Role::Tiny::__ANON__[Role/Tiny.pm:86] |
| 18 | |||||
| 19 | 1 | 1µs | 1 | 2µs | requires 'w_year'; # spent 2µs making 1 call to Role::Tiny::__ANON__[Role/Tiny.pm:86] |
| 20 | 1 | 1µs | 1 | 2µs | requires 'w_month'; # spent 2µs making 1 call to Role::Tiny::__ANON__[Role/Tiny.pm:86] |
| 21 | 1 | 1µs | 1 | 2µs | requires 'w_week'; # spent 2µs making 1 call to Role::Tiny::__ANON__[Role/Tiny.pm:86] |
| 22 | 1 | 1µs | 1 | 2µs | requires 'w_day'; # spent 2µs making 1 call to Role::Tiny::__ANON__[Role/Tiny.pm:86] |
| 23 | 1 | 1µs | 1 | 2µs | requires 'w_hour'; # spent 2µs making 1 call to Role::Tiny::__ANON__[Role/Tiny.pm:86] |
| 24 | 1 | 1µs | 1 | 1µs | requires 'w_minute'; # spent 1µs making 1 call to Role::Tiny::__ANON__[Role/Tiny.pm:86] |
| 25 | 1 | 1µs | 1 | 2µs | requires 'w_second'; # spent 2µs making 1 call to Role::Tiny::__ANON__[Role/Tiny.pm:86] |
| 26 | |||||
| 27 | 1 | 25µs | 12 | 25µs | requires "w_$_" for @short_mons; # spent 25µs making 12 calls to Role::Tiny::__ANON__[Role/Tiny.pm:86], avg 2µs/call |
| 28 | 1 | 15µs | 7 | 13µs | requires "w_$_" for @dow; # spent 13µs making 7 calls to Role::Tiny::__ANON__[Role/Tiny.pm:86], avg 2µs/call |
| 29 | |||||
| 30 | 1 | 1µs | 1 | 2µs | requires 'p_now'; # spent 2µs making 1 call to Role::Tiny::__ANON__[Role/Tiny.pm:86] |
| 31 | 1 | 1µs | 1 | 2µs | requires 'p_today'; # spent 2µs making 1 call to Role::Tiny::__ANON__[Role/Tiny.pm:86] |
| 32 | 1 | 1µs | 1 | 2µs | requires 'p_yesterday'; # spent 2µs making 1 call to Role::Tiny::__ANON__[Role/Tiny.pm:86] |
| 33 | 1 | 1µs | 1 | 2µs | requires 'p_tomorrow'; # spent 2µs making 1 call to Role::Tiny::__ANON__[Role/Tiny.pm:86] |
| 34 | 1 | 1µs | 1 | 2µs | requires 'p_dateymd'; # spent 2µs making 1 call to Role::Tiny::__ANON__[Role/Tiny.pm:86] |
| 35 | 1 | 1µs | 1 | 2µs | requires 'o_date'; # spent 2µs making 1 call to Role::Tiny::__ANON__[Role/Tiny.pm:86] |
| 36 | 1 | 1µs | 1 | 2µs | requires 'p_dur_ago'; # spent 2µs making 1 call to Role::Tiny::__ANON__[Role/Tiny.pm:86] |
| 37 | 1 | 1µs | 1 | 2µs | requires 'p_dur_later'; # spent 2µs making 1 call to Role::Tiny::__ANON__[Role/Tiny.pm:86] |
| 38 | 1 | 1µs | 1 | 2µs | requires 'p_which_dow'; # spent 2µs making 1 call to Role::Tiny::__ANON__[Role/Tiny.pm:86] |
| 39 | 1 | 1µs | 1 | 2µs | requires 'p_time'; # spent 2µs making 1 call to Role::Tiny::__ANON__[Role/Tiny.pm:86] |
| 40 | 1 | 1µs | 1 | 1µs | requires 'p_date_time'; # spent 1µs making 1 call to Role::Tiny::__ANON__[Role/Tiny.pm:86] |
| 41 | |||||
| 42 | our ($m, $o); | ||||
| 43 | # spent 21µs within DateTime::Format::Alami::new which was called:
# once (21µs+0s) by main::RUNTIME at line 1 of -e | ||||
| 44 | 1 | 1µs | my $class = shift; | ||
| 45 | 1 | 700ns | if ($class eq __PACKAGE__) { | ||
| 46 | die "Use one of the DateTime::Format::Alami::* instead, ". | ||||
| 47 | "e.g. DateTime::Format::Alami::EN"; | ||||
| 48 | } | ||||
| 49 | 1 | 2µs | my $self = bless {}, $class; | ||
| 50 | 2 | 763µs | 2 | 45µs | # spent 28µs (12+16) within DateTime::Format::Alami::BEGIN@50 which was called:
# once (12µs+16µs) by Role::Tiny::_load_module at line 50 # spent 28µs making 1 call to DateTime::Format::Alami::BEGIN@50
# spent 16µs making 1 call to strict::unimport |
| 51 | 1 | 8µs | unless (${"$class\::RE_DT"} && ${"$class\::RE_DUR"}) { | ||
| 52 | require Class::Inspector; | ||||
| 53 | require Data::Graph::Util; | ||||
| 54 | |||||
| 55 | my $meths = Class::Inspector->methods($class); | ||||
| 56 | my %pats; # key = "p_..." | ||||
| 57 | my %pat_lengths; # key = "p_..." | ||||
| 58 | my %graph; | ||||
| 59 | for my $meth (@$meths) { | ||||
| 60 | next unless $meth =~ /^(odur|o|pdur|p)_/; | ||||
| 61 | my $pat = $self->$meth; | ||||
| 62 | my $is_p = $meth =~ /^p_/; | ||||
| 63 | my $is_pdur = $meth =~ /^pdur_/; | ||||
| 64 | $pat =~ s/<(\w+)>/push @{$graph{$meth}}, $1; "(?\&$1)"/eg; | ||||
| 65 | my $action_meth = $meth; | ||||
| 66 | if ($is_pdur) { $action_meth =~ s/^pdur_/adur_/ } else { $action_meth =~ s/^p_/a_/ } | ||||
| 67 | #my $before_meth = $meth; $before_meth =~ s/^p_/before_p_/; | ||||
| 68 | #$before_meth = undef unless $is_p && $self->can($before_meth); | ||||
| 69 | $pat = join( | ||||
| 70 | "", | ||||
| 71 | "(", | ||||
| 72 | #($before_meth ? "(?{ ".($ENV{DEBUG} ? "say \"invoking $before_meth()\";" : "")."\$DateTime::Format::Alami::o->$before_meth(\$DateTime::Format::Alami::m) })" : ""), | ||||
| 73 | ($is_p || $is_pdur ? "\\b $pat \\b" : $pat), ")", | ||||
| 74 | |||||
| 75 | # we capture ourselves instead of relying on named capture | ||||
| 76 | # because subpattern capture are discarded | ||||
| 77 | "(?{ \$DateTime::Format::Alami::m->{$meth} = \$^N })", | ||||
| 78 | |||||
| 79 | ($is_p || $is_pdur ? "(?{ ".($ENV{DEBUG} ? "say \"invoking $action_meth(\$^N)\";" : "")."\$DateTime::Format::Alami::o->{_pat} = \"$meth\"; \$DateTime::Format::Alami::o->$action_meth(\$DateTime::Format::Alami::m) })" : ""), | ||||
| 80 | ); | ||||
| 81 | $pats{$meth} = $pat; | ||||
| 82 | $pat_lengths{$meth} = length($pat); | ||||
| 83 | } | ||||
| 84 | my @pat_names_by_deps = Data::Graph::Util::toposort(\%graph); | ||||
| 85 | my %pat_name_dep_orders = map { $pat_names_by_deps[$_] => $_ } | ||||
| 86 | 0..$#pat_names_by_deps; | ||||
| 87 | my @pat_names = sort {( | ||||
| 88 | ($pat_name_dep_orders{$a} // 9999) <=> | ||||
| 89 | ($pat_name_dep_orders{$b} // 9999) | ||||
| 90 | || | ||||
| 91 | $pat_lengths{$b} <=> $pat_lengths{$a}) } keys %pats; | ||||
| 92 | my $nl = $ENV{DEBUG} ? "\n" : ""; | ||||
| 93 | my $re_dt = join( | ||||
| 94 | "", | ||||
| 95 | "((?&top))", $nl, | ||||
| 96 | #"(?&p_dateymd)", $nl, # testing | ||||
| 97 | "(?(DEFINE)", $nl, | ||||
| 98 | "(?<top>", join("|", | ||||
| 99 | map {"(?&$_)"} grep {/^p_/} @pat_names), ")$nl", | ||||
| 100 | (map { "(?<$_> $pats{$_})$nl" } grep {/^(o|p)_/} @pat_names), | ||||
| 101 | ")", # end of define | ||||
| 102 | ); | ||||
| 103 | my $re_dur = join( | ||||
| 104 | "", | ||||
| 105 | "(?&top)", $nl, | ||||
| 106 | #"(?&pdur_dur)", $nl, # testing | ||||
| 107 | "(?(DEFINE)", $nl, | ||||
| 108 | "(?<top>", join("|", | ||||
| 109 | map {"(?&$_)"} grep {/^pdur_/} @pat_names), ")$nl", | ||||
| 110 | (map { "(?<$_> $pats{$_})$nl" } grep {/^(odur|pdur)_/} @pat_names), | ||||
| 111 | ")", # end of define | ||||
| 112 | ); | ||||
| 113 | { | ||||
| 114 | 2 | 622µs | 2 | 2.67ms | # spent 2.64ms (2.12+518µs) within DateTime::Format::Alami::BEGIN@114 which was called:
# once (2.12ms+518µs) by Role::Tiny::_load_module at line 114 # spent 2.64ms making 1 call to DateTime::Format::Alami::BEGIN@114
# spent 26µs making 1 call to re::import |
| 115 | ${"$class\::RE_DT"} = qr/$re_dt/ix; | ||||
| 116 | ${"$class\::RE_DUR"} = qr/$re_dur/ix; | ||||
| 117 | } | ||||
| 118 | } | ||||
| 119 | 1 | 2µs | unless (${"$class\::MAPS"}) { | ||
| 120 | my $maps = {}; | ||||
| 121 | # month names -> num | ||||
| 122 | { | ||||
| 123 | my $i = 0; | ||||
| 124 | for my $m (@short_mons) { | ||||
| 125 | ++$i; | ||||
| 126 | my $meth = "w_$m"; | ||||
| 127 | for (@{ $self->$meth }) { | ||||
| 128 | $maps->{months}{$_} = $i; | ||||
| 129 | } | ||||
| 130 | } | ||||
| 131 | } | ||||
| 132 | # day-of-week names -> num (monday=1, sunday=7) | ||||
| 133 | { | ||||
| 134 | my $i = 0; | ||||
| 135 | for my $m (@dow) { | ||||
| 136 | ++$i; | ||||
| 137 | my $meth = "w_$m"; | ||||
| 138 | for (@{ $self->$meth }) { | ||||
| 139 | $maps->{dow}{$_} = $i; | ||||
| 140 | } | ||||
| 141 | } | ||||
| 142 | } | ||||
| 143 | ${"$class\::MAPS"} = $maps; | ||||
| 144 | } | ||||
| 145 | |||||
| 146 | # _time_zone is old name (<= 0.11) will be removed later | ||||
| 147 | 1 | 3µs | $self->{time_zone} //= $self->{_time_zone}; | ||
| 148 | |||||
| 149 | 1 | 8µs | $self; | ||
| 150 | } | ||||
| 151 | |||||
| 152 | # spent 1.33ms within DateTime::Format::Alami::_reset which was called 1000 times, avg 1µs/call:
# 1000 times (1.33ms+0s) by DateTime::Format::Alami::parse_datetime at line 182, avg 1µs/call | ||||
| 153 | 1000 | 158µs | my $self = shift; | ||
| 154 | 1000 | 358µs | undef $self->{_pat}; | ||
| 155 | 1000 | 138µs | undef $self->{_dt}; | ||
| 156 | 1000 | 1.70ms | undef $self->{_uses_time}; | ||
| 157 | } | ||||
| 158 | |||||
| 159 | # spent 2.84s (49.1ms+2.79) within DateTime::Format::Alami::parse_datetime which was called 1000 times, avg 2.84ms/call:
# 1000 times (49.1ms+2.79s) by main::RUNTIME at line 1 of -e, avg 2.84ms/call | ||||
| 160 | # we require DateTime here, for all the a_* methods | ||||
| 161 | 1000 | 760µs | require DateTime; | ||
| 162 | |||||
| 163 | 2 | 725µs | 2 | 47µs | # spent 30µs (13+17) within DateTime::Format::Alami::BEGIN@163 which was called:
# once (13µs+17µs) by Role::Tiny::_load_module at line 163 # spent 30µs making 1 call to DateTime::Format::Alami::BEGIN@163
# spent 17µs making 1 call to strict::unimport |
| 164 | |||||
| 165 | 1000 | 462µs | my ($self, $str, $opts) = @_; | ||
| 166 | |||||
| 167 | # allow calling as static method | ||||
| 168 | 1000 | 286µs | unless (ref $self) { $self = $self->new } | ||
| 169 | |||||
| 170 | 1000 | 384µs | $opts //= {}; | ||
| 171 | 1000 | 521µs | $opts->{format} //= 'DateTime'; | ||
| 172 | #$opts->{prefers} //= 'nearest'; | ||||
| 173 | 1000 | 188µs | $opts->{returns} //= 'first'; | ||
| 174 | |||||
| 175 | 1000 | 178µs | local $self->{time_zone} = $opts->{time_zone} if $opts->{time_zone}; | ||
| 176 | |||||
| 177 | 1000 | 1.34ms | my $re = ${ref($self).'::RE_DT'}; | ||
| 178 | |||||
| 179 | 1000 | 166µs | $o = $self; | ||
| 180 | 1000 | 117µs | my @res; | ||
| 181 | 1000 | 129µs | while (1) { | ||
| 182 | 1000 | 820µs | 1000 | 1.33ms | $o->_reset; # spent 1.33ms making 1000 calls to DateTime::Format::Alami::_reset, avg 1µs/call |
| 183 | 1000 | 972µs | $m = {}; | ||
| 184 | 1000 | 7.72ms | 2000 | 2.53s | $str =~ /$re/g or last; # spent 2.53s making 1000 calls to DateTime::Format::Alami::CORE:match, avg 2.53ms/call
# spent 3.50ms making 1000 calls to DateTime::Format::Alami::CORE:regcomp, avg 4µs/call |
| 185 | 1000 | 1.50ms | 1000 | 175ms | $o->{_dt}->truncate(to=>'day') unless $o->{_uses_time}; # spent 175ms making 1000 calls to DateTime::truncate, avg 175µs/call |
| 186 | my $res = { | ||||
| 187 | verbatim => $1, | ||||
| 188 | pattern => $o->{_pat}, | ||||
| 189 | 1000 | 4.47ms | pos => pos($str) - length($1), | ||
| 190 | m => {%$m}, | ||||
| 191 | }; | ||||
| 192 | 1000 | 478µs | $res->{uses_time} = $o->{_uses_time} ? 1:0; | ||
| 193 | 1000 | 270µs | $res->{DateTime} = $o->{_dt}; | ||
| 194 | $res->{epoch} = $o->{_dt}->epoch if | ||||
| 195 | 1000 | 513µs | $opts->{format} eq 'combined' || $opts->{format} eq 'epoch'; | ||
| 196 | 1000 | 344µs | push @res, $res; | ||
| 197 | 1000 | 677µs | last if $opts->{returns} eq 'first'; | ||
| 198 | } | ||||
| 199 | |||||
| 200 | 1000 | 223µs | die "Can't parse date '$str'" unless @res; | ||
| 201 | |||||
| 202 | 1000 | 176µs | @res = ($res[-1]) if $opts->{returns} eq 'last'; | ||
| 203 | |||||
| 204 | 1000 | 1.73ms | 1000 | 238µs | if ($opts->{returns} =~ /\A(?:all_cron|earliest|latest)\z/) { # spent 238µs making 1000 calls to DateTime::Format::Alami::CORE:match, avg 238ns/call |
| 205 | # sort chronologically, note that by this time the DateTime module | ||||
| 206 | # should already have been loaded | ||||
| 207 | @res = sort { | ||||
| 208 | DateTime->compare($a->{DateTime}, $b->{DateTime}) | ||||
| 209 | } @res; | ||||
| 210 | } | ||||
| 211 | |||||
| 212 | 1000 | 2.72ms | if ($opts->{format} eq 'DateTime') { | ||
| 213 | @res = map { $_->{DateTime} } @res; | ||||
| 214 | } elsif ($opts->{format} eq 'epoch') { | ||||
| 215 | @res = map { $_->{epoch} } @res; | ||||
| 216 | } elsif ($opts->{format} eq 'verbatim') { | ||||
| 217 | @res = map { $_->{verbatim} } @res; | ||||
| 218 | } | ||||
| 219 | |||||
| 220 | 1000 | 9.35ms | 2000 | 1.39ms | if ($opts->{returns} =~ /\A(?:all|all_cron)\z/) { # spent 1.39ms making 2000 calls to DateTime::Format::Alami::CORE:match, avg 695ns/call |
| 221 | return \@res; | ||||
| 222 | } elsif ($opts->{returns} =~ /\A(?:first|earliest)\z/) { | ||||
| 223 | return $res[0]; | ||||
| 224 | } elsif ($opts->{returns} =~ /\A(?:last|latest)\z/) { | ||||
| 225 | return $res[-1]; | ||||
| 226 | } else { | ||||
| 227 | die "Unknown returns option '$opts->{returns}'"; | ||||
| 228 | } | ||||
| 229 | } | ||||
| 230 | |||||
| 231 | sub _reset_dur { | ||||
| 232 | my $self = shift; | ||||
| 233 | undef $self->{_pat}; | ||||
| 234 | undef $self->{_dtdur}; | ||||
| 235 | } | ||||
| 236 | |||||
| 237 | sub parse_datetime_duration { | ||||
| 238 | # we require DateTime here, for all the adur_* methods | ||||
| 239 | require DateTime; | ||||
| 240 | require DateTime::Duration; | ||||
| 241 | |||||
| 242 | 2 | 1.23ms | 2 | 44µs | # spent 28µs (12+16) within DateTime::Format::Alami::BEGIN@242 which was called:
# once (12µs+16µs) by Role::Tiny::_load_module at line 242 # spent 28µs making 1 call to DateTime::Format::Alami::BEGIN@242
# spent 16µs making 1 call to strict::unimport |
| 243 | |||||
| 244 | my ($self, $str, $opts) = @_; | ||||
| 245 | |||||
| 246 | # allow calling as static method | ||||
| 247 | unless (ref $self) { $self = $self->new } | ||||
| 248 | |||||
| 249 | $opts //= {}; | ||||
| 250 | $opts->{format} //= 'Duration'; | ||||
| 251 | $opts->{returns} //= 'first'; | ||||
| 252 | |||||
| 253 | my $re = ${ref($self).'::RE_DUR'}; | ||||
| 254 | |||||
| 255 | $o = $self; | ||||
| 256 | my @res; | ||||
| 257 | while (1) { | ||||
| 258 | $o->_reset_dur; | ||||
| 259 | $m = {}; | ||||
| 260 | $str =~ /($re)/g or last; | ||||
| 261 | my $res = { | ||||
| 262 | verbatim => $1, | ||||
| 263 | pattern => $o->{_pat}, | ||||
| 264 | pos => pos($str) - length($1), | ||||
| 265 | m => {%$m}, | ||||
| 266 | }; | ||||
| 267 | $res->{Duration} = $o->{_dtdur}; | ||||
| 268 | if ($opts->{format} eq 'combined' || $opts->{format} eq 'seconds') { | ||||
| 269 | my $d = $o->{_dtdur}; | ||||
| 270 | $res->{seconds} = | ||||
| 271 | $d->years * 365.25*86400 + | ||||
| 272 | $d->months * 30.4375*86400 + | ||||
| 273 | $d->weeks * 7*86400 + | ||||
| 274 | $d->days * 86400 + | ||||
| 275 | $d->hours * 3600 + | ||||
| 276 | $d->minutes * 60 + | ||||
| 277 | $d->seconds + | ||||
| 278 | $d->nanoseconds * 1e-9; | ||||
| 279 | } | ||||
| 280 | push @res, $res; | ||||
| 281 | last if $opts->{returns} eq 'first'; | ||||
| 282 | } | ||||
| 283 | |||||
| 284 | die "Can't parse duration" unless @res; | ||||
| 285 | |||||
| 286 | @res = ($res[-1]) if $opts->{returns} eq 'last'; | ||||
| 287 | |||||
| 288 | # XXX support returns largest, smallest, all_sorted | ||||
| 289 | if ($opts->{returns} =~ /\A(?:all_sorted|largest|smallest)\z/) { | ||||
| 290 | my $base_dt = DateTime->now; | ||||
| 291 | # sort from smallest to largest | ||||
| 292 | @res = sort { | ||||
| 293 | DateTime::Duration->compare($a->{Duration}, $b->{Duration}, $base_dt) | ||||
| 294 | } @res; | ||||
| 295 | } | ||||
| 296 | |||||
| 297 | if ($opts->{format} eq 'Duration') { | ||||
| 298 | @res = map { $_->{Duration} } @res; | ||||
| 299 | } elsif ($opts->{format} eq 'seconds') { | ||||
| 300 | @res = map { $_->{seconds} } @res; | ||||
| 301 | } elsif ($opts->{format} eq 'verbatim') { | ||||
| 302 | @res = map { $_->{verbatim} } @res; | ||||
| 303 | } | ||||
| 304 | |||||
| 305 | if ($opts->{returns} =~ /\A(?:all|all_sorted)\z/) { | ||||
| 306 | return \@res; | ||||
| 307 | } elsif ($opts->{returns} =~ /\A(?:first|smallest)\z/) { | ||||
| 308 | return $res[0]; | ||||
| 309 | } elsif ($opts->{returns} =~ /\A(?:last|largest)\z/) { | ||||
| 310 | return $res[-1]; | ||||
| 311 | } else { | ||||
| 312 | die "Unknown returns option '$opts->{returns}'"; | ||||
| 313 | } | ||||
| 314 | } | ||||
| 315 | |||||
| 316 | sub o_dayint { "(?:[12][0-9]|3[01]|0?[1-9])" } | ||||
| 317 | |||||
| 318 | sub o_monthint { "(?:0?[1-9]|1[012])" } | ||||
| 319 | |||||
| 320 | sub o_yearint { "(?:[0-9]{4}|[0-9]{2})" } | ||||
| 321 | |||||
| 322 | sub o_hour { "(?:[0-9][0-9]?)" } | ||||
| 323 | |||||
| 324 | sub o_minute { "(?:[0-9][0-9]?)" } | ||||
| 325 | |||||
| 326 | sub o_second { "(?:[0-9][0-9]?)" } | ||||
| 327 | |||||
| 328 | sub o_monthname { | ||||
| 329 | my $self = shift; | ||||
| 330 | "(?:" . join( | ||||
| 331 | "|", | ||||
| 332 | (map {my $meth="w_$_"; @{ $self->$meth }} @short_mons) | ||||
| 333 | ) . ")"; | ||||
| 334 | } | ||||
| 335 | |||||
| 336 | sub o_dow { | ||||
| 337 | my $self = shift; | ||||
| 338 | "(?:" . join( | ||||
| 339 | "|", | ||||
| 340 | (map {my $meth="w_$_"; @{ $self->$meth }} @dow) | ||||
| 341 | ) . ")"; | ||||
| 342 | } | ||||
| 343 | |||||
| 344 | sub o_durwords { | ||||
| 345 | my $self = shift; | ||||
| 346 | "(?:" . join( | ||||
| 347 | "|", | ||||
| 348 | @{ $self->w_year }, @{ $self->w_month }, @{ $self->w_week }, | ||||
| 349 | @{ $self->w_day }, | ||||
| 350 | @{ $self->w_hour }, @{ $self->w_minute }, @{ $self->w_second }, | ||||
| 351 | ) . ")"; | ||||
| 352 | } | ||||
| 353 | |||||
| 354 | sub o_dur { | ||||
| 355 | my $self = shift; | ||||
| 356 | "(?:(" . $self->o_num . "\\s*" . $self->o_durwords . "\\s*(?:,\\s*)?)+)"; | ||||
| 357 | } | ||||
| 358 | |||||
| 359 | sub odur_dur { | ||||
| 360 | my $self = shift; | ||||
| 361 | $self->o_dur; | ||||
| 362 | } | ||||
| 363 | |||||
| 364 | sub pdur_dur { | ||||
| 365 | my $self = shift; | ||||
| 366 | "(?:<odur_dur>)"; | ||||
| 367 | } | ||||
| 368 | |||||
| 369 | # durations less than a day | ||||
| 370 | sub o_timedurwords { | ||||
| 371 | my $self = shift; | ||||
| 372 | "(?:" . join( | ||||
| 373 | "|", | ||||
| 374 | @{ $self->w_hour }, @{ $self->w_minute }, @{ $self->w_second }, | ||||
| 375 | ) . ")"; | ||||
| 376 | } | ||||
| 377 | |||||
| 378 | sub o_timedur { | ||||
| 379 | my $self = shift; | ||||
| 380 | "(?:(" . $self->o_num . "\\s*" . $self->o_timedurwords . "\\s*(?:,\\s*)?)+)"; | ||||
| 381 | } | ||||
| 382 | |||||
| 383 | sub _parse_dur { | ||||
| 384 | 2 | 1.35ms | 2 | 14.9ms | # spent 14.8ms (1.66+13.2) within DateTime::Format::Alami::BEGIN@384 which was called:
# once (1.66ms+13.2ms) by Role::Tiny::_load_module at line 384 # spent 14.8ms making 1 call to DateTime::Format::Alami::BEGIN@384
# spent 36µs making 1 call to experimental::import |
| 385 | |||||
| 386 | my ($self, $str) = @_; | ||||
| 387 | |||||
| 388 | #say "D:dur=$str"; | ||||
| 389 | my %args; | ||||
| 390 | unless ($self->{_cache_re_parse_dur}) { | ||||
| 391 | my $o_num = $self->o_num; | ||||
| 392 | my $o_dw = $self->o_durwords; | ||||
| 393 | $self->{_cache_re_parse_dur} = qr/($o_num)\s*($o_dw)/ix; | ||||
| 394 | } | ||||
| 395 | unless ($self->{_cache_w_second}) { | ||||
| 396 | $self->{_cache_w_second} = $self->w_second; | ||||
| 397 | $self->{_cache_w_minute} = $self->w_minute; | ||||
| 398 | $self->{_cache_w_hour} = $self->w_hour; | ||||
| 399 | $self->{_cache_w_day} = $self->w_day; | ||||
| 400 | $self->{_cache_w_week} = $self->w_week; | ||||
| 401 | $self->{_cache_w_month} = $self->w_month; | ||||
| 402 | $self->{_cache_w_year} = $self->w_year; | ||||
| 403 | } | ||||
| 404 | while ($str =~ /$self->{_cache_re_parse_dur}/g) { | ||||
| 405 | my ($n, $unit) = ($1, $2); | ||||
| 406 | $n = $self->_parse_num($n); | ||||
| 407 | if ($unit ~~ $self->{_cache_w_second}) { | ||||
| 408 | $args{seconds} = $n; | ||||
| 409 | $self->{_uses_time} = 1; | ||||
| 410 | } elsif ($unit ~~ $self->{_cache_w_minute}) { | ||||
| 411 | $args{minutes} = $n; | ||||
| 412 | $self->{_uses_time} = 1; | ||||
| 413 | } elsif ($unit ~~ $self->{_cache_w_hour}) { | ||||
| 414 | $args{hours} = $n; | ||||
| 415 | $self->{_uses_time} = 1; | ||||
| 416 | } elsif ($unit ~~ $self->{_cache_w_day}) { | ||||
| 417 | $args{days} = $n; | ||||
| 418 | } elsif ($unit ~~ $self->{_cache_w_week}) { | ||||
| 419 | $args{weeks} = $n; | ||||
| 420 | } elsif ($unit ~~ $self->{_cache_w_month}) { | ||||
| 421 | $args{months} = $n; | ||||
| 422 | } elsif ($unit ~~ $self->{_cache_w_year}) { | ||||
| 423 | $args{years} = $n; | ||||
| 424 | } | ||||
| 425 | } | ||||
| 426 | DateTime::Duration->new(%args); | ||||
| 427 | } | ||||
| 428 | |||||
| 429 | sub _now_if_unset { | ||||
| 430 | my $self = shift; | ||||
| 431 | $self->a_now unless $self->{_dt}; | ||||
| 432 | } | ||||
| 433 | |||||
| 434 | sub _today_if_unset { | ||||
| 435 | my $self = shift; | ||||
| 436 | $self->a_today unless $self->{_dt}; | ||||
| 437 | } | ||||
| 438 | |||||
| 439 | sub a_now { | ||||
| 440 | my $self = shift; | ||||
| 441 | $self->{_dt} = DateTime->now( | ||||
| 442 | (time_zone => $self->{time_zone}) x !!defined($self->{time_zone}), | ||||
| 443 | ); | ||||
| 444 | $self->{_uses_time} = 1; | ||||
| 445 | } | ||||
| 446 | |||||
| 447 | # spent 961ms (15.1+946) within DateTime::Format::Alami::a_today which was called 3000 times, avg 320µs/call:
# 3000 times (15.1ms+946ms) by DateTime::Format::Alami::a_dateymd at line 469, avg 320µs/call | ||||
| 448 | 3000 | 523µs | my $self = shift; | ||
| 449 | $self->{_dt} = DateTime->today( | ||||
| 450 | 3000 | 7.08ms | 3000 | 946ms | (time_zone => $self->{time_zone}) x !!defined($self->{time_zone}), # spent 946ms making 3000 calls to DateTime::today, avg 315µs/call |
| 451 | ); | ||||
| 452 | 3000 | 6.94ms | $self->{_uses_time} = 0; | ||
| 453 | } | ||||
| 454 | |||||
| 455 | sub a_yesterday { | ||||
| 456 | my $self = shift; | ||||
| 457 | $self->a_today; | ||||
| 458 | $self->{_dt}->subtract(days => 1); | ||||
| 459 | } | ||||
| 460 | |||||
| 461 | sub a_tomorrow { | ||||
| 462 | my $self = shift; | ||||
| 463 | $self->a_today; | ||||
| 464 | $self->{_dt}->add(days => 1); | ||||
| 465 | } | ||||
| 466 | |||||
| 467 | # spent 2.46s (35.2ms+2.43) within DateTime::Format::Alami::a_dateymd which was called 3000 times, avg 821µs/call:
# 3000 times (35.2ms+2.43s) by DateTime::Format::Alami::CORE:match at line 94 of DateTime/Format/Alami/EN.pm, avg 821µs/call | ||||
| 468 | 3000 | 1.09ms | my ($self, $m) = @_; | ||
| 469 | 3000 | 2.35ms | 3000 | 961ms | $self->a_today; # spent 961ms making 3000 calls to DateTime::Format::Alami::a_today, avg 320µs/call |
| 470 | 3000 | 884µs | if (defined $m->{o_yearint}) { | ||
| 471 | my $year; | ||||
| 472 | if (length($m->{o_yearint}) == 2) { | ||||
| 473 | my $start_of_century_year = int($self->{_dt}->year / 100) * 100; | ||||
| 474 | $year = $start_of_century_year + $m->{o_yearint}; | ||||
| 475 | } else { | ||||
| 476 | $year = $m->{o_yearint}; | ||||
| 477 | } | ||||
| 478 | $self->{_dt}->set_year($year); | ||||
| 479 | } | ||||
| 480 | 3000 | 3.89ms | 3000 | 731ms | if (defined $m->{o_dayint}) { # spent 731ms making 3000 calls to DateTime::set_day, avg 244µs/call |
| 481 | $self->{_dt}->set_day($m->{o_dayint}); | ||||
| 482 | } | ||||
| 483 | 3000 | 922µs | if (defined $m->{o_monthint}) { | ||
| 484 | $self->{_dt}->set_month($m->{o_monthint}); | ||||
| 485 | } | ||||
| 486 | 3000 | 4.72ms | if (defined $m->{o_monthname}) { | ||
| 487 | 2 | 132µs | 2 | 53µs | # spent 34µs (14+19) within DateTime::Format::Alami::BEGIN@487 which was called:
# once (14µs+19µs) by Role::Tiny::_load_module at line 487 # spent 34µs making 1 call to DateTime::Format::Alami::BEGIN@487
# spent 19µs making 1 call to strict::unimport |
| 488 | 3000 | 4.45ms | my $maps = ${ ref($self) . '::MAPS' }; | ||
| 489 | 3000 | 5.39ms | 3000 | 735ms | $self->{_dt}->set_month($maps->{months}{lc $m->{o_monthname}}); # spent 735ms making 3000 calls to DateTime::set_month, avg 245µs/call |
| 490 | } | ||||
| 491 | } | ||||
| 492 | |||||
| 493 | sub a_which_dow { | ||||
| 494 | 2 | 553µs | 2 | 42µs | # spent 27µs (12+15) within DateTime::Format::Alami::BEGIN@494 which was called:
# once (12µs+15µs) by Role::Tiny::_load_module at line 494 # spent 27µs making 1 call to DateTime::Format::Alami::BEGIN@494
# spent 15µs making 1 call to strict::unimport |
| 495 | |||||
| 496 | my ($self, $m) = @_; | ||||
| 497 | $self->a_today; | ||||
| 498 | my $dow_num = $self->{_dt}->day_of_week; | ||||
| 499 | |||||
| 500 | my $maps = ${ ref($self) . '::MAPS' }; | ||||
| 501 | my $wanted_dow_num = $maps->{dow}{lc $m->{o_dow} }; | ||||
| 502 | |||||
| 503 | $self->{_dt}->add(days => ($wanted_dow_num-$dow_num)); | ||||
| 504 | |||||
| 505 | if ($m->{offset}) { | ||||
| 506 | $self->{_dt}->add(days => (7*$m->{offset})); | ||||
| 507 | } | ||||
| 508 | } | ||||
| 509 | |||||
| 510 | sub adur_dur { | ||||
| 511 | my ($self, $m) = @_; | ||||
| 512 | $self->{_dtdur} = $self->_parse_dur($m->{odur_dur}); | ||||
| 513 | } | ||||
| 514 | |||||
| 515 | sub a_dur_ago { | ||||
| 516 | my ($self, $m) = @_; | ||||
| 517 | $self->a_now; | ||||
| 518 | my $dur = $self->_parse_dur($m->{o_dur}); | ||||
| 519 | $self->{_dt}->subtract_duration($dur); | ||||
| 520 | } | ||||
| 521 | |||||
| 522 | sub a_dur_later { | ||||
| 523 | my ($self, $m) = @_; | ||||
| 524 | $self->a_now; | ||||
| 525 | my $dur = $self->_parse_dur($m->{o_dur}); | ||||
| 526 | $self->{_dt}->add_duration($dur); | ||||
| 527 | } | ||||
| 528 | |||||
| 529 | sub a_time { | ||||
| 530 | my ($self, $m) = @_; | ||||
| 531 | $self->_now_if_unset; | ||||
| 532 | $self->{_uses_time} = 1; | ||||
| 533 | my $hour = $m->{o_hour}; | ||||
| 534 | if ($m->{o_ampm}) { | ||||
| 535 | $hour += 12 if lc($m->{o_ampm}) eq 'pm' && $hour < 12; | ||||
| 536 | $hour = 0 if lc($m->{o_ampm}) eq 'am' && $hour == 12; | ||||
| 537 | } | ||||
| 538 | $self->{_dt}->set_hour($hour); | ||||
| 539 | $self->{_dt}->set_minute($m->{o_minute}); | ||||
| 540 | $self->{_dt}->set_second($m->{o_second} // 0); | ||||
| 541 | } | ||||
| 542 | |||||
| 543 | sub a_date_time { | ||||
| 544 | my ($self, $m) = @_; | ||||
| 545 | } | ||||
| 546 | |||||
| 547 | 1 | 17µs | 1; | ||
| 548 | # ABSTRACT: Parse human date/time expression (base class) | ||||
| 549 | |||||
| 550 | __END__ | ||||
# spent 2.53s (66.8ms+2.46) within DateTime::Format::Alami::CORE:match which was called 4000 times, avg 632µs/call:
# 2000 times (1.39ms+0s) by DateTime::Format::Alami::parse_datetime at line 220, avg 695ns/call
# 1000 times (65.2ms+2.46s) by DateTime::Format::Alami::parse_datetime at line 184, avg 2.53ms/call
# 1000 times (238µs+0s) by DateTime::Format::Alami::parse_datetime at line 204, avg 238ns/call | |||||
# spent 3.50ms within DateTime::Format::Alami::CORE:regcomp which was called 1000 times, avg 4µs/call:
# 1000 times (3.50ms+0s) by DateTime::Format::Alami::parse_datetime at line 184, avg 4µs/call |