Полное ручное преобразование времени эпохи в дату и время - PullRequest
0 голосов
/ 07 июня 2019

Я написал этот Perl-скрипт для преобразования даты и времени из файлов в время эпохи.

Исходный формат даты: dd-mm-yyyy hh:MM:ss

Причина, по которой я это делаю, заключается в том, что мне приходится писатьэти значения в базу данных и только целочисленные значения принимаются столбцами.

use strict;
use warnings;
use Time::Local;

$datestring = '07-06-2019 21:13:00';

my ($dd, $mm, $yyyy, $hh, $min, $sec) = split /\W+/, $datestring;

my $epoch = timelocal($sec,$min,$hh,$dd,$mm-1,$yyyy-1900);
print("$epoch\n");

, что переводит дату 07-06-2019 21:13:00 в 1559934780

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

Существует ли полностью ручной метод, просто используя калькулятор / расчет для перевода времени эпохи обратно в удобочитаемую дату и время?

Ответы [ 2 ]

3 голосов
/ 07 июня 2019

Ядро Время :: Часть может конвертировать в обоих направлениях просто для вашего местного часового пояса.

use strict;
use warnings;
use Time::Piece;

my $datestring = '07-06-2019 21:13:00';
my $time = localtime->strptime($datestring, '%d-%m-%Y %H:%M:%S');
my $epoch = $time->epoch;

...

my $time = localtime($epoch);
my $datestring = $time->strftime('%d-%m-%Y %H:%M:%S');

См. Любую стандартную справочную страницу strftime или strptime для спецификаторов формата, которые обычно принимаются - к сожалению, те, которые принимает Time :: Piece, не документированы.


Без доступа к Time :: Piece, который является ядром начиная с Perl 5.10, вы можете использовать встроенную функцию localtime , она немного сложнее (например, timelocal).

use strict;
use warnings;
my $epoch = 1559934780;
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime $epoch;
my $date_string = sprintf '%02d-%02d-%04d %02d:%02d:%02d',
  $mday, $mon+1, $year+1900, $hour, $min, $sec;
2 голосов
/ 08 июня 2019

В очень ранних версиях DateTime.pm вы найдете подпрограмму _rd2greg, которую я написал как jd2greg для более раннего и долгого несуществующего проекта Reefknot Рича Боуэна. Это занимает несколько дней с начала года 1 и производит год, месяц и день. Вы можете взять время эпохи, деленное на 86400 (секунд в дне), и добавить 719163 (дней до 1970 года), чтобы перейти к нему.

Здесь jd2greg и соответствующий greg2jd:

=head2 jd2greg

    ($year, $month, $day) = jd2greg( $jd );

    Convert number of days on or after Jan 1, 1 CE (Gregorian) to
    gregorian year,month,day.

=cut

sub jd2greg {
    use integer;
    my $d = shift;
    my $yadj = 0;
    my ( $c, $y, $m );

    # add 306 days to make relative to Mar 1, 0; also adjust $d to be within
    # a range (1..2**28-1) where our calculations will work with 32bit ints
    if ( $d > 2**28 - 307 ) {

        # avoid overflow if $d close to maxint
        $yadj = ( $d - 146097 + 306 ) / 146097 + 1;
        $d -= $yadj * 146097 - 306;
      } elsif ( ( $d += 306 ) <= 0 )
    {
        $yadj =
          -( -$d / 146097 + 1 );    # avoid ambiguity in C division of negatives
        $d -= $yadj * 146097;
    }

    $c =
      ( $d * 4 - 1 ) / 146097;    # calc # of centuries $d is after 29 Feb of yr 0
    $d -= $c * 146097 / 4;    #     (4 centuries = 146097 days)
    $y = ( $d * 4 - 1 ) / 1461;    # calc number of years into the century,
    $d -= $y * 1461 / 4;    #     again March-based (4 yrs =~ 146[01] days)
    $m =
      ( $d * 12 + 1093 ) / 367;    # get the month (3..14 represent March through
    $d -= ( $m * 367 - 1094 ) / 12;    #     February of following year)
    $y += $c * 100 + $yadj * 400;    # get the real year, which is off by
    ++$y, $m -= 12 if $m > 12;         #     one if month is January or February
    return ( $y, $m, $d );
}


=head2 greg2jd

    $jd = greg2jd( $year, $month, $day );

    Convert gregorian year,month,day to days on or after Jan 1, 1 CE
    (Gregorian).  Normalization is performed (e.g. month of 28 means
    April two years after given year) for month < 1 or > 12 or day < 1
    or > last day of month.

=cut

sub greg2jd {
    use integer;
    my ( $y, $m, $d ) = @_;
    my $adj;

    # make month in range 3..14 (treat Jan & Feb as months 13..14 of prev year)
    if ( $m <= 2 ) {
        $y -= ( $adj = ( 14 - $m ) / 12 );
        $m += 12 * $adj;
      } elsif ( $m > 14 )
    {
        $y += ( $adj = ( $m - 3 ) / 12 );
        $m -= 12 * $adj;
    }

    # make year positive (oh, for a use integer 'sane_div'!)
    if ( $y < 0 ) {
        $d -= 146097 * ( $adj = ( 399 - $y ) / 400 );
        $y += 400 * $adj;
    }

    # add: day of month, days of previous 0-11 month period that began w/March,
    # days of previous 0-399 year period that began w/March of a 400-multiple
    # year), days of any 400-year periods before that, and 306 days to adjust
    # from Mar 1, year 0-relative to Jan 1, year 1-relative (whew)

    $d += ( $m * 367 - 1094 ) / 12 + $y % 100 * 1461 / 4 +
      ( $y / 100 * 36524 + $y / 400 ) - 306;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...