【问题标题】:Increment hour field by 5 (UTC to EST format)将小时字段增加 5(UTC 到 EST 格式)
【发布时间】:2016-06-26 06:42:46
【问题描述】:

我有一个包含数千条记录的文件。每行应该有一个或多个 UTC 格式的日期时间字段。

我需要将日期和时间字段转换为EST格式:在小时字段中添加+5,如果它变得大于24,日期也应该改变。

例如:

输入:

123456|2016-03-10T14:30:25.000|abcd|efdgh|1245|2016-03-10T23:30:25.000

654321|2016-03-10T20:30:25.000|abcd|efdgh|1245|2016-03-11T04:30:25.000

输出应该是:

123456|2016-03-10T19:30:25.000|abcd|efdgh|1245|2016-03-10T14:30:25.000

654321|2016-03-11T01:30:25.000|abcd|efdgh|1245|2016-03-10T19:30:25.000

这是我尝试过的:

# cat f
123456|2016-03-10T14:30:25.000|abcd|efdgh|1245|2016-03-10T23:30:25.000 654321|2016-03-10T20:30:25.000|abcd|efdgh|1245|2016-03-11T04:30:25.000
# awk 'BEGIN {FS = "T";; OFS="T" } $2+=4,$3+=5' f
123456|2016-03-10T18T28 654321|2016-03-10T24T9

【问题讨论】:

  • 到目前为止,您尝试过什么?您似乎忘记发布无效代码的minimal reproducible example。
  • 很抱歉,Stack Overflow 不是代码编写服务。如果您希望在这里获得帮助,则必须表现出一些努力。
  • 我是新手,我对脚本的了解不多,但我尝试了以下一个更改小时字段但数据丢失的方法,如果小时超过 24,我不确定如何计算日期#猫 f 123456|2016-03-10T14:30:25.000|abcd|efdgh|1245|2016-03-10T23:30:25.000 654321|2016-03-10T20:30:25.000|abcd|efdgh|1245|2016-03 -11T04:30:25.000 # awk 'BEGIN {FS = "T";; OFS="T" } $2+=4,$3+=5' f 123456|2016-03-10T18T28 654321|2016-03-10T24T9
  • 你应该edit你的问题包括那个。

标签: linux perl awk sed


【解决方案1】:

寿命太短,无法手动计算日期和时间。因此,请使用包含用于时间处理的模块的语言。根据您选择的标签,我会选择 Perl 和 DateTime 模块。

所以提取日期字段,然后创建一个 DateTime 对象来进行计算:

use DateTime;
my $date = '2016-03-10T23:30:25.000'
if ($date =~ /(\d\d\d\d)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)/) {
    my $dt = DateTime->new(year => $1, month => $2, day => $3,
                           hour => $4, minute => $5, second => $6,
                           time_zone => 'UTC');

    $dt->set_time_zone("EST");
    $date = $dt->ymd . "T" . $dt->hms;
} else {
    die "invalid date";
}

这将处理所有不只是偏移 5 小时的极端情况。

是的,我知道 DateTime 不是最快的解决方案。但除非另有证明,否则我认为它应该表现得足够好。

【讨论】:

  • 小错字 - time_zone,而不是 time_sone。而且我认为 DateTime::Format::Strptime 会让这更容易一些 - 无需从时间戳中解析出所有单独的位。
【解决方案2】:

我认为你的计算是错误的。您通过减去五个小时而不是增加五个小时将 UTC 转换为 EST(假设“EST”是指美国东部标准时间)。

这就是我的做法。

#!/usr/bin/perl

use strict;
use warnings;

use DateTime::Format::Strptime;

my $fmt = '%Y-%m-%dT%H:%M:%S';
my $dp = DateTime::Format::Strptime->new(
  pattern   => $fmt,
  time_zone => 'UTC',
);

while (<DATA>) {
  s/(\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d)/change_time($1)/eg;
  print;
}

sub change_time {
  my $time = shift;
  my $dt = $dp->parse_datetime($time);
  $dt->set_time_zone("EST");
  return $dt;
}

__DATA__
123456|2016-03-10T14:30:25.000|abcd|efdgh|1245|2016-03-10T23:30:25.000

654321|2016-03-10T20:30:25.000|abcd|efdgh|1245|2016-03-11T04:30:25.000

运行的输出是:

123456|2016-03-10T09:30:25.000|abcd|efdgh|1245|2016-03-10T18:30:25.000

654321|2016-03-10T15:30:25.000|abcd|efdgh|1245|2016-03-10T23:30:25.000

【讨论】:

    【解决方案3】:

    使用 GNU awk 进行时间函数:

    $ cat tst.awk
    BEGIN { FS=OFS="|" }
    { $2=upd($2); $6=upd($6); print }
    function upd(dt,        a) {
        split(dt,a,/[.]/)
        gsub(/[-T:]/," ",a[1])
        return strftime("%Y-%m-%dT%H:%M:%S",mktime(a[1])+5*60*60) "." a[2]
    }
    
    $ awk -f tst.awk file
    123456|2016-03-10T19:30:25.000|abcd|efdgh|1245|2016-03-11T04:30:25.000
    654321|2016-03-11T01:30:25.000|abcd|efdgh|1245|2016-03-11T09:30:25.000
    

    【讨论】:

      猜你喜欢
      • 2018-05-11
      • 1970-01-01
      • 1970-01-01
      • 2018-09-07
      • 1970-01-01
      • 1970-01-01
      • 2016-07-16
      • 2018-02-14
      • 2021-11-10
      相关资源
      最近更新 更多