DateTime-Format-Natural

 view release on metacpan or  search on metacpan

lib/DateTime/Format/Natural.pm  view on Meta::CPAN

{
    my ($error) = @_;
    chomp $error;
    croak $error;
},
    stack_skip => 2,
);

sub new
{
    my $class = shift;

    my $self = bless {}, ref($class) || $class;

    $self->_init_check(@_);
    $self->_init(@_);

    return $self;
}

sub _init
{
    my $self = shift;
    my %opts = @_;

    my %presets = (
        lang           => 'en',
        format         => 'd/m/y',
        demand_future  =>  false,
        prefer_future  =>  false,
        time_zone      => 'floating',
        calendar_class =>  undef,
    );
    foreach my $opt (keys %presets) {
        $self->{ucfirst $opt} = $presets{$opt};
    }
    foreach my $opt (keys %opts) {
        if (defined $opts{$opt}) {
            $self->{ucfirst $opt} = $opts{$opt};
        }
    }
    $self->{Daytime} = $opts{daytime} || {};

    my $mod = join '::', (__PACKAGE__, 'Lang', uc $self->{Lang});
    eval "require $mod; 1" or die $@;

    $self->{data} = $mod->__new();
    $self->{grammar_class} = $mod;

    $self->{mode} = '';
}

sub _init_check
{
    my $self = shift;

    validate(@_, {
        calendar_class => {
            type => SCALAR | UNDEF,
            optional => true,
            callbacks => {
                'calendar class exists' => sub
                {
                    my $class = shift;
                    return true unless defined $class;
                    return $class eq 'DateTime::Calendar::Julian' && eval "require $class; 1";
                },
            },
        },
        demand_future => {
            # SCALARREF due to boolean.pm's implementation
            type => BOOLEAN | SCALARREF,
            optional => true,
            callbacks => {
                'mutually exclusive' => sub
                {
                    return true unless exists $_[1]->{prefer_future};
                    die "prefer_future provided\n";
                },
            },
        },
        lang => {
            type => SCALAR,
            optional => true,
            regex => qr!^(?:en)$!i,
        },
        format => {
            type => SCALAR,
            optional => true,
            regex => qr!^(?:
                           (?: (?: [dmy]{1,4}[-./] ){2}[dmy]{1,4} )
                             |
                           (?: [dm]{1,2}/[dm]{1,2} )
                         )$!ix,
        },
        prefer_future => {
            # SCALARREF due to boolean.pm's implementation
            type => BOOLEAN | SCALARREF,
            optional => true,
            callbacks => {
                'mutually exclusive' => sub
                {
                    return true unless exists $_[1]->{demand_future};
                    die "demand_future provided\n";
                },
            },
        },
        time_zone => {
            type => SCALAR | OBJECT,
            optional => true,
            callbacks => {
                'valid timezone' => sub
                {
                    my $val = shift;
                    if (blessed($val)) {
                        return $val->isa('DateTime::TimeZone');
                    }
                    else {
                        eval { DateTime::TimeZone->new(name => $val) };
                        return !$@;
                    }
                }
            },
        },
        daytime => {
            type => HASHREF,
            optional => true,
            callbacks => {
                'valid daytime' => sub
                {
                    my $href = shift;
                    my %daytimes = map { $_ => true } qw(morning afternoon evening);
                    if (any { !$daytimes{$_} } keys %$href) {
                        die "spelling of daytime\n";
                    }
                    elsif (any { !defined $href->{$_} } keys %$href) {
                        die "undefined hour\n";
                    }
                    elsif (any { $href->{$_} !~ /^\d{1,2}$/ } keys %$href) {
                        die "not a valid number\n";
                    }
                    elsif (any { $href->{$_} < 0 || $href->{$_} > 23 } keys %$href) {
                        die "hour out of range\n";
                    }
                    else {
                        return true;
                    }
                }
            },
        },
        datetime => {
            type => OBJECT,
            optional => true,
            callbacks => {
                'valid object' => sub
                {
                    my $obj = shift;
                    blessed($obj) && $obj->isa('DateTime');
                }
            },
        },
    });
}

sub _init_vars
{
    my $self = shift;

    delete @$self{qw(keyword modified postprocess)};
}

sub parse_datetime
{
    my $self = shift;

    $self->_parse_init(@_);

    $self->{input_string} = $self->{date_string};

    $self->{mode} = 'parse';

    my $date_string = $self->{date_string};

    $self->_rewrite(\$date_string);

    my ($formatted) = $date_string =~ $self->{data}->__regexes('format');
    my %count = $self->_count_separators($formatted);

    $self->{tokens} = [];
    $self->{traces} = [];

    if ($self->_check_formatted('ymd', \%count)) {
        my $dt = $self->_parse_formatted_ymd($date_string, \%count);
        return $dt if blessed($dt);
    }
    elsif ($self->_check_formatted('md', \%count)) {
        my $dt = $self->_parse_formatted_md($date_string);
        return $dt if blessed($dt);

        if ($self->{Prefer_future} || $self->{Demand_future}) {
            $self->_advance_future('md');
        }
    }
    elsif ($date_string =~ /^(\d{4}(?:-\d{2}){0,2})T(\d{2}(?::\d{2}){0,2})(?:[.,](\d+))?(Z|[+-]\d{2}(?::?\d{2})?)?$/) {
        my ($date, $time, $fractional, $tz) = ($1, $2, $3, $4);
        my %args;

        if (defined $tz) {
            if ($tz eq 'Z') {
                $self->{datetime}->set_time_zone('UTC');
            } elsif ($tz =~ /^([+-])(\d{2})$/) {
                $tz = "$1$2:00";
            } else {
                $tz =~ s/^([+-])(\d{2}):?(\d{2})$/$1$2:$3/;



( run in 0.671 second using v1.01-cache-2.11-cpan-483215c6ad5 )