如何在shell脚本中从这种格式的时间中减去毫秒:“2020-01-06 11:27:12.280”

huangapple go评论157阅读模式
英文:

How do I subtract milliseconds from time in this format: "2020-01-06 11:27:12.280" in shell script

问题

我有时间格式2020-01-06 11:27:12.280,其中.280表示毫秒。
想要从这个时间中减去500毫秒,并再次以相同的时间格式获得结果。

我尝试过使用以下命令将日期时间转换为纪元时间:

date +%s -d "2020-01-06 11:27:12.280"

但它不考虑毫秒。

英文:

I have time format 2020-01-06 11:27:12.280 where .280 is milliseconds.
Want to subtract 500 milliseconds from this time and get result in same time format again.

I have tried to convert date time in epoch time using this command:

date +%s -d"2020-01-06 11:27:12.280

but is does not consider milliseconds.

答案1

得分: 3

GNU: 使用GNU date,可以直接在date命令内部进行减法运算。这在Léa Gris的评论中有演示:

$ date -d "2020-01-06 11:27:12.280 - 0.5 sec" '+%F %T.%3N'
2020-01-06 11:27:11.780

这在这里有效,因为GNU date有使用-d标志查询任何日期字符串的可能性,并且具有纳秒的知识。

BSD/MacOS: BSD date的行为不同。在这里需要更多的工作:

$ d="2020-01-06 11:27:12.280"
$ d=$(( $(date -j -f "%F %T" "${d%.*}" "+%s")${d#*.} - 500 ))
$ date -r "${d%${d: -3}}" "+%F %T.${d: -3}"
2020-01-06 11:27:11.780

POSIX: 如果要遵循POSIX标准,情况就不同了。根据POSIX标准,不能使用date命令,因为无法使用-d标志设置自己的日期时间,也没有指定毫秒或纳秒的格式。因此,需要使用不同的工具。有很多可能的方法,但我们将在这里使用POSIX awk的一个版本:

awk -v d='2020-01-06 11:27:12.280' '
BEGIN{ gsub(/[-:]/," ",d); strftime_posix(mktime_posix(d)-0.5) }

# 从"天文算法"中的算法J.Meeus
function mktime_posix(datestring,    a,t) {
    split(datestring,a," ")
    if (a[1] < 1970) return -1
    if (a[2] <= 2) { a[1]--; a[2]+=12 }
    t=int(a[1]/100); t=2-t+int(t/4)
    t=int(365.25*a[1]) + int(30.6001*(a[2]+1)) + a[3] + t - 719593
    return t*86400 + a[4]*3600 + a[5]*60 + a[6]
}

function strftime_posix(epoch, JD,yyyy,mm,dd,HH,MM,SS,A,B,C,D,E ) {
    if (epoch < 0 ) return "0000 00 00 00 00 00.000000"
    JD=epoch; SS=JD%60; JD-=SS; JD/=60; MM=JD%60;
    JD-=MM; JD/=60; HH=JD%24; JD-=HH; JD/=24;
    JD+=2440588
    A=int((JD - 1867216.25)/(36524.25))
    A=JD+1+A-int(A/4)
    B=A+1524; C=int((B-122.1)/365.25); D=int(365.25*C); E=int((B-D)/30.6001)
    dd=B-D-int(30.6001*E)
    mm = E < 14 ? E-1 : E - 13
    yyyy=mm>2?C-4716:C-4715
    return sprintf("%0.4d-%0.2d-%0.2d %0.2d:%0.2d:%06.3f",yyyy,mm,dd,HH,MM,SS)
}
'
英文:

GNU: Using GNU date, it is possible to do the subtraction directly within the date-command. This is demonstrated in the comment of Léa Gris:

$ date -d &quot;2020-01-06 11:27:12.280 - 0.5 sec&quot; &#39;+%F %T.%3N&#39;
2020-01-06 11:27:11.780

This works here because GNU date has the possibility to query any date-string using the -d flag and has knowledge of nanoseconds.

BSD/MacOS: BSD date is behaving differently. You need a bit more work here:

$ d=&quot;2020-01-06 11:27:12.280&quot;
$ d=$(( $(date -j -f &quot;%F %T&quot; &quot;${d%.*}&quot; &quot;+%s&quot;)${d#*.} - 500 ))
$ date -r &quot;${d%${d: -3}}&quot; &quot;+%F %T.${d: -3}&quot;
2020-01-06 11:27:11.780

POSIX: If you want to be POSIX compliant, it is a different story. According to the POSIX standard, the date command cannot be used here as you cannot set your own date-time with the -d flag, and neither is there a format that specifies mili or nanoseconds. Hence, one is required to use different tools. There are many possible ways, but we will use here a version of POSIX awk:

awk -v d=&#39;2020-01-06 11:27:12.280&#39; &#39;
BEGIN{ gsub(/[-:]/,&quot; &quot;,d); strftime_posix(mktime_posix(d)-0.5) }
 
# Algorithm from &quot;Astronomical Algorithms&quot; By J.Meeus
function mktime_posix(datestring,    a,t) {
    split(datestring,a,&quot; &quot;)
    if (a[1] &lt; 1970) return -1
    if (a[2] &lt;= 2) { a[1]--; a[2]+=12 }
    t=int(a[1]/100); t=2-t+int(t/4)
    t=int(365.25*a[1]) + int(30.6001*(a[2]+1)) + a[3] + t - 719593
    return t*86400 + a[4]*3600 + a[5]*60 + a[6]
}

function strftime_posix(epoch, JD,yyyy,mm,dd,HH,MM,SS,A,B,C,D,E ) {
    if (epoch &lt; 0 ) return &quot;0000 00 00 00 00 00.000000&quot;
    JD=epoch; SS=JD%60; JD-=SS; JD/=60; MM=JD%60;
    JD-=MM; JD/=60; HH=JD%24; JD-=HH; JD/=24;
    JD+=2440588
    A=int((JD - 1867216.25)/(36524.25))
    A=JD+1+A-int(A/4)
    B=A+1524; C=int((B-122.1)/365.25); D=int(365.25*C); E=int((B-D)/30.6001)
    dd=B-D-int(30.6001*E)
    mm = E &lt; 14 ? E-1 : E - 13
    yyyy=mm&gt;2?C-4716:C-4715
    return sprintf(&quot;%0.4d-%0.2d-%0.2d %0.2d:%0.2d:%06.3f&quot;,yyyy,mm,dd,HH,MM,SS)
}
&#39;

huangapple
  • 本文由 发表于 2020年1月6日 19:15:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/59611108.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定