perl, int номер секунды с 1970 года

Используя старый выпуск программного обеспечения EPrints, у меня есть эта функция EPrints::Time::datestring_to_timet, чтобы возвращать целое число секунд с 1970 года

  ######################################################################               
  =pod                                                                                 

  =item $xhtml = EPrints::Time::datestring_to_timet( $handle, $datevalue )             

  Returns an interger number of seconds since 1970-01-01:00:00                         

  $datevalue - in the format YYYY-MM-DDTHH:MM:SSZ                                      

  =cut                                                                                 
  ######################################################################               

  sub datestring_to_timet                                                              
  {                                                                                    
          my( $session, $datevalue, $short ) = @_;                                     

          my( $year,$mon,$day,$hour,$min,$sec ) = split /[- :TZ]/, $datevalue;         

          my $t = timegm_nocheck $sec||0,$min||0,$hour,$day,$mon-1,$year-1900;         

          return $t;                                                                   
  }

если использовать с годом в далеком будущем, я получил отрицательное число:

print EPrints::Time::datestring_to_timet(undef, "3017-9-20T12:00:00Z");

результат:

-26895412800

что здесь не так?

1 ответ

Решение

Я думаю, что этот пакет использует 32-разрядное целое число для представления секунд. Это ошибка, потому что она приводит к так называемой проблеме 2038 года - 19 января 2038 года число секунд с 1 января 1970 года достигает 231, и происходит целочисленное переполнение.

На самом деле, поскольку вы пытаетесь использовать год 3017, это переполнение происходит много раз (через каждые 68 лет).

Типичным решением этой проблемы является использование 64-битных чисел в течение нескольких секунд.

Другая возможность заключается в том, что вы используете старый 32-битный Perl. Обновление до 64-битного Perl (вместе с вашим пакетом) может исправить это само по себе.

В качестве альтернативы вы можете использовать пакет DateTime. Он поддерживает достаточно большие временные метки даже на 32-битном Perl, используя числа с плавающей запятой (53 бита).

$ perl -V:ivsize
ivsize='4';

$ perl -MDateTime::Format::RFC3339 -E'
   say DateTime::Format::RFC3339
      ->parse_datetime("3017-09-20T12:00:00Z")
          ->epoch'
33062817600
Другие вопросы по тегам