简体   繁体   English

检查参数是否是 bash shell 中的有效日期

[英]check if argument is a valid date in bash shell

I am writing a bash shell script in Linux, this program will accept a date (mm-dd-yyyy) as a parameter.我正在 Linux 中编写 bash shell 脚本,该程序将接受日期 (mm-dd-yyyy) 作为参数。 I am wondering if there is a simply way to check if the date is valid?我想知道是否有一种简单的方法可以检查日期是否有效? is there an operator and I can just use test to check?是否有操作员,我可以使用测试来检查?

You can check with date -d "datestring"您可以使用date -d "datestring"检查

So date -d "12/31/2012" is valid, but using hyphens, eg date -d "12-31-2012" , is not valid for date .所以date -d "12/31/2012"是有效的,但使用连字符,例如date -d "12-31-2012" ,对date无效。

You can also use words: date -d 'yesterday' or date -d '1 week ago' are both valid.您还可以使用以下词语: date -d 'yesterday'date -d '1 week ago'都是有效的。

You can extract the day, month, and year values from the input date value MM-DD-YYYY and validate it as the unambiguous (ISO) format YYYY-MM-DD instead (you can validate a DD-MM-YYY formatted date as "correct" using date, eg 25-12-2010, but it is not a valid MM-DD-YYY date, hence the need to change the date format first)您可以从输入日期值 MM-DD-YYYY 中提取日、月和年值,并将其验证为明确的 (ISO) 格式 YYYY-MM-DD(您可以验证 DD-MM-YYY 格式的日期为“正确”使用日期,例如 25-12-2010,但它不是有效的 MM-DD-YYY 日期,因此需要先更改日期格式)


A valid date in the correct format is OK格式正确的有效日期是可以的

30th November 2005 is valid: 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

An invalid date in the correct format is NOT OK格式正确的无效日期不正常

31st November 2005 does not validate: 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

A valid date in the incorrect format is NOT OK格式不正确的有效日期不正确

20th April 1979 in DD-MM-YYYY format does not validate as a MM-DD-YYYY date: 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

Alternate simpler method: use BASH variable string replace hyphens to slashes另一种更简单的方法:使用 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

For script use, I kept it as simple as I could.对于脚本使用,我尽可能地保持简单。 Testing the date value with the date function then checking the exit code of the process.使用 date 函数测试日期值,然后检查进程的退出代码。

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

This will redirect the standard in and standard error to null : and using echo to return the exit code with $?这会将标准输入和标准错误重定向到 null :并使用 echo 返回带有$? allows me to check for 0=good date and 1=bad date.允许我检查 0=好日期和 1=坏日期。

The following worked well for me.以下对我来说效果很好。 Many thanks to my co-worker, Tyler Chamberlain, for the OSX solution.非常感谢我的同事 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."

I tested this script on a Red Hat-based system, a Debian-based system and OSX, and it worked as expected on all three platforms.我在基于 Red Hat 的系统、基于 Debian 的系统和 OSX 上测试了这个脚本,它在所有三个平台上都按预期工作。 I did not have time to test on Windows (Cygwin).我没有时间在 Windows (Cygwin) 上进行测试。

For validation of YYYY-MM-DD (ISO 8601) dates on OSX in the BASH shell, the following approach validates both the format and the date.为了在 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. It first uses a regular expression match to check the format.它首先使用正则表达式匹配来检查格式。
  2. Then, it converts the date to epoch time and then back to a date.然后,它将日期转换为纪元时间,然后再转换回日期。
  3. If the original and twice-converted dates match, then it is valid.如果原始日期和两次转换的日期匹配,则它是有效的。

Test a valid date: 2005-11-30测试有效日期:2005-11-30

$ isYYYYMMDDdate 2005-11-30
0

Test an invalid date: 2005-11-31测试无效日期:2005-11-31

$ isYYYYMMDDdate 2005-11-31
1

Test a valid date formatted incorrectly: 1979-20-04测试格式不正确的有效日期:1979-20-04

$ isYYYYMMDDdate 1979-20-04
1

case statements make it easy to support multiple formats and capturing date-parts, ie 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

I hope this helps.我希望这有帮助。

The date command will parse a date given with the -d argument. date命令将解析使用-d参数给出的日期。 If the date is invalid, an error message is printed to STDERR and date exits with an error status.如果日期无效,则会向 STDERR 打印一条错误消息,并且date以错误状态退出。 If the date is valid, it prints the date on STDOUT and exits with a success status.如果日期有效,它将在 STDOUT 上打印日期并以成功状态退出。

Because of this, date -d "$date" can be used directly in a bash if statement.因此, date -d "$date"可以直接在bash if语句中使用。

The first wrinkle is that to prevent printing a message for valid dates, you need to redirect STDOUT to /dev/null using >/dev/null .第一招是一种能够防止印刷的有效日期的消息,您需要将stdout到/dev/null使用>/dev/null

The second wrinkle is that date accepts an empty string as a valid date without complaint.第二个问题是date接受空字符串作为有效日期而没有抱怨。 In most cases, that should mean that your user didn't enter a date when they should have.在大多数情况下,这应该意味着您的用户没有输入他们应该输入的日期。 You will want to test for an empty date separately using the test [ "z$date" != "z" ]您将需要使用测试[ "z$date" != "z" ]单独测试空日期

date also accepts a variety of formats. date也接受多种格式。 If you are using actual bash (as opposed to dash or some of ther sh variety, you could use regular expressions against your preferred format in place of a simple check for an empty string. For example to check my preferred ISO format, I would use: [[ "$date" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]如果您使用的是实际的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

If you try this with an invalid date (such as 2001-01-53 ), it doesn't get into the if and it prints out:如果您使用无效日期(例如2001-01-53 )尝试此操作,它不会进入if并打印出来:

date: invalid date '2001-01-53'日期:无效日期“2001-01-53”

Alternately, you could check if the date is invalid and exit:或者,您可以检查日期是否无效并退出:

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"

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM