Epoch时间到日期和时间的全手动转换

Posted

技术标签:

【中文标题】Epoch时间到日期和时间的全手动转换【英文标题】:Full manual conversion of Epoch time to Date and Time 【发布时间】:2019-10-23 04:36:57 【问题描述】:

我编写了这个 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

问题: 这些值现在显示在用户无法读取的前端,前端没有脚本实用程序,我只能使用许多不同的计算公式来使其可读。

是否有一种完全手动的方法,只需使用计算器/计算将纪元时间转换回用户可读的日期和时间?

【问题讨论】:

为什么要“完全手动的方法”?你真的不想使用图书馆吗? @zdim 这就是问题所在,整数只对前端可用,前端没有任何脚本功能,除了从数字到文本的正常翻译,加法,乘法等计算。@ 987654325@ "前端没有任何脚本功能"——那么我不明白你在问什么:不是 Perl 脚本可以做到这一点吗?那么有哪些工具可用呢? “计算器/计算”是什么意思?这是在命令行上完成的,还是“前端”是什么?我很困惑:) @zdim。好的,让我说得更清楚。所以它具有基本的功能。没有像Time::Local; 这样的可用项目,它只能做像$time = $hour + $min; 这样的基本操作,就像:) 一样手动操作。 那么什么是“it”(具有基本功能)——那么它根本就不是 Perl 吗? (为什么您使用 Perl 的变量,例如 $hour?该系统是否对变量使用相同的表示法?)问题的阅读方式我希望您要求通过 Perl 进行转换。 【参考方案1】:

核心Time::Piece 可以简单地针对您当地的时区进行双向转换。

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 接受的格式说明符没有记录。


如果不访问 Perl 5.10 以来的核心 Time::Piece,您可以使用内置的 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;

【讨论】:

"不幸的是 Time::Piece 接受的那些没有记录在案" -- 好吧,它把我们发送到 strptime 手册页。如果这些是正确的规格(以我的经验是正确的),那么就会记录在案。 不完全是:Time::Piece 的 strptime 解析器非常定制,当然只是在扩展中。 嗯。那么这是文档中的一个错误。如果它将我发送到一个格式的手册页,该格式暗示(对我作为用户而言)该手册页准确地描述了它的格式(或者,实际上,程序使用了系统的工具)。 谢谢。加一个作为答案,但问题是,前端 perl 是 perl 的黑盒版本,它对 perl 库的资源有限。我需要在实际的1+1=2level :( @Gerry Time::Piece 是核心。除非您使用的 Perl 版本早于 5.10 或 Perl 安装不完整,否则您可以访问它。【参考方案2】:

在非常早期的 DateTime.pm 版本中,您会发现一个子 _rd2greg,它是我为 Rich Bowen 的早期且长期失效的 Reefknot 项目编写的 jd2greg。这需要从第 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;

【讨论】:

太棒了,这是手动的。让我在我的系统上测试一下:) 这不考虑您当地的时区,并且非常复杂且无法审核。只需使用本地时间。 @Grinnz 它仍然是问题所要求的,或者至少是其中的日期部分。不过,我错过了他们正在使用 timelocal();这使事情变得更加艰难。审计很容易;将各种结果与 localtime() 进行比较

以上是关于Epoch时间到日期和时间的全手动转换的主要内容,如果未能解决你的问题,请参考以下文章

在Android中将Epoch时间转换为日期并将日期转换为Epoch时间[重复]

将 Epoch 时间转换为日期

如何在标准 SQL 中将 Epoch 时间戳转换为日期

C# Epoch 日期时间转换

从纪元到日期时间的转换不正确

Razor 视图中的 Epoch/Unix 时间戳(以毫秒为单位)到日期时间