如何比较shell中的两个日期?

Abd*_*dul 114 shell shell-script date

如何在shell中比较两个日期?

这是我想如何使用它的示例,尽管它不能按原样工作:

todate=2013-07-18
cond=2013-07-15

if [ $todate -ge $cond ];
then
    break
fi                           
Run Code Online (Sandbox Code Playgroud)

我怎样才能达到预期的结果?

小智 157

仍然缺少正确答案:

todate=$(date -d 2013-07-18 +%s)
cond=$(date -d 2014-08-19 +%s)

if [ $todate -ge $cond ];
then
    break
fi  
Run Code Online (Sandbox Code Playgroud)

请注意,这需要 GNU 日期。dateBSD的等效语法date(就像在 OSX 中默认找到的一样)是date -j -f "%F" 2014-08-19 +"%s"

  • 不知道为什么有人不赞成这个,它非常准确并且不处理连接丑陋的字符串。将您的日期转换为 unix 时间戳(以秒为单位),比较 unix 时间戳。 (12认同)
  • 使用 `(( ... > ... ))` 可能比 `[ ... -gt ... ]` 或类似的更好。当 $x 为空时,`[[ "$x" -lt "$y" ]]` 返回 true,事实上 `[[ "" -eq 0 ]]` 为 TRUE。如果填充 $x 时出现问题并且它最终为空,我希望 `"" < 1` 返回 false。当 $x 为空时, `(( "$x" < "$y" ))` 会正确出错,无需额外检查。 (5认同)
  • 您可以使用“date -d 2013-07-18 +%s%N”包含纳秒精度 (2认同)

daj*_*jon 46

可以使用标准字符串比较来比较 [年、月、日格式的字符串] 的时间顺序。

date_a=2013-07-18
date_b=2013-07-15

if [[ "$date_a" > "$date_b" ]] ;
then
    echo "break"
fi
Run Code Online (Sandbox Code Playgroud)

值得庆幸的是,当 [使用 YYYY-MM-DD 格式的字符串] 按字母顺序排序*时,它们也按时间顺序排序*。

(* - 排序或比较)

在这种情况下不需要任何花哨的东西。好极了!

  • 这无疑是这里最聪明的答案 (2认同)
  • 使用这个答案,它更加健壮,因为它不依赖于外部命令。 (2认同)

小智 36

您缺少比较的日期格式:

#!/bin/bash

todate=$(date -d 2013-07-18 +"%Y%m%d")  # = 20130718
cond=$(date -d 2013-07-15 +"%Y%m%d")    # = 20130715

if [ $todate -ge $cond ]; #put the loop where you need it
then
 echo 'yes';
fi
Run Code Online (Sandbox Code Playgroud)

您也缺少循环结构,您打算如何获得更多日期?


ser*_*gut 9

这不是循环结构的问题,而是数据类型的问题。

这些日期(todatecond)是字符串,而不是数字,因此您不能使用test. (请记住,方括号表示法等效于命令test。)

您可以做的是为您的日期使用不同的符号,以便它们是整数。例如:

date +%Y%m%d
Run Code Online (Sandbox Code Playgroud)

将产生一个整数,如 20130715 为 2013 年 7 月 15 日。然后您可以将您的日期与“-ge”和等效运算符进行比较。

更新:如果给出了日期(例如,您正在从 2013-07-13 格式的文件中读取它们),那么您可以使用 tr 轻松预处理它们。

$ echo "2013-07-15" | tr -d "-"
20130715
Run Code Online (Sandbox Code Playgroud)


Gil*_*il' 7

该运算符-ge仅适用于整数,而您的日期则不是。

如果您的脚本是 bash 或 ksh 或 zsh 脚本,则可以改用<运算符。此运算符在 dash 或其他不超出 POSIX 标准的 shell 中不可用。

if [[ $cond < $todate ]]; then break; fi
Run Code Online (Sandbox Code Playgroud)

在任何 shell 中,您只需删除破折号即可将字符串转换为数字,同时遵守日期顺序。

if [ "$(echo "$todate" | tr -d -)" -ge "$(echo "$cond" | tr -d -)" ]; then break; fi
Run Code Online (Sandbox Code Playgroud)

或者,您可以采用传统方法并使用该expr实用程序。

if expr "$todate" ">=" "$cond" > /dev/null; then break; fi
Run Code Online (Sandbox Code Playgroud)

由于在循环中调用子进程可能很慢,您可能更喜欢使用 shell 字符串处理构造进行转换。

todate_num=${todate%%-*}${todate#*-}; todate_num=${todate_num%%-*}${todate_num#*-}
cond_num=${cond%%-*}${cond#*-}; cond_num=${cond_num%%-*}${cond_num#*-}
if [ "$todate_num" -ge "$cond_num" ]; then break; fi
Run Code Online (Sandbox Code Playgroud)

当然,如果您可以首先检索没有连字符的日期,您将能够将它们与-ge.

  • 这似乎是最正确的答案。很有帮助! (2认同)

Jos*_*Gee 0

日期是字符串,而不是整数;您无法将它们与标准算术运算符进行比较。

如果分隔符保证是,您可以使用一种方法-

IFS=-
read -ra todate <<<"$todate"
read -ra cond <<<"$cond"
for ((idx=0;idx<=numfields;idx++)); do
  (( todate[idx] > cond[idx] )) && break
done
unset IFS
Run Code Online (Sandbox Code Playgroud)

这可以追溯到bash 2.05b.0(1)-release.