在 shell 脚本中比较多个日期和时间

在 shell 脚本中比较多个日期和时间

我有以下 jq 命令的输出,我想比较所有日期和时间并告诉哪个是最新的

Mon Feb 20 09:22:25 2023
Mon Feb 20 17:42:13 2023
Thu Mar  2 05:55:07 2023
Tue Feb 28 16:02:40 2023

请指导我如何做到这一点,我似乎有多个比较两个日期的答案,不确定如何比较日期和时间,还要比较我是否需要将上述时间戳转换为特定格式,

请指导

问候,武士

答案1

假设您有一些如下所示的 JSON 文档:

[
   { "datestring": "Mon Feb 20 09:22:25 2023" },
   { "datestring": "Mon Feb 20 17:42:13 2023" },
   { "datestring": "Thu Mar  2 05:55:07 2023" },
   { "datestring": "Tue Feb 28 16:02:40 2023" }
]

(您可以使用问题中的数据创建此数据jq -Rn '[inputs] | map({datestring: .})',但我假设您已经在某个 JSON 文档中拥有此数据。)

...然后您可以使用和jq将这些日期字符串转换为 Unix 时间戳(整数),然后使用这些时间戳作为排序键对原始字符串进行排序。strptime()mktime

jq 'sort_by(.datestring|strptime("%a %b %e %H:%M:%S %Y")|mktime)' file

这将计算示例文档中顶级数组中每个条目的 Unix 时间戳。它通过使用给定的特定格式字符串解析给定的日期字符串(请参阅系统上的strptime()手册了解此格式字符串的含义)并将生成的时间表示形式转换为带有.然后使用该 Unix 时间戳按升序对条目进行排序。strptimemktimesort_by()

鉴于上面的示例文档,这将产生与以下内容等效的内容:

[
   { "datestring": "Mon Feb 20 09:22:25 2023" },
   { "datestring": "Mon Feb 20 17:42:13 2023" },
   { "datestring": "Tue Feb 28 16:02:40 2023" },
   { "datestring": "Thu Mar  2 05:55:07 2023" }
]

一种稍微更有效的方法是预先计算 Unix 时间戳,使用它们进行排序,然后再次删除它们(一种施瓦茨变换):

jq 'map(.ts = (.datestring|strptime("%a %b %e %H:%M:%S %Y")|mktime)) | sort_by(.ts) | map(del(.ts))' file

答案2

您可以使用date命令将这些日期转换为unix时间戳并对它们进行排序,然后您可以将它们转换回您想要的任何格式。

例如,将日期转换为时间戳,然后再转换回来:

date -d "Mon Feb 20 09:22:25 2023" +%s
1676884945
date -d "@1676884945" +%c
Mon Feb 20 09:22:25 2023
  • -d表示显示字符串中表示的日期/时间,如果您使用unix时间,则需要放在@时间之前
  • +%s表示以 UNIX 纪元时间显示日期
  • +%c表示以区域设置时间格式显示日期

然后,您可以将它们放入一些循环中,并将时间转换为 unix 纪元,轻松排序,并将排序后的时间转换回您想要的任何时间格式。

如果 datefile 中有日期,这会将它们转换为 unix 时间戳并对其进行排序。

while IFS= read -r line; do date -d "$line" +%s; done < datefile  | sort -n

然后您可以将这些排序后的格式转换回您想要的任何格式

for i in $(while IFS= read -r line; do date -d "$line" +%s; done < datefile  | sort -n); do date -d "@$i" +%c; done

对于你给出的例子,你会得到这样的东西

for i in $(while IFS= read -r line; do date -d "$line" +%s; done < datefile  | sort -n); do date -d "@$i" +%c; done
Mon Feb 20 09:22:25 2023
Mon Feb 20 17:42:13 2023
Tue Feb 28 16:02:40 2023
Thu Mar  2 05:55:07 2023

请注意,当您使用 %c 时,您将获得符合您的区域设置的格式的输出,因此不需要您想要的格式。

如果您想确保从示例中获取格式,则需要使用+'%a %b %d %T %Y'

for i in $(while IFS= read -r line; do date -d "$line" +%s; done < datefile  | sort -n); do date -d "@$i" +'%a %b %d %T %Y'; done
Mon Feb 20 09:22:25 2023
Mon Feb 20 17:42:13 2023
Tue Feb 28 16:02:40 2023
Thu Mar 02 05:55:07 2023
  • %a缩写的三个字母日
  • %b缩写的三个字母月份
  • %d一个月中的某一天
  • %T带前导零的时间
  • %Y

20230220092225您还可以像格式一样转换为年、月、日、时间等所有数字,不带空格'%Y%m%dH%M%S',并使用该格式对日期进行排序或比较

date -d "Mon Feb 20 09:22:25 2023" +'%Y%m%d%H%M%S'
20230220092225

答案3

使用 GNUsort或兼容版本,您可以使用以下命令按时间顺序对输入进行排序:

LC_ALL=C sort -b -k5,5rn -k2,2rM -k3,3rn -k4,4r

这里r从最新到最旧的顺序排列,因此您可以通过管道head -n1获取最新的。非标准部分是M第二个排序键的标志,用于根据月份名称或缩写进行排序(此处用于LC_ALL=C强制使用英文)。

注意jq有时间解析和格式化功能,所以您应该能够直接从产生输出的调用jq中对日期数组进行排序jq首先。

相关内容