Этот вопрос уже имеет хороший answer, но я хочу, чтобы предоставить ответ, показывающий почему вычисления разницы в секундах НЕПРАВИЛЬНО (когда мы используем, отформатированные/местные даты, а не плавающие даты).
Я нахожу, что это огорчает, сколько предложений говорят людям, чтобы вычесть секунды. (Этот вопрос стал первым хитом Google для моего поиска, поэтому мне все равно, сколько ему лет.)
Я сам сделал эту ошибку и задался вопросом, почему приложение внезапно (за выходные) покажет неиспользуемые времена , Поэтому я надеюсь, что этот код поможет людям (кто может столкнуться с такой проблемой) понять, почему этот подход неверен и помочь им избежать этой ошибки.
Вот полный пример, который не содержит «...» в какой-то ключевой момент (потому что если вы вставляете две даты в том же часовом поясе, вы можете не увидеть ошибку).
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
use DateTime;
# Friday, Oct 31
my $dt1 = DateTime->new(
time_zone => "America/Chicago",
year => 2014,
month => 10,
day => 31,
);
my $date1 = $dt1->strftime("%Y-%m-%d (%Z %z)");
# Monday, Nov 01
my $dt2 = $dt1->clone->set(month => 11, day => 3);
my $date2 = $dt2->strftime("%Y-%m-%d (%Z %z)");
# Friday, Mar 06
my $dt3 = DateTime->new(
time_zone => "America/Chicago",
year => 2015,
month => 3,
day => 6,
);
my $date3 = $dt3->strftime("%Y-%m-%d (%Z %z)");
# Monday, Mar 09
my $dt4 = $dt3->clone->set(day => 9);
my $date4 = $dt4->strftime("%Y-%m-%d (%Z %z)");
# CDT -> CST
print "dt1:\t$dt1 ($date1):\t".$dt1->epoch."\n";
print "dt2:\t$dt2 ($date2):\t".$dt2->epoch."\n";
my $diff1_duration = $dt2->subtract_datetime_absolute($dt1);
my $diff1_seconds = $diff1_duration->seconds;
my $diff1_seconds_days = $diff1_seconds/86400;
print "diff:\t$diff1_seconds seconds = $diff1_seconds_days days (WRONG)\n";
my $diff1_seconds_days_int = int($diff1_seconds_days);
print "int:\t$diff1_seconds_days_int days (RIGHT in this case)\n";
print "days\t".$dt2->delta_days($dt1)->days." days (RIGHT)\n";
print "\n";
# CST -> CDT
print "dt3:\t$dt3 ($date3):\t".$dt3->epoch."\n";
print "dt4:\t$dt4 ($date4):\t".$dt4->epoch."\n";
my $diff3_duration = $dt4->subtract_datetime_absolute($dt3);
my $diff3_seconds = $diff3_duration->seconds;
my $diff3_seconds_days = $diff3_seconds/86400;
print "diff:\t$diff3_seconds seconds = $diff3_seconds_days days (WRONG)\n";
my $diff3_seconds_days_int = int($diff3_seconds_days);
print "int:\t$diff3_seconds_days_int days (WRONG!!)\n";
print "days\t".$dt4->delta_days($dt3)->days." days (RIGHT)\n";
print "\n";
Выход:
dt1: 2014-10-31T00:00:00 (2014-10-31 (CDT -0500)): 1414731600
dt2: 2014-11-03T00:00:00 (2014-11-03 (CST -0600)): 1414994400
diff: 262800 seconds = 3.04166666666667 days (WRONG)
int: 3 days (RIGHT in this case)
days 3 days (RIGHT)
dt3: 2015-03-06T00:00:00 (2015-03-06 (CST -0600)): 1425621600
dt4: 2015-03-09T00:00:00 (2015-03-09 (CDT -0500)): 1425877200
diff: 255600 seconds = 2.95833333333333 days (WRONG)
int: 2 days (WRONG!!)
days 3 days (RIGHT)
Примечания:
- Опять же, я использую местные даты. Если вы используете плавающие даты, у вас не будет этой проблемы - просто потому, что ваши даты остаются в одном и том же часовом поясе.
- Оба диапазон времени в моем примере идет от пятницы до понедельника, так что разница в дни 3, а не 3,04 ... и, конечно, не 2,95 ...
- Включения поплавка в целое число, используя int() (как это было предложено в answer) просто неверно, как показано в примере.
- Я понимаю, что округление разницы в секундах также вернет правильные результаты в моем примере, но я чувствую, что это все еще неправильно. Вы будете вычислять разницу в день 2 (при большом значении 2) и, поскольку это большое значение 2, превратите его в 3. До тех пор, пока DateTime предоставляет функциональность, используйте DateTime.
Цитирование documentation (delta_days() против subtract_datetime()):
дата против даты и времени по математике
Если вы заботитесь только о дате (календарь) части даты-времени, вы следует использовать либо delta_md(), либо delta_days(), а не subtract_datetime(). Это даст предсказуемые, неудивительные результаты, свободные от осложнения, связанные с ДСТ.
Нижняя строка: не используйте интервалы секунд, если вы используете DateTime. Если вы не знаете, какую фреймворк даты использовать, используйте DateTime, это потрясающе.
Вы не можете просто преобразовать даты в секунды и рассчитать разницу? – TStamper
Пожалуйста, не повторяйте ошибки вычисления разницы в секундах. См. [Мой ответ] (http://stackoverflow.com/a/26732755/664132) для примера. – basic6