web-dev-qa-db-ja.com

シェルで2つの日付を比較する方法は?

シェルで2つの日付を比較するにはどうすればよいですか?

これはそのままでは機能しませんが、これを使用する方法の例を次に示します。

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

if [ $todate -ge $cond ];
then
    break
fi                           

どうすれば望ましい結果を得ることができますか?

95
Abdul

正しい答えはまだありません:

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

if [ $todate -ge $cond ];
then
    break
fi  

これにはGNU日付が必要です。BSDの同等のdate構文date(デフォルトでOSXにあるような)はdate -j -f "%F" 2014-08-19 +"%s"

122
user93501

標準の文字列比較を使用して、[年、月、日の形式の文字列の]年代順を比較できます。

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

if [[ "$date_a" > "$date_b" ]] ;
then
    echo "break"
fi

ありがたいことに、[YYYY-MM-DD形式を使用する文字列]がアルファベット順に並べ替え*られると、時系列順に並べ替え*られます。

(*-ソートまたは比較)

この場合、特別なことは何も必要ありません。わーい!

36
user2533809

比較の日付形式がありません:

#!/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

ループ構造もありません。どのようにしてより多くの日付を取得する予定ですか?

32
LPoblet

これはループ構造の問題ではなく、データ型の問題です。

これらの日付(todateおよびcond)は数値ではなく文字列であるため、testの「-ge」演算子は使用できません。 (角括弧表記は、コマンドtestと同等です。)

あなたができることは、それらが整数になるように日付に異なる表記法を使うことです。例えば:

date +%Y%m%d

2013年7月15日の20130715のような整数を生成します。次に、「-ge」および同等の演算子を使用して日付を比較できます。

pdate:日付が指定されている場合(たとえば、2013-07-13形式のファイルから日付を読み取っている場合)、trを使用して簡単に前処理できます。

$ echo "2013-07-15" | tr -d "-"
20130715
8
sergut

演算子-geは、日付ではなく整数でのみ機能します。

スクリプトがbash、ksh、またはzshスクリプトの場合は、代わりに<演算子を使用できます。この演算子は、POSIX標準をはるかに超えないダッシュまたはその他のシェルでは使用できません。

if [[ $cond < $todate ]]; then break; fi

どのシェルでも、ダッシュを削除するだけで、日付の順序を尊重しながら文字列を数値に変換できます。

if [ "$(echo "$todate" | tr -d -)" -ge "$(echo "$cond" | tr -d -)" ]; then break; fi

または、従来の方法でexprユーティリティを使用することもできます。

if expr "$todate" ">=" "$cond" > /dev/null; then break; fi

ループでのサブプロセスの呼び出しは低速になる可能性があるため、シェル文字列処理構造を使用して変換を行うことをお勧めします。

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

もちろん、最初にハイフンなしで日付を取得できる場合は、それらを-geと比較できます。

文字列をUNIXタイムスタンプに変換します(1.1.1970 0:0:0からの秒数)。これらは簡単に比較できます

unix_todate=$(date -d "${todate}" "+%s")
unix_cond=$(date -d "${cond}" "+%s")
if [ ${unix_todate} -ge ${unix_cond} ]; then
   echo "over condition"
fi
1
InuSasha

タイトルが付けられた記事にあるこのメソッドもあります: BASHでの単純な日付と時刻の計算 unix.comから。

これらの関数は そのスレッドのスクリプト!からの抜粋です

date2stamp () {
    date --utc --date "$1" +%s
}

dateDiff (){
    case $1 in
        -s)   sec=1;      shift;;
        -m)   sec=60;     shift;;
        -h)   sec=3600;   shift;;
        -d)   sec=86400;  shift;;
        *)    sec=86400;;
    esac
    dte1=$(date2stamp $1)
    dte2=$(date2stamp $2)
    diffSec=$((dte2-dte1))
    if ((diffSec < 0)); then abs=-1; else abs=1; fi
    echo $((diffSec/sec*abs))
}

使用法

# calculate the number of days between 2 dates
    # -s in sec. | -m in min. | -h in hours  | -d in days (default)
    dateDiff -s "2006-10-01" "2006-10-31"
    dateDiff -m "2006-10-01" "2006-10-31"
    dateDiff -h "2006-10-01" "2006-10-31"
    dateDiff -d "2006-10-01" "2006-10-31"
    dateDiff  "2006-10-01" "2006-10-31"
1
slm

@Gillesの回答( "演算子-geは整数でのみ機能します")をエコーし​​ます。ここに例を示します。

curr_date=$(date +'%Y-%m-%d')
echo "$curr_date"
2019-06-20

old_date="2019-06-19"
echo "$old_date"
2019-06-19

https://stackoverflow.com/questions/10990949/convert-date-time-string-to-Epochの@ mike-qの回答に従って、datetime整数変換からEpochへ-in-bash

curr_date_int=$(date -d "${curr_date}" +"%s")
echo "$curr_date_int"
1561014000

old_date_int=$(date -d "${old_date}" +"%s")
echo "$old_date_int"
1560927600

"$curr_date"はより大きい(より新しい)"$old_date"ですが、この式は誤ってFalseと評価されます。

if [[ "$curr_date" -ge "$old_date" ]]; then echo 'foo'; fi

...ここに明示的に示します:

if [[ "$curr_date" -ge "$old_date" ]]; then echo 'foo'; else echo 'bar'; fi
bar

整数比較:

if [[ "$curr_date_int" -ge "$old_date_int" ]]; then echo 'foo'; fi
foo

if [[ "$curr_date_int" -gt "$old_date_int" ]]; then echo 'foo'; fi
foo

if [[ "$curr_date_int" -lt "$old_date_int" ]]; then echo 'foo'; fi

if [[ "$curr_date_int" -lt "$old_date_int" ]]; then echo 'foo'; else echo 'bar'; fi
bar
0
Victoria Stuart

Mysqlの組み込み関数を使用して日付を比較することもできます。結果は「日数」で表示されます。

from_date="2015-01-02"
date_today="2015-03-10"
diff=$(mysql -u${DBUSER} -p${DBPASSWORD} -N -e"SELECT DATEDIFF('${date_today}','${from_date}');")

変数に応じて、$DBUSER変数と$DBPASSWORD変数の値を挿入するだけです。

0
Abid Khan

日付は整数ではなく文字列です。それらを標準の算術演算子と比較することはできません。

セパレータが_-_であることが保証されている場合に使用できる1つのアプローチ:

_IFS=-
read -ra todate <<<"$todate"
read -ra cond <<<"$cond"
for ((idx=0;idx<=numfields;idx++)); do
  (( todate[idx] > cond[idx] )) && break
done
unset IFS
_

これはbash 2.05b.0(1)-releaseまでさかのぼります。

0
Josh McGee

この比較がハイフン付きの日付文字列でうまく機能しない理由は、シェルは先行する0を持つ数値が8進数(この場合は月 "07")であると想定するためです。さまざまな解決策が提案されてきましたが、最も速くて簡単なのはハイフンを取り除くことです。 Bashには文字列置換機能があり、これをすばやく簡単に実行できるため、比較を算術式として実行できます。

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

if (( ${todate//-/} > ${cond//-/} ));
then
    echo larger
fi
0
John McNulty

FWIW:Macでは、「2017-05-05」のような日付だけを日付にフィードすると、日付に現在の時刻が追加され、エポック時刻に変換するたびに異なる値が得られます。固定日付のより一貫したエポック時間を取得するには、時間、分、秒のダミー値を含めます。

date -j -f "%Y-%m-%d %H:%M:%S" "2017-05-05 00:00:00" +"%s"

これは、macOSに同梱されている日付のバージョンに限定された奇妙なものである可能性があります... macOS 10.12.6でテストされました。

0
s84