Dave Cross: Still Munging Data With Perl: Online event - Mar 17 Learn more

# ABSTRACT: Representation of Neo4j date/time related structs
$Neo4j::Bolt::DateTime::VERSION = '0.5000';
use strict;
# Full days since the Unix epoch
sub days {
my $self = shift;
if (defined $self->{epoch_secs}) { # DateTime / LocalDateTime
return int( $self->{epoch_secs} / 86400 ) - 1 if $self->{epoch_secs} < 0; # floor
return int( $self->{epoch_secs} / 86400 );
}
elsif (defined $self->{epoch_days}) { # Date
return $self->{epoch_days};
}
else { # Time / LocalTime
return undef;
}
}
# Seconds since the start of the day
sub seconds {
my $self = shift;
if (defined $self->{epoch_secs}) { # DateTime / LocalDateTime
return $self->{epoch_secs} % 86400;
}
elsif (defined $self->{epoch_days}) { # Date
return undef;
}
else { # Time / LocalTime
return int( $self->{nsecs} / 1e9 );
}
}
# Nanoseconds since the start of the second
sub nanoseconds {
my $self = shift;
if (defined $self->{epoch_secs}) { # DateTime / LocalDateTime
return $self->{nsecs};
}
elsif (defined $self->{epoch_days}) { # Date
return undef;
}
else { # Time / LocalTime
return $self->{nsecs} % 1e9;
}
}
sub epoch {
my $self = shift;
if (defined $self->{epoch_secs}) { # DateTime / LocalDateTime
return $self->{epoch_secs};
}
elsif (defined $self->{epoch_days}) { # Date
return $self->{epoch_days} * 86400;
}
else { # Time / LocalTime
return int( $self->{nsecs} / 1e9 );
}
}
my %TYPE = (
Date => 'DATE',
DateTime => 'ZONED DATETIME',
LocalDateTime => 'LOCAL DATETIME',
Time => 'ZONED TIME',
LocalTime => 'LOCAL TIME',
);
sub type {
$TYPE{ shift->{neo4j_type} }
}
sub tz_name {
my $self = shift;
if (defined $self->{offset_secs} && ! defined $self->{tz_name}) {
my $hours = $self->{offset_secs} / -3600;
return sprintf 'Etc/GMT%+i', $hours
if $hours == int $hours && $hours >= -14 && $hours <= 12;
}
return $self->{tz_name};
}
sub tz_offset {
shift->{offset_secs}
}
sub as_DateTime {
my ($self) = @_;
my $dt;
for ($self->{neo4j_type}) {
/^Date$/ && do {
return DateTime->from_epoch( epoch => $self->{epoch_days}*86400 );
};
/^DateTime$/ && do {
$dt = DateTime->from_epoch( epoch => $self->{epoch_secs} );
$dt->set_nanosecond( $self->{nsecs} // 0 );
$dt->set_time_zone(sprint("%+05d", $self->{offset_secs}/3600));
};
/^LocalDateTime$/ && do {
$dt = DateTime->from_epoch( epoch => $self->{epoch_secs} );
$dt->set_nanosecond( $self->{nsecs} // 0 );
$dt->set_time_zone('floating');
};
/^Time$/ && do {
$dt->DateTime->from_epoch( epoch => $self->{nsecs} / 1000000000 );
$dt->set_nanosecond($self->{nsecs} % 1000000000);
$dt->set_time_zone(sprint("%+05d", $self->{offset_secs}/3600));
};
/^LocalTime$/ && do {
$dt->DateTime->from_epoch( epoch => $self->{nsecs} / 1000000000 );
$dt->set_nanosecond($self->{nsecs} % 1000000000);
};
}
return $dt;
}
1;
__END__
=head1 NAME
Neo4j::Bolt::DateTime - Representation of a Neo4j date/time related structure
=head1 SYNOPSIS
$q = "RETURN datetime('2021-01-21T12:00:00-0500')";
$dt = ( $cxn->run_query($q)->fetch_next )[0];
$neo4j_type = $dt->{neo4j_type}; # Date, Time, DateTime, LocalDateTime, LocalTime
$epoch_days = $dt->{epoch_days};
$epoch_secs = $dt->{epoch_secs};
$secs = $dt->{secs};
$nanosecs = $dt->{nsecs};
$offset_secs = $dt->{offset_secs};
$perl_dt = $node->as_DateTime;
=head1 DESCRIPTION
L<Neo4j::Bolt::DateTime> instances are created by executing
a Cypher query that returns one of the date/time Bolt structures
from the Neo4j database.
They can also be created locally and passed to Neo4j as
query parameter. See L<Neo4j::Types::Generic/"DateTime">.
The values in the Bolt structures are described at L<https://neo4j.com/docs/bolt/current/bolt/structure-semantics/>. The Neo4j::Bolt::DateTime objects possess values
for the keys that are relevant to the underlying date/time structure.
This class conforms to the L<Neo4j::Types::DateTime> API,
which offers an object-oriented interface to the underlying
date/time component values. This is entirely optional to use.
Use the L</as_DateTime> method to obtain an equivalent L<DateTime>
object that is probably easier to use.
=head1 METHODS
This class provides the following methods defined by
L<Neo4j::Types::DateTime>:
=over
=item * L<B<days()>|Neo4j::Types::DateTime/"days">
=item * L<B<epoch()>|Neo4j::Types::DateTime/"epoch">
=item * L<B<nanoseconds()>|Neo4j::Types::DateTime/"nanoseconds">
=item * L<B<seconds()>|Neo4j::Types::DateTime/"seconds">
=item * L<B<type()>|Neo4j::Types::DateTime/"type">
=item * L<B<tz_name()>|Neo4j::Types::DateTime/"tz_name">
=item * L<B<tz_offset()>|Neo4j::Types::DateTime/"tz_offset">
=back
The following additional method is provided:
=over
=item as_DateTime()
$perl_dt = $dt->as_DateTime;
$node_id = $simple->{_node};
@labels = @{ $simple->{_labels} };
$value1 = $simple->{property1};
$value2 = $simple->{property2};
Obtain a L<DateTime> object equivalent to the Neo4j structure returned
by the database. Time and LocalTime objects generate a DateTime whose date is the
first day of the Unix epoch (1970-01-01).
=back
=head1 SEE ALSO
L<Neo4j::Bolt>, L<Neo4j::Types::DateTime>, L<DateTime>
=head1 AUTHOR
Mark A. Jensen
CPAN: MAJENSEN
=head1 LICENSE
This software is Copyright (c) 2024 by Mark A. Jensen.
This is free software, licensed under:
The Apache License, Version 2.0, January 2004
=cut