কিভাবে একটি খোল দুটি তারিখ তুলনা করতে?


88

একটি খোলসের সাথে কীভাবে দুটি তারিখের তুলনা করা যায়?

আমি এটি কীভাবে ব্যবহার করতে চাই তার উদাহরণ এখানে দেওয়া হয়েছে, যদিও এটি যেমনটি কাজ করে না:

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

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

আমি কীভাবে পছন্দসই ফলাফল অর্জন করতে পারি?


আপনি কি জন্য লুপ করতে চান? আপনি লুপ চেয়ে শর্তসাপেক্ষ বলতে চান?
মাদুর

আপনি ফাইল ট্যাগ কেন ? এই তারিখগুলি আসলে ফাইলের সময়?
manatwork

এটি স্ট্যাকওভারফ্লোতে দেখুন: stackoverflow.com/questions/8116503/…
স্ল্যাম

উত্তর:


107

সঠিক উত্তরটি এখনও অনুপস্থিত:

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

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

নোট করুন যে এর জন্য GNU তারিখ প্রয়োজন requires dateবিএসডি এর সমতুল্য বাক্য গঠন date(যেমন ডিফল্টরূপে ওএসএক্সে পাওয়া যায়)date -j -f "%F" 2014-08-19 +"%s"


10
ডোনো কেন কেউ এটিকে নিম্নচাপ দিয়েছে, এটি বেশ নির্ভুল এবং কুরুচিপূর্ণ স্ট্রিংগুলি মোকাবেলা করে না। আপনার তারিখটিকে ইউনিক্স টাইমস্ট্যাম্পে (সেকেন্ডে) রূপান্তর করুন, ইউনিক্স টাইমস্ট্যাম্পগুলি তুলনা করুন।
নিকোলি

আমি মনে করি, আমার এই সমাধানটির মূল সুবিধাটি হ'ল আপনি সহজেই সংযোজন বা বিয়োগগুলি করতে পারেন। উদাহরণস্বরূপ, আমি এক্স সেকেন্ডের টাইমআউট পেতে চেয়েছিলাম, তবে আমার প্রথম ধারণাটি ( timeout=$(`date +%Y%m%d%H%M%S` + 500)) অবশ্যই স্পষ্টতই ভুল।
আইজেল

আপনি ন্যানোসেকেন্ডস যথার্থতার সাথে অন্তর্ভুক্ত করতে পারেনdate -d 2013-07-18 +%s%N
টাইপলজিক

32

তুলনা করার জন্য আপনি তারিখের ফর্ম্যাটটি মিস করছেন:

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

আপনি লুপিং স্ট্রাকচারগুলিও হারিয়েছেন, আপনি আরও তারিখগুলি কীভাবে পাওয়ার পরিকল্পনা করছেন?


এটি dateম্যাকস সহ শিপডের সাথে কাজ করে না ।
ফ্লিম

date -dমানহীন এবং আদর্শ ইউনিক্সে কাজ করে না। বিএসডি তে এটি কেনেল মান সেট করার চেষ্টা করে DST
সহজেই

32

কালানুক্রমিক ক্রম [একটি বছর, মাস, দিনের ফর্ম্যাটে স্ট্রিংগুলির] তুলনা করার জন্য একটি স্ট্যান্ডার্ড স্ট্রিং তুলনা ব্যবহার করতে পারে।

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

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

ধন্যবাদ, যখন [YYYY-MM-DD ফর্ম্যাট ব্যবহার করে এমন স্ট্রিং] যখন বর্ণানুক্রমিকভাবে বাছাই করা হয়, সেগুলি কালানুক্রমিক ক্রমেও বাছাই করা হয়।

(* - বাছাই বা তুলনা করা)

এক্ষেত্রে অভিনব কোনও দরকার নেই। হ্যাঁ!


এখানে অন্য শাখা কোথায়?
ভ্লাদিমির দেশপোটোভিচ

এই একমাত্র সমাধান যা সিয়েরা ম্যাকোজে আমার জন্য কাজ করেছে
ভ্লাদিমির দেশপোটোভিচ

এটি সহজ যে আমার সমাধান if [ $(sed -e s/-//g <<< $todate) -ge $(sed -e s/-//g <<< $cond) ];... এই তারিখের ফর্ম্যাটটি স্ট্যান্ডার্ড আলফা সংখ্যার বাছাই করে বা -ছাঁটাই করে এবং সংখ্যাগতভাবে সাজানোর জন্য ডিজাইন করা হয়েছিল ।
ctrl-alt-delor

এটি এখানে খুব দূর থেকে স্মার্ট উত্তর
এড র্যান্ডাল

7

এটি লুপিং স্ট্রাকচারের সমস্যা নয় তবে ডেটা ধরণের।

এই তারিখগুলি ( todateএবং cond)গুলি স্ট্রিং হয়, সংখ্যা নয়, সুতরাং আপনি "-ge" অপারেটরটি ব্যবহার করতে পারবেন না test। (মনে রাখবেন যে বর্গাকার বন্ধনী চিহ্নিতকরণ কমান্ডের সমান test))

আপনি যা করতে পারেন তা হ'ল আপনার তারিখের জন্য আলাদা স্বরলিপি ব্যবহার করুন যাতে তারা পূর্ণসংখ্যা হয়। উদাহরণ স্বরূপ:

date +%Y%m%d

15 জুলাই, 2013 এর জন্য 20130715 এর মতো পূর্ণসংখ্যা উত্পাদন করবে Then তারপরে আপনি আপনার তারিখগুলি "-ge" এবং সমমানের অপারেটরের সাথে তুলনা করতে পারেন।

আপডেট: যদি আপনার তারিখগুলি দেওয়া হয় (যেমন আপনি 2013-07-13 ফর্ম্যাটে কোনও ফাইল থেকে সেগুলি পড়ছেন) তবে আপনি সহজেই ট্রাম্পের মাধ্যমে এগুলি প্রিপ্রোসেস করতে পারেন।

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

6

অপারেটর -geকেবল পূর্ণসংখ্যার সাথে কাজ করে, যা আপনার তারিখগুলি নয়।

যদি আপনার স্ক্রিপ্টটি ব্যাশ বা ksh বা zsh স্ক্রিপ্ট হয় তবে আপনি <পরিবর্তে অপারেটরটি ব্যবহার করতে পারেন । এই অপারেটরটি ড্যাশ বা অন্যান্য শেলগুলিতে উপলভ্য নয় যা পসিক্স স্ট্যান্ডার্ডের বেশি না।

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

যে কোনও শেলের মধ্যে, ড্যাশগুলি সরিয়ে কেবল তারিখের ক্রমকে সম্মান করে আপনি স্ট্রিংগুলিকে সংখ্যায় রূপান্তর করতে পারেন।

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

বিকল্পভাবে, আপনি traditional 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


এই বাশের অন্য শাখা কোথায়?
ভ্লাদিমির দেশপোটোভিচ

2
এটি সবচেয়ে সঠিক উত্তর বলে মনে হচ্ছে। খুব উপকারী!
মোজতাবা রেজাianীয়

1

আমি স্ট্রিংসকে ইউনিক্স-টাইমস্ট্যাম্পগুলিতে রূপান্তর করি (১.১.১৯70০ সাল থেকে সেকেন্ড 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

এটি dateম্যাকোস সহ জাহাজগুলির সাথে কাজ করে না ।
ফ্লিম

Unix.stackexchange.com/a/170982/100397 এর সমান বলে মনে হচ্ছে যা আপনার কিছু সময় আগে পোস্ট করা হয়েছিল
রোয়াইমা

1

শিরোনাম নিবন্ধ থেকে এই পদ্ধতিটি রয়েছে: ইউনিক্স ডটকম থেকে বিএএসএজে সাধারণ তারিখ এবং সময় গণনা।

এই ফাংশনগুলি সেই থ্রেডের একটি স্ক্রিপ্টের একটি অংশ !

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"

এটি dateম্যাকোস সহ জাহাজগুলির সাথে কাজ করে না ।
ফ্লিম

আপনি চোলাই মাধ্যমে MacOS এর উপর gdate ইনস্টল করা হলে এই সহজে পরিবর্তন করে কাজ করতে পরিবর্তন করা যাবে dateথেকে gdate
slm

1
এই উত্তরটি আমার ক্ষেত্রে খুব সহায়ক হয়েছিল। এটা হার উচিত!
মোজতাবা রেজাianীয়

1

নির্দিষ্ট উত্তর

আমি কাঁটাচামচ কমাতে এবং অনেক কৌশল করতে চাই বলে আমার উদ্দেশ্য রয়েছে:

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

এখন ভালো:

{ read todate; read cond ;} < <(date -f - +%s <<<"$todate"$'\n'"$cond")

এই উভয় ভেরিয়েবল পুনরায় পূরণ হবে $todateএবং $condমাত্র কাঁটাচামচ ব্যবহার করে, এর ouptut সঙ্গে date -f -কোনটা নিতে stdio লাইন দ্বারা এক তারিখ পড়ার জন্য।

অবশেষে, আপনি আপনার লুপটি ভেঙে ফেলতে পারেন

((todate>=cond))&&break

বা একটি ফাংশন হিসাবে :

myfunc() {
    local todate cond
    { read todate
      read cond
    } < <(
      date -f - +%s <<<"$1"$'\n'"$2"
    )
    ((todate>=cond))&&return
    printf "%(%a %d %b %Y)T older than %(%a %d %b %Y)T...\n" $todate $cond
}

ব্যবহার 'র builtin printfকোনটা সঙ্গে তারিখ সময় রেন্ডার করতে পারে যুগান্তকারী থেকে কয়েক সেকেন্ডের (দেখুন man bash;-)

এই স্ক্রিপ্টটিতে কেবল একটি কাঁটাচামচ ব্যবহার করা হয়েছে।

সীমিত কাঁটাচামচ এবং তারিখ পাঠক ফাংশন সহ বিকল্প

এটি একটি উত্সর্গীকৃত উপপ্রসেস তৈরি করবে (কেবলমাত্র একটি কাঁটাচামচ):

mkfifo /tmp/fifo
exec 99> >(exec stdbuf -i 0 -o 0 date -f - +%s >/tmp/fifo 2>&1)
exec 98</tmp/fifo
rm /tmp/fifo

ইনপুট এবং আউটপুট খোলা থাকায়, ফিফো এন্ট্রি মুছতে পারে।

কাজ:

myDate() {
    local var="${@:$#}"
    shift
    echo >&99 "${@:1:$#-1}"
    read -t .01 -u 98 $var
}

নোটা যেমন অকেজো কাঁটাচামচ প্রতিরোধ করতে todate=$(myDate 2013-07-18), ভেরিয়েবলটি নিজেই ফাংশনটি দ্বারা সেট করা উচিত। এবং নিখরচায় সিনট্যাক্সের অনুমতি দেওয়ার জন্য (তারিখের স্ট্রিংয়ে কোট সহ বা ছাড়াই) চলক নামটি অবশ্যই শেষ যুক্তি হতে হবে

তারপরে তারিখের তুলনা:

myDate 2013-07-18        todate
myDate Mon Jul 15 2013   cond
(( todate >= cond )) && {
    printf "To: %(%c)T > Cond: %(%c)T\n" $todate $cond
    break
}

রেন্ডার করতে পারে:

To: Thu Jul 18 00:00:00 2013 > Cond: Mon Jul 15 00:00:00 2013
bash: break: only meaningful in a `for', `while', or `until' loop

যদি লুপের বাইরে থাকে

বা শেল সংযোজক ব্যাশ ফাংশন ব্যবহার করুন:

wget https://github.com/F-Hauri/Connector-bash/raw/master/shell_connector.bash

অথবা

wget https://f-hauri.ch/vrac/shell_connector.sh

(যা একেবারে একই নয়: .shযদি উত্সাহিত না হয় তবে সম্পূর্ণ পরীক্ষার স্ক্রিপ্ট থাকে)

source shell_connector.sh
newConnector /bin/date '-f - +%s' @0 0

myDate 2013-07-18        todate
myDate "Mon Jul 15 2013"   cond
(( todate >= cond )) && {
    printf "To: %(%c)T > Cond: %(%c)T\n" $todate $cond
    break
}

প্রোফাইলিংdate -f - ব্যাশে কীভাবে রিসোর্সেস প্রয়োজনীয়তা হ্রাস করতে পারে তার জন্য একটি ভাল প্রদর্শন রয়েছে ।
এফ। হাউরি

0

তারিখগুলি স্ট্রিং হয়, পূর্ণসংখ্যা নয়; আপনি স্ট্যান্ডার্ড পাটিগণিত অপারেটরগুলির সাথে তাদের তুলনা করতে পারবেন না।

একটি পদ্ধতির আপনি ব্যবহার করতে পারেন, যদি বিভাজকের গ্যারান্টিযুক্ত থাকে -:

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

তারিখগুলি তুলনা করতে আপনি মাইএসকিএল এর বিল্টিন ফাংশনও ব্যবহার করতে পারেন। এটি 'দিনগুলিতে' ফলাফল দেয়।

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

এফডাব্লুআইডাব্লু: ম্যাকের জন্য, "2017-05-05" তারিখের মতো ঠিক একটি তারিখ খাওয়ানো এখনকার সময়টিকে তারিখের সাথে যুক্ত করবে এবং প্রতিবার আপনি যখন এটি রূপান্তরিত করবেন তখন আপনি আলাদা আলাদা মান পাবেন। স্থির তারিখগুলির জন্য আরও সুসংগত যুগের সময় পেতে, ঘন্টা, মিনিট এবং সেকেন্ডের জন্য ডামি মান অন্তর্ভুক্ত করে:

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

এটি ম্যাকোস সহ প্রেরিত তারিখের সংস্করণে সীমাবদ্ধ বিজোড়তা হতে পারে .... ম্যাকোস 10.12.6 এ পরীক্ষা করা হয়েছে।


0

@ গিলসের উত্তর প্রতিধ্বনি করা হচ্ছে ("অপারেটর -ge কেবল পূর্ণসংখ্যার সাথে কাজ করে"), এখানে একটি উদাহরণ রয়েছে।

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

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

datetimeepoch@ মাইক-কিউ এর উত্তর অনুসারে https://stackoverflow.com/questions/10990949/convert-date-time-string-to-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

হাইফেনেটেড ডেট স্ট্রিংয়ের সাথে এই তুলনাটি ভালভাবে কাজ করে না তার কারণটি শেলটি একটি শীর্ষস্থানীয় 0 এর সাথে একটি সংখ্যা ধরে নিয়েছে অষ্টাল, এই ক্ষেত্রে "07" মাসে হয় month প্রস্তাবিত বিভিন্ন সমাধান রয়েছে তবে দ্রুত এবং সহজতম হাইপেনগুলি ছড়িয়ে দেওয়া। বাশের একটি স্ট্রিং প্রতিস্থাপন বৈশিষ্ট্য রয়েছে যা এই দ্রুত এবং সহজ করে তোলে তবে তুলনাটি পাটিগণিতের এক্সপ্রেশন হিসাবে সম্পাদন করা যায়:

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

if (( ${todate//-/} > ${cond//-/} ));
then
    echo larger
fi
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.