package Mojolicious::Plugin::Vparam::Datetime;
use Mojo::Base -strict;
use Mojolicious::Plugin::Vparam::Common;
sub check_date($) {
return 'Value is not defined' unless defined $_[0];
return 'Value is not set' unless length $_[0];
return 0;
}
sub check_time($) {
return 'Value is not defined' unless defined $_[0];
return 'Value is not set' unless length $_[0];
return 0;
}
sub check_datetime($) {
return 'Value is not defined' unless defined $_[0];
return 'Value is not set' unless length $_[0];
return 0;
}
# Get a string and return DateTime or undef.
# Have a hack for parse Russian data and time.
sub parse_date($;$) {
my ($str, $tz) = @_;
return undef unless defined $str;
s{^\s+}{}, s{\s+$}{} for $str;
return undef unless length $str;
my $dt;
if( $str =~ m{^\d+$} ) {
$dt = DateTime->from_epoch( epoch => int $str, time_zone => 'local' );
} elsif( $str =~ m{^[+-]} ) {
my @relative = $str =~ m{
^([+-]) # sign
\s*
(?:(\d+)\s+)? # days
(?:(\d+):)?? # hours
(\d+) # minutes
(?::(\d+))? # seconds
$}x;
$dt = DateTime->now(time_zone => 'local');
my $sub = $relative[0] eq '+' ? 'add' : 'subtract';
$dt->$sub(days => int $relative[1]) if defined $relative[1];
$dt->$sub(hours => int $relative[2]) if defined $relative[2];
$dt->$sub(minutes => int $relative[3]) if defined $relative[3];
$dt->$sub(seconds => int $relative[4]) if defined $relative[4];
} else {
# RU format
if( $str =~ s{^(\d{1,2})\.(\d{1,2})\.(\d{1,4})(.*)$}{$3-$2-$1$4} ) {
my $cur_year = DateTime->now(time_zone => 'local')->strftime('%Y');
my $cur_len = length( $cur_year ) - 1;
# Less digit year
if( my ($year) = $str =~ m{^(\d{1,$cur_len})-} ) {
$str = substr($cur_year, 0, 4 - length($year)) . $str;
}
}
# If looks like time add it
$str = DateTime->now(time_zone => 'local')->strftime('%F ') . $str
if $str =~ m{^\d{2}:};
$dt = eval { DateTime::Format::DateParse->parse_datetime( $str ); };
return undef if $@;
}
return undef unless $dt;
# Always local timezone
$tz //= DateTime->now(time_zone => 'local')->strftime('%z');
$dt->set_time_zone( $tz );
return $dt;
}
sub register {
my ($class, $self, $app, $conf) = @_;
$app->vtype(
date =>
load => ['DateTime', 'DateTime::Format::DateParse'],
pre => sub { parse_date trim $_[1] },
valid => sub { check_date $_[1] },
post => sub {
return unless defined $_[1];
return ref($_[1]) && ( $conf->{date} || ! $_[2]->{blessed} )
? $_[1]->strftime( $conf->{date} )
: $_[1];
},
);
$app->vtype(
time =>
load => ['DateTime', 'DateTime::Format::DateParse'],
pre => sub { parse_date trim $_[1] },
valid => sub { check_time $_[1] },
post => sub {
return unless defined $_[1];
return ref($_[1]) && ( $conf->{time} || ! $_[2]->{blessed} )
? $_[1]->strftime( $conf->{time} )
: $_[1];
},
);
$app->vtype(
datetime =>
load => ['DateTime', 'DateTime::Format::DateParse'],
pre => sub { parse_date trim $_[1] },
valid => sub { check_datetime $_[1] },
post => sub {
return unless defined $_[1];
return ref($_[1]) && ( $conf->{datetime} || ! $_[2]->{blessed} )
? $_[1]->strftime( $conf->{datetime} )
: $_[1];
},
);
return;
}
1;