【问题标题】:check if argument is a valid date in bash shell检查参数是否是 bash shell 中的有效日期
【发布时间】:2012-06-01 07:35:34
【问题描述】:

我正在 Linux 中编写一个 bash shell 脚本,该程序将接受一个日期 (mm-dd-yyyy) 作为参数。我想知道是否有一种简单的方法来检查日期是否有效?有运营商,我可以用test来检查吗?

【问题讨论】:

标签: linux bash shell


【解决方案1】:

您可以通过date -d "datestring"查看

所以date -d "12/31/2012" 是有效的,但使用连字符,例如date -d "12-31-2012",对date无效。

您也可以使用单词:date -d 'yesterday'date -d '1 week ago' 都有效。

【讨论】:

  • Bash 不在乎,date 抱怨连字符。
  • 我刚刚尝试使用斜杠和反斜杠(bash .4.2.2,日期 gnu coreutils 8,4),它很乐意接受这两种不带连字符的。
【解决方案2】:

您可以从输入日期值 MM-DD-YYYY 中提取日、月和年值,并将其验证为明确 (ISO) 格式 YYYY-MM-DD(您可以验证 DD-MM-YYY使用日期将日期格式化为“正确”,例如 25-12-2010,但它不是有效的 MM-DD-YYY 日期,因此需要先更改日期格式)


格式正确的有效日期是可以的

2005 年 11 月 30 日有效:

$ DATE=11-30-2005; d=${DATE:3:2}; m=${DATE:0:2}; Y=${DATE:6:4}; echo "year=$Y, month=$m, day=$d"; if date -d "$Y-$m-$d" &> /dev/null; then echo VALID; else echo INVALID; fi
year=2005, month=11, day=30  
VALID

$ DATE=11-30-2005; if date -d "${DATE:6:4}-${DATE:0:2}-${DATE:3:2}" &> /dev/null; then echo VALID; else echo INVALID; fi
VALID

格式正确的无效日期是错误的

2005 年 11 月 31 日未验证:

$ DATE=11-31-2005; d=${DATE:3:2}; m=${DATE:0:2}; Y=${DATE:6:4}; echo "year=$Y, month=$m, day=$d"; if date -d "$Y-$m-$d" &> /dev/null; then echo VALID; else echo INVALID; fi
year=2005, month=11, day=31  
INVALID

$ DATE=11-31-2005; if date -d "${DATE:6:4}-${DATE:0:2}-${DATE:3:2}" &> /dev/null; then echo VALID; else echo INVALID; fi
INVALID

格式不正确的有效日期不正确

DD-MM-YYYY 格式的 1979 年 4 月 20 日不验证为 MM-DD-YYYY 日期:

$ DATE=20-04-1979; d=${DATE:3:2}; m=${DATE:0:2}; Y=${DATE:6:4}; echo "year=$Y, month=$m, day=$d"; if date -d "$Y-$m-$d" &> /dev/null; then echo VALID; else echo INVALID; fi
year=1979, month=20, day=04  
INVALID

$ DATE=20-04-1979; if date -d "${DATE:6:4}-${DATE:0:2}-${DATE:3:2}" &> /dev/null; then echo VALID; else echo INVALID; fi
INVALID

另一种更简单的方法:使用 BASH 变量字符串将连字符替换为斜杠

$ DATE="04-30-2005"; [[ $(date -d "${DATE//-/\/}" 2> /dev/null) ]] && echo VALID || echo INVALID
VALID

$ DATE="04-31-2005"; [[ $(date -d "${DATE//-/\/}" 2> /dev/null) ]] && echo VALID || echo INVALID
INVALID

【讨论】:

  • 我知道你发布这个答案已经很长时间了,但是我如何修改你的条件,以便它检查“如果无效”而不是“如果有效”
  • 像许多其他语言一样,您使用“!”作为 NOT 运算符,然后更改您的 thenelse 以适应,例如DATE=20-04-1979; d=${DATE:3:2}; m=${DATE:0:2}; Y=${DATE:6:4}; echo "year=$Y, month=$m, day=$d"; if ! date -d "$Y-$m-$d" &> /dev/null; then echo INVALID; fi
【解决方案3】:

对于脚本使用,我尽量保持简单。使用 date 函数测试日期值,然后检查进程的退出代码。

date -d "02/01/2000" 2>: 1>:; echo $?

这会将标准输入和标准错误重定向到 null :,并使用 echo 返回带有 $? 的退出代码,让我可以检查 0=good date 和 1=bad date。

【讨论】:

  • 我不会输出日期来创建一个名为“:”的文件。我会清理一下... date -d "11/31/2018" > /dev/null 2>&1,这将返回 1(假)。将 31 更改为 30,返回 0(真)。
【解决方案4】:

以下内容对我来说效果很好。非常感谢我的同事 Tyler Chamberlain 提供的 OSX 解决方案。

# Validate a given date/time in Bash on either Linux or Mac (OSX).

# Expected date/time format (in quotes from the command line):  YYYY-MM-DD HH:MM:SS
# Example(s):  ./this_script "2012-02-29 13:00:00"   # IS valid
#              ./this_script "2013-02-29 13:00:00"   # Is NOT valid

START_DATETIME=$1

function report_error_and_exit
{
   local MSG=$1
   echo "$MSG" >&2
   exit 1
}

# We can use OSTYPE to determine what OS we're running on.
# From http://stackoverflow.com/questions/394230/detect-the-os-from-a-bash-script

# Determine whether the given START_DATETIME is valid.
if [[ "$OSTYPE" == "linux-gnu" ]]
then
   # Validate the date on a Linux machine (Redhat or Debian).  On Linux, this is 
   # as easy as adding one minute and checking the return code.  If one minute 
   # cannot be added, then the starting value is not a valid date/time.
   date -d "$START_DATETIME UTC + 1 min" +"%F %T" &> /dev/null
   test $? -eq 0 || report_error_and_exit "'$START_DATETIME' is not a valid date/time value. $OSTYPE"
elif [[ "$OSTYPE" == "darwin"* ]]
then
   # Validate the date on a Mac (OSX).  This is done by adding and subtracting
   # one minute from the given date/time.  If the resulting date/time string is identical 
   # to the given date/time string, then the given date/time is valid.  If not, then the
   # given date/time is invalid.
   TEST_DATETIME=$(date -v+1M -v-1M -jf "%F %T" "$START_DATETIME" +"%F %T" 2> /dev/null)

   if [[ "$TEST_DATETIME" != "$START_DATETIME" ]]
   then
      report_error_and_exit "'$START_DATETIME' is not a valid date/time value. $OSTYPE"
   fi
fi

echo "The date/time is valid."

我在基于 Red Hat 的系统、基于 Debian 的系统和 OSX 上测试了这个脚本,它在所有三个平台上都按预期工作。我没有时间在 Windows (Cygwin) 上进行测试。

【讨论】:

    【解决方案5】:

    为了在 BASH shell 中在 OSX 上验证 YYYY-MM-DD (ISO 8601) 日期,以下方法同时验证格式和日期。

    isYYYYMMDDdate() {
      [[ "$1" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]] && [[ "$1" == $(date -r $(date -j -f "%Y-%m-%d" "$1" "+%s") '+%Y-%m-%d') ]] &> /dev/null; echo "$?"
    }
    
    1. 它首先使用正则表达式匹配来检查格式。
    2. 然后,它将日期转换为纪元时间,然后再转换回日期。
    3. 如果原始日期和两次转换的日期匹配,则有效。

    测试有效日期:2005-11-30

    $ isYYYYMMDDdate 2005-11-30
    0
    

    测试一个无效的日期:2005-11-31

    $ isYYYYMMDDdate 2005-11-31
    1
    

    测试格式错误的有效日期:1979-20-04

    $ isYYYYMMDDdate 1979-20-04
    1
    

    【讨论】:

      【解决方案6】:

      case 语句可以轻松支持多种格式和捕获日期部分,即

       case ${date} in
          [0-3][0-9]-[0-1][0-9]-[0-9][0-9][0-9][0-9] )
             yr=...
             mn=...
             dy=... 
          ;;
          [0-1][0-9]-[0-3][0-9]-[0-9][0-9][0-9][0-9] )
             yr=...
             dy=... 
             mn=...
          ;;
          .... other formats
          ;;
          * )
            echo "ERROR on date format, from value=$date, expected formats ..."
            return 1
          ;;     
       esac
      

      我希望这会有所帮助。

      【讨论】:

        【解决方案7】:

        date 命令将解析使用-d 参数给出的日期。如果日期无效,则会向 STDERR 打印一条错误消息,并且date 以错误状态退出。如果日期有效,它会在 STDOUT 上打印日期并以成功状态退出。

        因此,date -d "$date" 可以直接在 bash if 语句中使用。

        第一个问题是,为了防止打印有效日期的消息,您需要使用 >/dev/null 将 STDOUT 重定向到 /dev/null

        第二个问题是date 接受一个空字符串作为有效日期而没有抱怨。在大多数情况下,这应该意味着您的用户没有输入他们应该输入的日期。您将需要使用测试 [ "z$date" != "z" ] 单独测试空日期

        date 也接受多种格式。如果您使用实际的bash(而不是dash 或其他sh 变体,您可以针对您的首选格式使用正则表达式,而不是简单地检查空字符串。例如检查我的首选ISO 格式,我会使用:[[ "$date" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]

        date=2001-01-01
        if [ "z$date" != "z" ] && date -d "$date" >/dev/null
        then
          echo "VALID DATE"
        fi
        

        如果您尝试使用无效日期(例如 2001-01-53),它不会进入 if 并打印出来:

        日期:无效日期“2001-01-53”

        或者,您可以检查日期是否无效并退出:

        date=2001-01-01
        if [ "z$date" == "z" ]
        then
          echo "No date specified"
          exit 1
        fi
        if ! [[ "$date" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]
        then
          echo "Expected date in YYYY-MM-DD format"
          exit 1
        fi
        if ! date -d "$date" >/dev/null
        then
          exit 1
        fi
        echo "VALID DATE"
        

        【讨论】:

          【解决方案8】:

          您可以使用 Python 的 timedatetime 模块或 Perl 的 Time::Piece 模块中提供的 strptime() 函数。

          【讨论】:

            猜你喜欢
            • 2017-02-28
            • 2012-03-15
            • 1970-01-01
            • 1970-01-01
            • 2020-01-24
            • 2013-01-09
            • 1970-01-01
            • 2011-09-22
            相关资源
            最近更新 更多