Как заставить DateTime :: Duration выводить только в днях? - PullRequest
11 голосов
/ 01 июля 2011

Этот код находит разницу между сегодняшним днем ​​и фиксированной датой.

#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;

use DateTime ();
use DateTime::Duration ();
use DateTime::Format::Strptime ();

my $date = "23/05-2022";

my $parser = DateTime::Format::Strptime->new(
    pattern     => '%d/%m-%Y',
    time_zone   => 'local',
    );

$date = $parser->parse_datetime($date);

my $today = DateTime->today(time_zone=>'local');

my $d = DateTime::Duration->new($today - $date);

print Dumper $d->delta_days;

Проблема в том, что выводится только -22 дня.

Если я сделаю print Dumper $d;, я тоже смогу увидеть -130 месяцев.

$VAR1 = bless( {
                 'seconds' => 0,
                 'minutes' => 0,
                 'end_of_month' => 'preserve',
                 'nanoseconds' => 0,
                 'days' => -22,
                 'months' => -130
               }, 'DateTime::Duration' );

Как мне заставить его выводить результат в днях?

Doing

print Dumper $d->delta_days + $d->delta_months*30;

не выглядит как элегантное решение.

Ответы [ 2 ]

25 голосов
/ 01 июля 2011

Сначала вам нужно сделать правильное вычитание. Существует delta_md, delta_days, delta_ms и subtract_datetime_absolute. В зависимости от того, какую единицу вы хотите позже, вам нужно выбрать правильное вычитание. Проблема заключается в том, что не каждая единица позже может быть конвертирована без информации о часовом поясе. Вот почему вам нужно выбрать правильный метод дельта.

Например, день может иметь 23 часа или 24 или 25 часов, в зависимости от часового пояса. Из-за этого вам нужно указать, как должно работать вычитание. Поскольку вы хотите дни спустя, вычитание должно быть сосредоточено на днях, а не на часах. Не используйте функцию перегрузки, потому что она подходит лучше всего.

Это означает, что вам нужно сделать delta_days вычитание.

my $dur = $date->delta_days($today);

Теперь $ dur является DateTime::Duration объектом. Вы должны знать, что он всегда старается лучше всего соответствовать дням, неделям, годам, месяцам, если это возможно. Это означает, что ваши дни будут разделены на недели и дни. Потому что это преобразование всегда константа.

Если вам не нужно это «наилучшее соответствие», вам нужно вызвать метод in_units и преобразовать его только в дни.

my $days = $dur->in_units('days');

Но, как я уже говорил, in_units может выполнять преобразование только там, где это возможно. Вызов с in_units('hours') не будет работать с этим объектом и просто вернет ноль, потому что вы не можете преобразовать дни в часы. Например, если вам нужны часы, вам нужно набрать delta_ms, и для этого объекта вы можете позвонить in_units('hours')

Полный пример:

#!/usr/bin/env perl
use 5.010;
use strict;
use warnings;

use DateTime;
use DateTime::Format::Strptime;

my $date = "23/05-2022";
my $parser = DateTime::Format::Strptime->new(
    pattern     => '%d/%m-%Y',
    time_zone   => 'local',
);
$date = $parser->parse_datetime($date);

my $today = DateTime->new(
    day   => 1,
    month => 7,
    year  => 2011,
    time_zone => 'local'
);  

my $dur = $date->delta_days($today);
say "Weeks:          ", $dur->weeks;
say "Days:           ", $dur->days;
say "Absolute Days:  ", $dur->in_units('days');
say "Absolute Hours: ", $date->delta_ms($today)->in_units('hours');

Вывод этой программы:

Weeks:          568
Days:           3
Absolute Days:  3979
Absolute Hours: 95496

И только для информации:
1) Вам не нужно загружать DateTime::Duration, его загружают DateTime.
2) Вам не нужно (). Эти модули являются ООП и ничего не экспортируют / не импортируют.

2 голосов
/ 01 июля 2011

Из краткого прочтения модуля DateTime doc я не верю, что

DateTime::Duration->new($today - $date)

будет делать то, что вы ожидаете.Я считаю, что вам нужно использовать

$dur = $today->subtract_datetime($date)

Тип $dur, однако, не сразу понятен из документации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...