Этот вопрос уже имеет хороший ответ , но я хочу предоставить ответ, показывающий , почему вычисление разницы в секундах НЕПРАВИЛЬНО (когда мы используем форматированные / локальные даты, а чем плавающие даты).
Меня огорчает, как много предложений говорят людям вычитать секунды. (Этот вопрос был первым попаданием 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.
Цитирование документации (delta_days () vs subtract_datetime ()):
дата против даты и времени математика
Если вас интересует только часть даты (календаря) даты, вы
следует использовать delta_md () или delta_days (), а не subtract_datetime ().
Это даст предсказуемые, неудивительные результаты, свободные от
Осложнения, связанные с ДСТ.
Итог: не различайте секунды, если вы используете DateTime. Если вы не уверены, какую платформу даты использовать, используйте DateTime, это здорово.