diff --git a/example/ntptime.pl b/example/ntptime.pl new file mode 100644 index 0000000..06ff3d0 --- /dev/null +++ b/example/ntptime.pl @@ -0,0 +1,25 @@ +#!/usr/bin/env perl + +use strict; +use warnings; +use v5.10; + +use DateTime::Format::Epoch::NTP; +use Socket; + +my $hostname = 'pool.ntp.org'; +socket(SOCKET, PF_INET, SOCK_DGRAM, getprotobyname('udp')); +my $ipaddr = inet_aton($hostname); +my $portaddr = sockaddr_in(123, $ipaddr); +my $bstr = "\010" . "\0"x47; +send(SOCKET, $bstr, 0, $portaddr); +$portaddr = recv(SOCKET, $bstr, 1024, 0); +my @words = unpack("N12",$bstr); +my $ntptime = $words[10]; + +my $dt = DateTime::Format::Epoch::NTP->parse_datetime( $ntptime ); + +$dt->set_time_zone('Europe/Moscow'); + +say "NTPTime $ntptime is in Moscow: " . $dt->hms; +say $dt->datetime; diff --git a/lib/DateTime/Format/Epoch/NTP.pm b/lib/DateTime/Format/Epoch/NTP.pm new file mode 100644 index 0000000..9768f12 --- /dev/null +++ b/lib/DateTime/Format/Epoch/NTP.pm @@ -0,0 +1,88 @@ +package DateTime::Format::Epoch::NTP; + +use strict; +use warnings; + +use vars qw($VERSION @ISA); + +$VERSION = '0.14'; + +use DateTime; +use DateTime::Format::Epoch; + +@ISA = qw/DateTime::Format::Epoch/; + +my $epoch = DateTime->new( year => 1900, month => 1, day => 1, + time_zone => 'UTC' ); + +sub new { + my $class = shift; + + return $class->SUPER::new( epoch => $epoch, + unit => 'seconds', + type => 'int', + skip_leap_seconds => 1 ); +} + +1; +__END__ + +=head1 NAME + +DateTime::Format::Epoch::NTP - Convert DateTimes to/from NTP epoch seconds + +=head1 SYNOPSIS + + use DateTime::Format::Epoch::NTP; + + my $dt = DateTime::Format::Epoch::NTP->parse_datetime( 3629861151 ); + print $dt->datetime; # '2015-01-10T06:45:51' + + my $formatter = DateTime::Format::Epoch::NTP->new(); + my $dt = DateTime->new( year => 2015, month => 1, day => 10, + time_zone => 'Europe/Amsterdam' ); + print $formatter->format_datetime($dt); # '3629833200' + +=head1 DESCRIPTION + +This module can convert a DateTime object (or any object that can be +converted to a DateTime object) to the number of seconds since the NTP +epoch. + +The NTP epoch uses UTC; if you parse an NTP date your DateTime object +will be using the UTC timezone. + +=head1 METHODS + +Most of the methods are the same as those in L. +The only difference is the constructor. + +=over 4 + +=item * new() + +Constructor of the formatter/parser object. It has no parameters. + +=back + +=head1 SUPPORT + +Support for this module is provided via the datetime@perl.org email +list. See http://lists.perl.org/ for more details. + +=head1 AUTHOR + +Eugene van der Pijll + +=head1 COPYRIGHT + +Copyright (c) 2015 Michiel Beijen. This program is free software; you can +redistribute it and/or modify it under the same terms as Perl itself. + +=head1 SEE ALSO + +L + +datetime@perl.org mailing list + +=cut diff --git a/t/502_format.t b/t/502_format.t index 01ea850..f1971cf 100644 --- a/t/502_format.t +++ b/t/502_format.t @@ -6,6 +6,7 @@ use Test::More qw/no_plan/; use DateTime; use DateTime::Format::Epoch::JD; use DateTime::Format::Epoch::MJD; +use DateTime::Format::Epoch::NTP; use DateTime::Format::Epoch::TJD; use DateTime::Format::Epoch::RJD; use DateTime::Format::Epoch::Lilian; @@ -16,6 +17,7 @@ my $dt = DateTime->new( year => 2004, month => 8, day => 28 ); my %dates = ( JD => 2453245.5, MJD => 53245, + NTP => 3302640000, TJD => 13245, RJD => 53245.5, Lilian => 154086, diff --git a/t/701_load.t b/t/701_load.t new file mode 100644 index 0000000..a39b557 --- /dev/null +++ b/t/701_load.t @@ -0,0 +1,5 @@ +# t/001_load.t - check module loading + +use Test::More tests => 1; + +BEGIN { use_ok( 'DateTime::Format::Epoch::NTP' ); } diff --git a/t/702_format.t b/t/702_format.t new file mode 100644 index 0000000..cff9184 --- /dev/null +++ b/t/702_format.t @@ -0,0 +1,19 @@ +use strict; +BEGIN { $^W = 1 } + +use Test::More tests => 4; +use DateTime; +use DateTime::Format::Epoch::NTP; + +my $f = DateTime::Format::Epoch::NTP->new(); + +isa_ok($f, 'DateTime::Format::Epoch::NTP' ); + +my $dt = DateTime->new( year => 2015, month => 1, day => 10, +time_zone => 'Europe/Amsterdam' ); +is($f->format_datetime($dt), '3629833200', 'Format DateTime as NTP epoch time'); + +$dt = DateTime::Format::Epoch::NTP->parse_datetime( 3629848426 ); + +is($dt->iso8601(), '2015-01-10T03:13:46', 'read NTP time'); +is($dt->time_zone_long_name(), 'UTC', 'NPT time timezone is UTC');