用date-n小时替换文件中的日期

时间:2014-07-17 02:24:37

标签: regex bash perl awk sed

我正在尝试将格式为YYYYMMDDHHMMSS的日期替换为该时间减去7小时。

该文件看起来像这样

File with text and some dates 20140716223000 20140716013000

我希望输出看起来像

File with text and some dates 20140716153000 20140715183000

我能想到的最好的是perl的替代品:

perl -ape 's/(-*\d+.\d+)/$1-70000/ge' file.txt

但显然这不是日期减法,而是简单算术。任何bash或perl语句都适用于我。也许是sed或awk声明?谢谢!

4 个答案:

答案 0 :(得分:4)

您可以使用Time::Piece来解析日期时间字符串并执行算术运算。它是Perl 5版本10以来的核心模块,因此不需要安装。

相关的Time::Seconds模块以秒为单位提供各种时间间隔的有用常量。

此程序可以像您在问题中一样使用可执行替换。请注意,它不会正确处理夏令时,因为它只是从每个值中简单地减去25,200秒。

use strict;
use warnings;
use 5.010;

use Time::Piece;
use Time::Seconds qw/ ONE_HOUR /;

my $text = 'File with text and some dates 20140716223000 20140716013000';

say "Before: $text";

$text =~ s{(\d{14})}{
  my $dt = Time::Piece->strptime($1, '%Y%m%d%H%M%S');
  $dt -= 7 * ONE_HOUR;
  $dt->strftime('%Y%m%d%H%M%S');
}ge;

say " After: $text";

<强>输出

Before: File with text and some dates 20140716223000 20140716013000
 After: File with text and some dates 20140716153000 20140715183000

答案 1 :(得分:0)

既然你有GNU Bash,你很可能也有GNU Coreutils,所以你为什么不使用GNU date

$ cat file
File with text and some dates 20140716223000 20140716013000

$ cat script 
#!/bin/bash

while read -a LINE; do
    for i in "${!LINE[@]}"; do
        [[ ${LINE[$i]} =~ ^[0-9]{14}$ ]] && {
            DATE="${LINE[$i]}"
            YEAR="${DATE:0:4}"
            MONTH="${DATE:4:2}"
            DAY="${DATE:6:2}"
            HOUR="${DATE:8:2}"
            MINUTE="${DATE:10:2}"
            SECOND="${DATE:12:2}"
            NEWDATE="$(date -d \
                "-7 hours ${YEAR}-${MONTH}-${DAY}T${HOUR}:${MINUTE}:${SECOND}" \
                +'%Y%m%d%H%M%S')"
            LINE[$i]="$NEWDATE"
        }
    done
    echo "${LINE[@]}"
done < "$1"

$ ./script file
File with text and some dates 20140716153000 20140715183000

答案 2 :(得分:0)

将GNU awk用于gensub()和时间函数:

$ cat tst.awk
{
    head = ""
    tail = $0
    while ( match(tail,/\<[[:digit:]]{14}\>/) ) {
        oldTime = substr(tail,RSTART,RLENGTH)

        secs = mktime( gensub(/(....)(..)(..)(..)(..)(..)/,"\\1 \\2 \\3 \\4 \\5 \\6","",oldTime) )
        newTime = strftime("%Y%m%d%H%M%S", secs - (7 * 60 * 60))

        head = head substr(tail,1,RSTART-1) newTime
        tail = substr(tail,RSTART+RLENGTH)
    }
    print head tail
}
$
$ awk -f tst.awk file
File with text and some dates 20140716153000 20140715183000

答案 3 :(得分:-1)

并非所有问题都应使用正则表达式。

使用Date :: Calc怎么样?它的功能正是您所需要的:

($year,$month,$day, $hour,$min,$sec) = Add_Delta_DHMS($year,$month,$day, $hour,$min,$sec, $Dd,$Dh,$Dm,$Ds);

您可以使用简单的正则表达式将日期字符串分解为年/月/日/小时/分钟/秒变量。$ Dx参数可以为负数。

在说明中,我希望当你说“减去7小时”时,你并不是想做时区数学。因为这是一个与另一个解决方案不同的问题。