我正在 Linux 中编写一个 bash shell 脚本,该程序将接受一个日期(mm-dd-yyyy)作为参数。我想知道是否有一种简单的方法来检查日期是否有效?有操作员,我可以用测试来检查吗?
8 回答
你可以检查date -d "datestring"
所以date -d "12/31/2012"
是有效的,但使用连字符,例如date -d "12-31-2012"
,对 无效date
。
您也可以使用单词:date -d 'yesterday'
或date -d '1 week ago'
两者都有效。
您可以从输入日期值 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
对于脚本使用,我尽可能简单。使用 date 函数测试日期值,然后检查进程的退出代码。
date -d "02/01/2000" 2>: 1>:; echo $?
这会将标准输入和标准错误重定向为 null :
,并使用 echo 返回退出代码,$?
允许我检查 0=good date 和 1=bad date。
以下对我来说效果很好。非常感谢我的同事 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) 上进行测试。
为了在 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 "$?"
}
- 它首先使用正则表达式匹配来检查格式。
- 然后,它将日期转换为纪元时间,然后再转换回日期。
- 如果原始日期和两次转换的日期匹配,则它是有效的。
测试有效日期:2005-11-30
$ isYYYYMMDDdate 2005-11-30
0
测试无效日期:2005-11-31
$ isYYYYMMDDdate 2005-11-31
1
测试格式错误的有效日期:1979-20-04
$ isYYYYMMDDdate 1979-20-04
1
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
我希望这有帮助。
该date
命令将解析-d
参数给出的日期。如果日期无效,则会向 STDERR 打印一条错误消息并date
以错误状态退出。如果日期有效,它将在 STDOUT 上打印日期并以成功状态退出。
正因为如此,date -d "$date"
可以直接在bash
if
语句中使用。
第一个问题是,为了防止打印有效日期的消息,您需要将 STDOUT 重定向到/dev/null
using >/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'</p>
或者,您可以检查日期是否无效并退出:
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"
您可以使用strptime()
Python 的时间或日期时间模块或 Perl 的Time::Piece模块中可用的函数。