2016-06-16 13 views
6

Próbuję obliczyć liczbę dni kalendarzowych między dwiema datami wyodrębnionymi z bazy danych. Pomyślałem, że konwersja dat na sekundy będzie prostym i poprawnym rozwiązaniem.Perl: Oblicz liczbę dni przez konwersję na sekundy

#!/usr/bin/perl 
use warnings; 
use strict; 
use POSIX qw(strftime); 
use Date::Parse; 

my $minDate = "2016-03-27"; 
my $maxDate = "2016-06-15"; 

print "Format as extracted from db: mindate: $minDate and maxdate: $maxDate\n"; 

my ($dbYear,$dbMonth,$dbDay) = split ('-', $minDate); 
my $datum = "$dbYear$dbMonth$dbDay"; 
my $minDateSec = str2time($datum); 

($dbYear,$dbMonth,$dbDay) = split ('-', $maxDate); 
$datum = "$dbYear$dbMonth$dbDay"; 
my $maxDateSec = str2time($datum); 

my $numCalDaysSec = ($maxDateSec-$minDateSec)/86400; 

print "Min date in Seconds: $minDateSec\n"; 
print "Max date in Seconds: $maxDateSec\n"; 
print "Num days: $numCalDaysSec\n"; 

Początkowo myślałem, że metoda ta dostarczyła mi wiarygodnych wyników:

bash-3.2$ ./testNumDays.pl 
As extracted from db: mindate: 2016-06-14 and maxdate: 2016-06-15 
Min date in Seconds: 1465855200 
Max date in Seconds: 1465941600 
Num days: 1 
bash-3.2$ ./testNumDays.pl 
As extracted from db: mindate: 2016-05-31 and maxdate: 2016-06-15 
Min date in Seconds: 1464645600 
Max date in Seconds: 1465941600 
Num days: 15 
bash-3.2$ ./testNumDays.pl 
As extracted from db: mindate: 2016-03-28 and maxdate: 2016-06-15 
Min date in Seconds: 1459116000 
Max date in Seconds: 1465941600 
Num days: 79 
bash-3.2$ ./testNumDays.pl 
As extracted from db: mindate: 2016-03-27 and maxdate: 2016-06-15 
Min date in Seconds: 1459033200 
Max date in Seconds: 1465941600 
Num days: 79.9583333333333 
bash-3.2$ 

Oczywiście, liczba dat kalendarzowych od daty powinien być liczbą całkowitą. Mmmm, co robię źle? Dlaczego przeliczanie na sekundy nie jest niezawodne?

Ponieważ jestem nowicjuszem Perl, prawdopodobnie przeoczyłem oczywistość. Każda pomoc jest zatem mile widziane.

+2

Dlaczego nie zrobić tego bezpośrednio w zapytaniu do bazy danych? – ThisSuitIsBlackNot

+1

W rzeczywistości uczę się obsługiwać daty w Perlu. Ciekawość i zapoznanie się z Perlem są głównymi motorami. –

+1

Wygląda jak błąd czasu letniego. Nie sprawdziłem mojego kalendarza, aby sprawdzić, czy to jest problem. – hymie

Odpowiedz

7

Jednym ze sposobów jest użycie modułu Time::Piece Rdzeń:

use warnings; 
use strict; 
use Time::Piece qw(); 

my $t1 = Time::Piece->strptime('2016-03-27', '%Y-%m-%d'); 
my $t2 = Time::Piece->strptime('2016-06-15', '%Y-%m-%d'); 
my $seconds = $t2 - $t1; 
print $seconds->days(), "\n"; 

__END__ 

80 
5

Alternatywą jest DateTime. Nie jest w Core, ale często jest bardzo przydatny. Ponieważ nie analizuje dat, szybko stworzyliśmy własną funkcję analizy składni.

use strict; 
use warnings; 
use DateTime; 
my $minDate = "2016-03-27"; 
my $maxDate = "2016-06-15"; 

sub parse { 
    my $date = shift; 

    my ($y, $m, $d) = split /-/, $date; 

    return DateTime->new(year => $y, month => $m, day => $d); 
} 

my $days = parse($minDate)->delta_days(parse($maxDate))->in_units('days'); 
print $days; 

__END__ 

80 
+2

Parsuje daty. DateTime :: Format :: Strptime jest najbardziej elastyczny, ale DateTime :: Format :: ISO8601 jest prawdopodobnie najprostszy w tym przypadku. – ikegami

+0

@ikegami tak, jeśli załadujesz jedną z nich. Ale to [mówi, że ten moduł nie parsuje date_] (https://metacpan.org/pod/DateTime#Parsing-Dates) ...;) – simbabque

+0

Według tej logiki, DateTime nie wie nic o strefach czasowych, ponieważ wszystkie ta informacja o strefie czasowej znajduje się w innej dystrybucji. To raczej głupie. – ikegami

3

Dokonujesz błędnego założenia, że ​​każdy dzień ma 86 400 sekund.

Przejdź do http://www.timeanddate.com/time/dst/2016.html i spójrz na wszystkie miejsca, w których czas letni zaczyna się w dniu 27 marca 2016 r. Ten dzień nie wynosi 86 400 sekund.

Powiązane problemy