【问题标题】:validate date in unix for DD-MM-YYYY format为 DD-MM-YYYY 格式在 unix 中验证日期
【发布时间】:2015-02-07 09:48:55
【问题描述】:

如何验证Unix中的日期。
其中日期格式为DD-MM-YYYY
例如,如果我运行一个脚本./ValidateDate.sh DD-MM-YYYY,那么它应该检查日期是否采用这种格式并且日期是否存在。
如果日期有效且采用上述格式,则继续下一步打印消息“无效日期”

谢谢。

【问题讨论】:

  • 那里的答案对 dmy 不起作用。
  • 如果您对需求有任何影响,我鼓励您使用国际标准格式YYYY-MM-DD,而不是模棱两可的DD-MM-YYYY

标签: bash unix arguments


【解决方案1】:

嗯...这是一个很好的蠕虫。

您创建的任何 shell 脚本可能无法在所有不同风格的 Unix/Linux 上运行。

BSD date 命令(可在 OS X 和 Solaris 上找到)在获取日期和验证格式方面做得很好。它要求您指定日期格式,但是一旦您这样做了,就没有问题了:

if date -j -f "%d-%m-%Y" "$DATE" 2>&1 > /dev/null # No output
then
    echo "ERROR: Date '$DATE' is not a valid format."
    exit 2
else
    echo "Date is '$DATE'."
fi

Linux 和其他使用 GNU 日期的系统也可以验证日期,但使用不同的语法:

date -d "$DATE" 2>&1 /dev/null   # With a bit of luck this will work...
if $? -ne 0
then
    echo "ERROR: Date '$DATE' is not a valid format."
else
    echo "Date is '$DATE'."
fi

我说 运气好 因为这取决于date 命令来确定您的日期格式。这通常有效,并且适用于您的 YYYY-MM-DD 格式,但可能会造成混淆:

想象一下:

$ DATE="15/6/2014"              # It's June 15, 2014
$ date -d "$DATE"
date: invalid date `15/6/2014'  # Invalid?

这是因为在我的时区,dd/mm/yyyy 格式不是有效格式。在我的时区,日期应该是mm/dd/yyyy。为了解决这个问题,您可以使用Wintermute's 建议并将日期格式化为 ISO 格式,然后再使用 GNU 的日期格式。

通用的可能性是使用 Perl 或 Python 来确定日期是否正确:

if perl -mTime::Piece -e "Time::Piece->strptime(\"$DATE\", \"%Y-%m-%d\")" 2> /dev/null
then
    echo "ERROR: Date '$DATE' is not a valid format."
else
    echo "Date is '$DATE'."
fi

如果$DATE 不是%Y-%m-%d 格式的有效日期,则此Perl oneliner 将返回非零错误状态。

【讨论】:

  • 我的 awk 也应该适用于所有口味(只要它们明显有 awk)。
  • gawk(在 Linux 上别名为 gawk)具有 strptime 功能,但不是 BSD 系统上的标准 awk。您的脚本无法在我的 Mac 上运行。
【解决方案2】:

如果您愿意将验证分为两个步骤,则可以相当轻松地完成此操作。首先,检查字符串的格式是否正确:

date=$1
[[ $date =~ ([0-9][0-9])-([0-9][0-9])-([0-9]+) ]] || { printf "Invalid date format\n"; exit 1; }

如果该测试通过,您可以提取日、月和年字段,然后验证每个字段是否在正确的范围内。

day=${BASH_REMATCH[1]}
month=${BASH_REMATCH[2]}
year=${BASH_REMATCH[3]}

thirty_one_days='0[1-9]|[12][0--9]|3[01]'
thirty_days='0[1-9]|[12][0--9]|30'
twenty_eight_days='0[1-9]|1[0-9]|2[0-8]'
case $month in
    01|03|05|07|08|10|12)
        [[ $day =~ $thirty_one_days ]] ;;
    04|06|09|11)
        [[ $day =~ $thirty_days ]] ;;
    02)
        # 1-28, but 29 OK in a leap year.
        [[ $day =~ $twenty_eight_days ]] ||
            (( year % 4 == 0 && $year % 400 == 0 && day == 29 ))
    *)
         false
 esac || { print "Invalid date\n"; exit 1; }

【讨论】:

    【解决方案3】:

    方法

    awk 'split($0,a,"-"){print strftime("%d-%m-%Y",mktime(a[3]" "a[2]" "a[1]" 00 00 00"))==$0?"valid":"not valid"}' <<< "31-12-1992"
    

    它将字符串转换为纪元,将纪元转换回来,然后检查原始字符串。

    编辑:

    认为我会在测试日期后添加此作品
    FROM 01-01-0
    31-12-2147483647

    虽然缺点是在您低于 1000 年之后,您必须从年份中删除前导零。

    【讨论】:

      【解决方案4】:

      您可以使用date 实用程序验证日期,但您首先必须将输入转换为它可以理解的内容。我建议 ISO 表示(总是)。例如,它可能如下所示:

       #!/bin/sh
      
       PATTERN='\([0-9]\{1,2\}\)-\([0-9]\{1,2\}\)-\([0-9]\+\)'
      
       # if the pattern doesn't match, this will give date an empty string, so it will fail as expected.
       if date -d $(echo "$1" | sed -n "/$PATTERN/ { s/$PATTERN/\3-\2-\1/; p }") > /dev/null 2>&1 ; then
           echo valid
       else
           echo invalid
       fi
      

      【讨论】:

      • 有什么理由使用sed -n ... p 而不仅仅是默认的 sed 吗?
      • p 是有条件的。只有当行与模式匹配时才会执行。否则,与模式不匹配但按日期识别的输入将被视为有效。
      • 请注意,date -d 是特定于 GNU 的扩展,而不是 POSIX 的一部分。
      猜你喜欢
      • 2016-01-26
      • 2014-01-18
      • 2022-11-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-01
      • 1970-01-01
      • 2017-04-07
      相关资源
      最近更新 更多