A = 2002-20-10
B = 2003-22-11
Wie finde ich den Unterschied in Tagen zwischen zwei Daten?
A = 2002-20-10
B = 2003-22-11
Wie finde ich den Unterschied in Tagen zwischen zwei Daten?
Antworten:
Wenn Sie über GNU verfügen date
, können Sie die Darstellung eines beliebigen Datums drucken ( -d
Option). In diesem Fall konvertieren Sie die Daten in Sekunden seit EPOCH, subtrahieren und dividieren Sie durch 24 * 3600.
Oder brauchen Sie einen tragbaren Weg?
echo "( `date -d $B +%s` - `date -d $A +%s`) / (24*3600)" | bc -l
Die Bash-Methode: Konvertieren Sie die Daten in das Format% y% m% d, und Sie können dies direkt über die Befehlszeile tun:
echo $(( ($(date --date="031122" +%s) - $(date --date="021020" +%s) )/(60*60*24) ))
%y%m%d
formatiert sein. Das Gnu-Datum akzeptiert beispielsweise das %Y-%m-%d
vom OP verwendete Format. Im Allgemeinen ist ISO-8601 eine gute Wahl (und das OP-Format ist ein solches Format). Formate mit zweistelligen Jahren werden besser vermieden.
days_diff=$(( (`date -d $B +%s` - `date -d "00:00" +%s`) / (24*3600) ))
. Beachten Sie, dass $days_diff
dies eine Ganzzahl sein wird (dh keine Dezimalstellen)
date
installierten Variante ab . Es funktioniert für GNU date
. Es funktioniert nicht mit POSIX date
. Dies ist wahrscheinlich kein Problem für die meisten Leser, aber es ist erwähnenswert.
%Y-%m-%d
, bis wir es einführen August 2.0
und October 2.0
das Format von OP ist %Y-%d-%m
. Relevante xkcd: xkcd.com/1179
tl; dr
date_diff=$(( ($(date -d "2015-03-11 UTC" +%s) - $(date -d "2015-03-05 UTC" +%s)) / (60*60*24) ))
Achtung! Viele der hier aufgeführten Bash-Lösungen sind für Datumsbereiche unterteilt, die das Datum umfassen, an dem die Sommerzeit beginnt (sofern zutreffend). Dies liegt daran, dass das Konstrukt $ ((math)) eine 'Floor'- / Kürzungsoperation für den resultierenden Wert ausführt und nur die ganze Zahl zurückgibt. Lassen Sie mich veranschaulichen:
Die Sommerzeit begann am 8. März dieses Jahres in den USA. Verwenden wir also einen Datumsbereich, der Folgendes umfasst:
start_ts=$(date -d "2015-03-05" '+%s')
end_ts=$(date -d "2015-03-11" '+%s')
Mal sehen, was wir mit den doppelten Klammern bekommen:
echo $(( ( end_ts - start_ts )/(60*60*24) ))
Gibt '5' zurück.
Wenn wir dies mit 'bc' genauer tun, erhalten wir ein anderes Ergebnis:
echo "scale=2; ( $end_ts - $start_ts )/(60*60*24)" | bc
Gibt '5,95' zurück - die fehlende 0,05 ist die verlorene Stunde aus der Sommerzeitumschaltung.
Wie soll das richtig gemacht werden?
Ich würde vorschlagen, dies stattdessen zu verwenden:
printf "%.0f" $(echo "scale=2; ( $end_ts - $start_ts )/(60*60*24)" | bc)
Hier rundet der 'printf' das von 'bc' berechnete genauere Ergebnis ab und gibt uns den korrekten Datumsbereich von '6'.
Bearbeiten: Hervorheben der Antwort in einem Kommentar von @ hank-schultz unten, den ich in letzter Zeit verwendet habe:
date_diff=$(( ($(date -d "2015-03-11 UTC" +%s) - $(date -d "2015-03-05 UTC" +%s) )/(60*60*24) ))
Dies sollte auch Schaltsekundensicher sein, solange Sie immer das frühere Datum vom späteren subtrahieren, da Schaltsekunden immer nur zur Differenz beitragen - das Abschneiden rundet effektiv auf das richtige Ergebnis ab.
echo $(( ($(date --date="2015-03-11 UTC" +%s) - $(date --date="2015-03-05 UTC" +%s) )/(60*60*24) ))
, das 6 statt 5 zurückgibt.
Und in Python
$python -c "from datetime import date; print (date(2003,11,22)-date(2002,10,20)).days"
398
bash
und angegeben shell
, daher können wir davon ausgehen, dass es sich um ein * nix-System handelt. Innerhalb solcher Systeme echo
und date
sind zuverlässig vorhanden, Python jedoch nicht.
Das funktioniert bei mir:
A="2002-10-20"
B="2003-11-22"
echo $(( ($(date -d $B +%s) - $(date -d $A +%s)) / 86400 )) days
Druckt
398 days
Was ist los?
date -d
diese , um Zeitzeichenfolgen zu verarbeitendate %s
diese , um Zeitzeichenfolgen seit 1970 in Sekunden umzuwandeln (Unix-Epoche).Wenn die Option -d in Ihrem System funktioniert, können Sie dies auf folgende Weise tun. Es gibt eine Einschränkung, die Schaltjahre nicht berücksichtigen würde, da ich 365 Tage pro Jahr in Betracht gezogen habe.
date1yrs=`date -d "20100209" +%Y`
date1days=`date -d "20100209" +%j`
date2yrs=`date +%Y`
date2days=`date +%j`
diffyr=`expr $date2yrs - $date1yrs`
diffyr2days=`expr $diffyr \* 365`
diffdays=`expr $date2days - $date1days`
echo `expr $diffyr2days + $diffdays`
Hier ist die MAC OS X-Version für Ihre Bequemlichkeit.
$ A="2002-20-10"; B="2003-22-11";
$ echo $(((`date -jf %Y-%d-%m $B +%s` - `date -jf %Y-%d-%m $A +%s`)/86400))
nJoy!
A="2002-20-10"; B="2003-22-11"
echo $(((`date -jf "%Y-%d-%m" "$B" +%s` - `date -jf "%Y-%d-%m" "$A" +%s`)/86400))
, dh sowohl Formate als auch Variablen in doppelte Anführungszeichen zu setzen, andernfalls kann es bei einem anderen Datumsformat (z. B. %b %d, %Y
/ Jul 5, 2017
)
Selbst wenn Sie kein GNU-Datum haben, haben Sie wahrscheinlich Perl installiert:
use Time::Local;
sub to_epoch {
my ($t) = @_;
my ($y, $d, $m) = ($t =~ /(\d{4})-(\d{2})-(\d{2})/);
return timelocal(0, 0, 0, $d+0, $m-1, $y-1900);
}
sub diff_days {
my ($t1, $t2) = @_;
return (abs(to_epoch($t2) - to_epoch($t1))) / 86400;
}
print diff_days("2002-20-10", "2003-22-11"), "\n";
Dies ergibt 398.041666666667
398 Tage und eine Stunde aufgrund der Sommerzeit.
Die Frage tauchte wieder in meinem Feed auf. Hier ist eine präzisere Methode mit einem gebündelten Perl-Modul
days=$(perl -MDateTime -le '
sub parse_date {
@f = split /-/, shift;
return DateTime->new(year=>$f[0], month=>$f[2], day=>$f[1]);
}
print parse_date(shift)->delta_days(parse_date(shift))->in_units("days");
' $A $B)
echo $days # => 398
Hier ist mein Arbeitsansatz mit zsh. Unter OSX getestet:
# Calculation dates
## A random old date
START_DATE="2015-11-15"
## Today's date
TODAY=$(date +%Y-%m-%d)
# Import zsh date mod
zmodload zsh/datetime
# Calculate number of days
DIFF=$(( ( $(strftime -r %Y-%m-%d $TODAY) - $(strftime -r %Y-%m-%d $START_DATE) ) / 86400 ))
echo "Your value: " $DIFF
Ergebnis:
Your value: 1577
Grundsätzlich verwenden wir die Funktion strftime
reverse ( -r
), um unsere Datumszeichenfolge wieder in einen Zeitstempel umzuwandeln, und führen dann unsere Berechnung durch.
Ich würde eine andere mögliche Lösung in Ruby einreichen. Sieht so aus, als wäre es das kleinste und sauberste, das es bisher gibt:
A=2003-12-11
B=2002-10-10
DIFF=$(ruby -rdate -e "puts Date.parse('$A') - Date.parse('$B')")
echo $DIFF
date
oder eine Skriptsprache), und ich denke ehrlich, dass Ruby ein guter Weg ist, um hierher zu gelangen. Diese Lösung ist sehr kurz und verwendet keine nicht standardmäßigen Bibliotheken oder andere Abhängigkeiten. Tatsächlich denke ich, dass die Wahrscheinlichkeit, dass Ruby installiert wird, höher ist als bei einem GNU-Datum.
Verwenden Sie die Shell-Funktionen von http://cfajohnson.com/shell/ssr/ssr-scripts.tar.gz . Sie funktionieren in jeder Standard-Unix-Shell.
date1=2012-09-22
date2=2013-01-31
. date-funcs-sh
_date2julian "$date1"
jd1=$_DATE2JULIAN
_date2julian "$date2"
echo $(( _DATE2JULIAN - jd1 ))
Weitere Informationen finden Sie in der Dokumentation unter http://cfajohnson.com/shell/ssr/08-The-Dating-Game.shtml
Verwenden des Befehls mysql
$ echo "select datediff('2013-06-20 18:12:54+08:00', '2013-05-30 18:12:54+08:00');" | mysql -N
Ergebnis: 21
HINWEIS: Bei der Berechnung werden nur die Datumsteile der Werte verwendet
Referenz: http://dev.mysql.com/doc/refman/5.6/en/date-and-time-functions.html#function_datediff
Unter Unix sollten GNU-Daten installiert sein. Sie müssen nicht von Bash abweichen. Hier ist die aufgereihte Lösung für Tage, nur um die Schritte zu zeigen. Es kann vereinfacht und auf volle Daten erweitert werden.
DATE=$(echo `date`)
DATENOW=$(echo `date -d "$DATE" +%j`)
DATECOMING=$(echo `date -d "20131220" +%j`)
THEDAY=$(echo `expr $DATECOMING - $DATENOW`)
echo $THEDAY
Dies setzt voraus, dass ein Monat 1/12 eines Jahres ist:
#!/usr/bin/awk -f
function mktm(datespec) {
split(datespec, q, "-")
return q[1] * 365.25 + q[3] * 365.25 / 12 + q[2]
}
BEGIN {
printf "%d\n", mktm(ARGV[2]) - mktm(ARGV[1])
}
Probieren Sie es aus:
perl -e 'use Date::Calc qw(Delta_Days); printf "%d\n", Delta_Days(2002,10,20,2003,11,22);'
Angenommen, wir synchronisieren Oracle DB-Sicherungen manuell auf einer tertiären Festplatte. Dann möchten wir alte Backups auf dieser Festplatte löschen. Hier ist ein kleines Bash-Skript:
#!/bin/sh
for backup_dir in {'/backup/cmsprd/local/backupset','/backup/cmsprd/local/autobackup','/backup/cfprd/backupset','/backup/cfprd/autobackup'}
do
for f in `find $backup_dir -type d -regex '.*_.*_.*' -printf "%f\n"`
do
f2=`echo $f | sed -e 's/_//g'`
days=$(((`date "+%s"` - `date -d "${f2}" "+%s"`)/86400))
if [ $days -gt 30 ]; then
rm -rf $backup_dir/$f
fi
done
done
Passen Sie die Verzeichnisse und die Aufbewahrungsfrist ("30 Tage") an Ihre Bedürfnisse an.
Für MacOS Sierra (möglicherweise von Mac OS X Yosemate),
So rufen Sie die Epochenzeit (Sekunden ab 1970) aus einer Datei ab und speichern sie in einer Variablen:
old_dt=`date -j -r YOUR_FILE "+%s"`
Um die Epochenzeit der aktuellen Zeit zu erhalten
new_dt=`date -j "+%s"`
Berechnung der Differenz von mehr als zwei Epochen
(( diff = new_dt - old_dt ))
Um zu überprüfen, ob diff länger als 23 Tage ist
(( new_dt - old_dt > (23*86400) )) && echo Is more than 23 days
echo $(date +%d/%h/%y) date_today
echo " The other date is 1970/01/01"
TODAY_DATE="1970-01-01"
BEFORE_DATE=$(date +%d%h%y)
echo "THE DIFFERNS IS " $(( ($(date -d $BEFORE_DATE +%s) - $(date -d $TODAY_DATE +%s)) )) SECOUND
Verwenden Sie es, um Ihr Datum heute und Ihre Sekunde seit dem gewünschten Datum zu erhalten. Wenn Sie es mit Tagen wollen, teilen Sie es einfach mit 86400
echo $(date +%d/%h/%y) date_today
echo " The other date is 1970/01/01"
TODAY_DATE="1970-01-01"
BEFORE_DATE=$(date +%d%h%y)
echo "THE DIFFERNS IS " $(( ($(date -d $BEFORE_DATE +%s) - $(date -d $TODAY_DATE +%s))/ 86400)) SECOUND