<commit_before>package PGObject::Type::DateTime;

use 5.006;
use Carp;
use strict;
use warnings;
use base qw(DateTime);
use DateTime::TimeZone;

=head1 NAME

PGObject::Type::DateTime - DateTime Wrappers for PGObject

=head1 VERSION

Version 0.01

=cut

our $VERSION = '0.01';
our $default_tz = DateTime::TimeZone->new(name => 'UTC');


=head1 SYNOPSIS

   PGObject::Type::DateTime->register();

Now all Datetime, Timestamp, and TimestampTZ types are returned 
returned as datetime objects.  Date and time modules may require subclasses
to serialize properly to the database.

=head1 DESCRIPTION

This module provides a basic wrapper around DateTime to allow PGObject-framework
types to automatically tie date/time related objects, but we handle date and
timestamp formats in our from_db routines.

This specific module only supports the ISO YMD datestyle.  The MDY or DMY 
datestyles may be usable in future versions but datestyles other than ISO raise
ambiguity issues, sufficient that they cannot always even be used in PostgreSQL as input.

This module also provides basic default handling.  Times are assigned a date of
'0001-01-01' and dates are assigned a time of midnight.  Whether this is set is
persisted, along with whether timezones are set, and these are returned to a 
valid ISO YMD format on export, if a date component was initially set.

This means you can use this for general math without worrying about many of the
other nicities.  Parsing ISO YMD dates and standard times (24 hr format) is 
supported via the from_db interface, which also provides a useful way of handing
dates in.

=head1 SUBROUTINES/METHODS

=head2 register

By default registers 'date', 'time', 'timestamp', and 'timestamptz'

=cut

sub register {
    my $self = shift @_;
    croak "Can't pass reference to register \n".
          "Hint: use the class instead of the object" if ref $self;
    my %args = @_;
    my $registry = $args{registry};
    $registry ||= 'default';
    my $types = $args{types};
    $types = ['date', 'time', 'timestamp', 'timestamptz'] 
           unless defined $types and @$types;
    for my $type (@$types){
        my $ret = 
            PGObject->register_type(registry => $registry, pg_type => $type,
                                  perl_class => $self);
        return $ret unless $ret;
    }
    return 1;
}

=head2 from_db

Parses a date from YYYY-MM-DD format and generates the new object based on it.

=cut

sub from_db {
    my ($class, $value) = @_;
    my ($year, $month, $day, $hour, $min, $sec, $nanosec, $tz);
    $value =~ /(\d{4})-(\d{2})-(\d{2})/ 
          and ($year, $month, $day) = ($1, $2, $3);
    $value =~ /(\d+):(\d+):([0-9.]+)([+-]\d+)?/ 
          and ($hour, $min, $sec, $tz) = ($1, $2, $3, $4);
    $tz ||= $default_tz; # defaults to UTC
    $tz .= '00' if $tz =~ /([+-]\d{2}$)/;
    ($sec, $nanosec) = split /\./, $sec if $sec;
    $nanosec *= 1000 if $nanosec; # no need to worry about truth here
                                # since 0 * anything is.... --CT
    $nanosec ||= 0;
    my %args = ();
    $args{year} = ($year || 1);
    $args{month} = ($month || 1);
    $args{day} = ($day || 1);
    $args{hour} = ($hour || 0);
    $args{minute} = ($min || 0);
    $args{second} = ($sec || 0);
    $args{nanosecond} = ($nanosec || 0);
    $args{time_zone} = $tz;
    my $self = __PACKAGE__->new(%args);
    $self->{_pgobject_is_date} = 1 if $year;
    $self->{_pgobject_is_time} = 1 if defined $hour;
    return $self;
}

=head2 to_db

Returns the date in YYYY-MM-DD format.

=cut<commit_msg>fixing subclassing and from_db<commit_after>package PGObject::Type::DateTime;

use 5.006;
use Carp;
use strict;
use warnings;
use base qw(DateTime);
use DateTime::TimeZone;

=head1 NAME

PGObject::Type::DateTime - DateTime Wrappers for PGObject

=head1 VERSION

Version 0.01

=cut

our $VERSION = '0.01';
our $default_tz = DateTime::TimeZone->new(name => 'UTC');


=head1 SYNOPSIS

   PGObject::Type::DateTime->register();

Now all Datetime, Timestamp, and TimestampTZ types are returned 
returned as datetime objects.  Date and time modules may require subclasses
to serialize properly to the database.

=head1 DESCRIPTION

This module provides a basic wrapper around DateTime to allow PGObject-framework
types to automatically tie date/time related objects, but we handle date and
timestamp formats in our from_db routines.

This specific module only supports the ISO YMD datestyle.  The MDY or DMY 
datestyles may be usable in future versions but datestyles other than ISO raise
ambiguity issues, sufficient that they cannot always even be used in PostgreSQL as input.

This module also provides basic default handling.  Times are assigned a date of
'0001-01-01' and dates are assigned a time of midnight.  Whether this is set is
persisted, along with whether timezones are set, and these are returned to a 
valid ISO YMD format on export, if a date component was initially set.

This means you can use this for general math without worrying about many of the
other nicities.  Parsing ISO YMD dates and standard times (24 hr format) is 
supported via the from_db interface, which also provides a useful way of handing
dates in.

=head1 SUBROUTINES/METHODS

=head2 register

By default registers 'date', 'time', 'timestamp', and 'timestamptz'

=cut

sub register {
    my $self = shift @_;
    croak "Can't pass reference to register \n".
          "Hint: use the class instead of the object" if ref $self;
    my %args = @_;
    my $registry = $args{registry};
    $registry ||= 'default';
    my $types = $args{types};
    $types = ['date', 'time', 'timestamp', 'timestamptz'] 
           unless defined $types and @$types;
    for my $type (@$types){
        my $ret = 
            PGObject->register_type(registry => $registry, pg_type => $type,
                                  perl_class => $self);
        return $ret unless $ret;
    }
    return 1;
}

=head2 from_db

Parses a date from YYYY-MM-DD format and generates the new object based on it.

=cut

sub from_db {
    my ($class, $value) = @_;
    my ($year, $month, $day, $hour, $min, $sec, $nanosec, $tz);
    $value =~ /(\d{4})-(\d{2})-(\d{2})/ 
          and ($year, $month, $day) = ($1, $2, $3);
    $value =~ /(\d+):(\d+):([0-9.]+)([+-]\d+)?/ 
          and ($hour, $min, $sec, $tz) = ($1, $2, $3, $4);
    $tz ||= $default_tz; # defaults to UTC
    $tz .= '00' if $tz =~ /([+-]\d{2}$)/;
    ($sec, $nanosec) = split /\./, $sec if $sec;
    $nanosec *= 1000 if $nanosec; # no need to worry about truth here
                                # since 0 * anything is.... --CT
    $nanosec ||= 0;
    my %args = ();
    $args{year} = ($year || 1);
    $args{month} = ($month || 1);
    $args{day} = ($day || 1);
    $args{hour} = ($hour || 0);
    $args{minute} = ($min || 0);
    $args{second} = ($sec || 0);
    $args{nanosecond} = ($nanosec || 0);
    $args{time_zone} = $tz;
    my $self = "$class"->new(%args);
    $self->{_pgobject_is_date} = 1 if $year;
    $self->{_pgobject_is_time} = 1 if defined $hour;
    return $self;
}

=head2 to_db

Returns the date in YYYY-MM-DD format.

=cut
{'fraction_non_alphanumeric': 0.13580073177596397, 'fraction_numerical': 0.016605685336335493, 'mean_word_length': 3.1033487297921476, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6412138', 'n_tokens_mistral': 2408, 'n_tokens_neox': 2308, 'n_words': 878}