Hızla tarih farkı hesapla


84

Sık sık, bazı hızlı tarih hesaplamaları yapmak istiyorum:

  • Bu iki tarih arasındaki fark nedir?
  • Bu tarihten sonra n hafta sonra tarih nedir?

Genelde bir takvim açar ve günleri sayarım, ancak bu tür hesaplamaları yapmak için kullanabileceğim bir program / komut dosyası olması gerektiğini düşünüyorum. Baska öneri?


3
Ayrıca GNU tarihinin uygun olmadığı tarihler çıkarmak için UNIX’deki Araç’a bakınız .
Gilles

Yanıtlar:


106

GNU tarihiyle "bir tarihten sonra n hafta" kolaydır (1):

$ date -d 'now + 3 weeks'
Tue Dec  6 23:58:04 EST 2011
$ date -d 'Aug 4 + 3 weeks'
Thu Aug 25 00:00:00 EST 2011
$ date -d 'Jan 1 1982 + 11 weeks'
Fri Mar 19 00:00:00 EST 1982

İki tarih arasındaki farkı hesaplamanın basit bir yolunu bilmiyorum, ancak tarih (1) etrafında bir kabuk işlevi olan küçük bir mantığı kapatabilirsiniz.

datediff() {
    d1=$(date -d "$1" +%s)
    d2=$(date -d "$2" +%s)
    echo $(( (d1 - d2) / 86400 )) days
}
$ datediff '1 Nov' '1 Aug'
91 days

Değişim d1ve d2tarih hesaplamasını başka bir yolla istiyorsanız veya farketmemesi için biraz meraklısı olun. Ayrıca, aralıkta DST -DST olmayan bir geçiş olması durumunda, günlerden biri sadece 23 saat olacaktır; toplamı ½ gün ekleyerek telafi edebilirsiniz.

echo $(( (((d1-d2) > 0 ? (d1-d2) : (d2-d1)) + 43200) / 86400 )) days

40

Bir dizi taşınabilir araç için kendi tarih bilgilerimi deneyin . İki örneğiniz tek gömleklere kadar kaynatır:

ddiff 2011-11-15 2012-04-11
=>
  148

veya haftalar ve günlerde:

ddiff 2011-11-15 2012-04-11 -f '%w %d'
=>
  21 1

ve

dadd 2011-11-15 21w
=>
  2012-04-10

3
1 araçlarınız kaya (gerçi dateadd -i '%m%d%Y' 01012015 +1d? İşe görünmüyor, sadece tarih gözlük char, herhangi bir karakter ... yanlış ne herhangi bir fikir ile ayrılır eğer çalışır ... orada süresiz kapatır)
don_crissti

2
@don_crissti ayrıştırıcı rakamları salt tarihleri ve süreleri arasında ayrım olamazdı, geçerli ustası (d0008f98) içinde çözüldü
hroptatyr

Pencerenin dateutils ikili dağılımına sahip misiniz?
Mosh

@ mosh hayır ve denemek için imkanlarım yok.
hroptatyr

Partiye geç saatlerde, ancak Windows kullanmanız gerekiyorsa dateutils cygwin'de.
gregb212

30

Gezegende yürüdüğüm gün sayısını hesaplamak için bir python örneği:

$ python
>>> from datetime import date as D
>>> print (D.today() - D(1980, 6, 14)).days
11476

2
Birisinin bunun sadece tek bir komut gibi davranmasını ychaouche@ychaouche-PC ~ $ python -c "from datetime import date as d; print (d.today() - d(1980, 6, 14)).days" 12813 ychaouche@ychaouche-PC ~ $
istemesi

1
bu benim için çalışıyor python3 -c "tarih gününden itibaren d olarak; yazdırma (d.today () - d (2016, 1, 9))" "gün sonunda zorunlu değil
Kiran K Telukunta

13

Ben genellikle zaman / tarihin unix utime biçiminde olmasını tercih ederim (yetmişlerin başladığı zamandan beri saniye sayısı, UTC). Bu şekilde her zaman düz çıkarma ya da saniye ekleme işlemine başlar.

Sorun genellikle bir tarih / saati bu formata dönüştürme haline gelir.

Bir kabuk ortamında / betiği ile alabilirsiniz date '+%s' . Yazma sırasında, şimdiki zaman 1321358027.

2011-11-04 (benim doğum günüm) ile karşılaştırmak date '+%s' -d 2011-11-04, verimlidir 1320361200. Çıkar: expr 1321358027 - 1320361200vermektedir 996827olan saniye expr 996827 / 8640011 gün önce =.

Utime'dan (1320361200 formatı) bir tarihe dönüştürmek, standart kütüphaneleri kullanarak, örneğin C, PHP veya perl'de yapmak için çok basittir. GNU ile date, -dargüman @"Epoch'tan beri Saniye" biçiminde göstermek için hazırlanabilir.


7
GNU tarihiyle, date -d @1234567890çağdan bu yana geçen saniye, belirttiğiniz tarih biçimine dönüştürür.
Gilles

1
@Gilles: bu harika. Manpage üzerinde bulamadım. Bunu nereden öğrendin?
MattBianco

1
@MattBianco, bkz info date, özellikle Epoch beri Saniye düğümü: “Eğer` ile bir numara önüne varsa @', bu saniyelik bir sayım olarak bir iç zaman damgası temsil ediyor.”
manatwork

8

Bu date -d "$death_date - $y years - $m months - $d days"doğum tarihini almak için kullanıldığında (şecere için) ortaya çıktı. Bu komut YANLIŞ. Aylar hepsi aynı uzunlukta değil (date + offset) - offset != date. Yaş, yıl / ay / gün olarak, doğum tarihinden itibaren ileri giden önlemlerdir.

$ date --utc -d 'mar 28 1867 +72years +11months +2days'
Fri Mar  1 00:00:00 UTC 1940

$ date --utc -d 'mar 1 1940 -72years -11months -2days'
Sat Mar 30 00:00:00 UTC 1867
# (2 days later than our starting point)

Tarih her iki durumda da doğru çıktı veriyor, ancak ikinci durumda yanlış soruyu soruyordunuz. WHICH'in yılın 11 ayı ile +/- 11'in kapattığı günler eklenir / çıkarılır. Örneğin:

$ date --utc -d 'mar 31 1939  -1month'
Fri Mar  3 00:00:00 UTC 1939
$ date --utc -d 'mar 31 1940  -1month' # leap year
Sat Mar  2 00:00:00 UTC 1940
$ date --utc -d 'jan 31 1940  +1month' # leap year
Sat Mar  2 00:00:00 UTC 1940

Çıkarma işleminin ters işlem yapması için işlem sırasının tersine çevrilmesi gerekir. Yıllar, THEN aylar, THEN günler ekler. Çıkarma işlemi ters siparişi kullandıysa, başlangıç ​​noktanıza dönersiniz. Öyle değil, bu yüzden değil, eğer gün ofseti farklı bir aydaki bir ay sınırını geçerse.

Bir bitiş tarihi ve yaşından itibaren geriye doğru çalışmanız gerekiyorsa, bunu birden fazla çağrı ile yapabilirsiniz date. İlk önce günleri, sonra ayları, sonra yılları çıkarın. ( dateYılları ve ayları, şubatın uzunluğunu değiştiren artık yıllar nedeniyle tek bir başvuruda birleştirmenin güvenli olduğunu sanmıyorum .)


7

Eğer grafiksel bir araç sizin için uygunsa, içtenlikle öneririm qalculate(birim dönüşümlere önem veren bir hesap makinesi, bir GTK ve KDE arayüzü, IIRC ile birlikte gelir). Orada söyleyebilirsin örneğin

days(1900-05-21, 1900-01-01)

Tarihler arasında gün sayısını (140, 1900'den beri artık bir yıl değildi) almak için elbette aynı şeyi zaman zaman da yapabilirsiniz:

17:12:45 − 08:45:12

8.4591667saat verir veya çıktıyı zaman biçimlendirmesine ayarlarsanız 8:27:33,.


3
Bu harika, ve hatta daha çok qalculate çünkü yaptığı bir CLI var. Deneyin qalco zaman help days.
Sparhawk

qcalcörnek: qalc -t 'days(1900-05-21, 1900-01-01)'-> 140
sierrasdetandil

3

Tarih hesaplamaları için sık sık SQL kullanıyorum. Örneğin , MySQL , PostgreSQL veya SQLite :

bash-4.2$ mysql <<< "select datediff(current_date,'1980-06-14')"
datediff(current_date,'1980-06-14')
11477

bash-4.2$ psql <<< "select current_date-'1980-06-14'"
 ?column? 
----------
    11477
(1 row)

bash-4.2$ sqlite2 <<< "select julianday('now')-julianday('1980-06-14');"
11477.3524537035

Diğer zamanlarda sadece JavaScript için havanda hissediyorum. Örneğin , SpiderMonkey , WebKit , Seed veya Node.js :

bash-4.2$ js -e 'print((new Date()-new Date(1980,5,14))/1000/60/60/24)'
11477.477526192131

bash-4.2$ jsc-1 -e 'print((new Date()-new Date(1980,5,14))/1000/60/60/24)'
11477.47757960648

bash-4.2$ seed -e '(new Date()-new Date(1980,5,14))/1000/60/60/24'
11477.4776318287

bash-4.2$ node -pe '(new Date()-new Date(1980,5,14))/1000/60/60/24'
11624.520061481482

(Ayı JavaScript Datenesnesinin yapıcısına iletirken dikkat edin. 0 ile başlar.)


3

Aynı takvim yılının iki tarihi arasındaki farkı hesaplamanın başka bir yolu da bunu kullanabilirsiniz:

date_difference.sh
1  #!/bin/bash
2  DATEfirstnum=`date -d "2014/5/14" +"%j"`
3  DATElastnum=`date -d "12/31/14" +"%j"`
4  DAYSdif=$(($DATElastnum - $DATEfirstnum))
5  echo "$DAYSdif"
  • Satır 1, hangi tercümanın kullanılacağını kabuğa bildirir.
  • Satır 2, değeri dateDATEfirstnum değişkenine dışarı atar . -dBayrak, bu durumda 14 Mayıs 2014 yılında bir zaman biçiminde dizesini görüntüler ve +"%j"söyler dateyıl (1-365) sadece güne çıktı biçimlendirmek için.
  • Satır 3, Satır 2 ile aynıdır, ancak dize için farklı bir tarih ve farklı biçimde, 31 Aralık 2014.
  • Satır 4, değeri DAYSdifiki günün farkına atar .
  • Satır 5, değerini gösterir DAYSdif.

Bu datePC-BSD / FreeBSD versiyonunun GNU versiyonuyla çalışır , ancak çalışmaz. coreutilsPort ağacından yükledim ve /usr/local/bin/gdatebunun yerine komutu kullandım.


1
Bu komut dosyası çalışmayacak. Son satırda bir yazım hatası var ve değişken atamalarının etrafındaki boşluklar var, bu nedenle bash, DATEfirst name adlı bir programı iki argümanla çalıştırmaya çalışıyor. Bunu dene: DATEfirstnum=$(date -d "$1" +%s) DATElastnum=$(date -d "$2" +%s) Ayrıca, bu komut dosyası iki farklı yıl arasındaki farkı hesaplayamayacak. +%jyılın gününü (001..366) belirtir, böylece ./date_difference.sh 12/31/2001 12/30/2014-1 çıkışı olur. Diğer cevapların da belirttiği gibi, her iki tarihi de 1970-01-01 00:00:00 UTC’den bu yana saniyeler içerisinde dönüştürmeniz gerekir.
Altı

$Aritmetik ifadenin içine ihtiyacınız yok : $((DATElastnum - DATEfirstnum))aynı zamanda çalışacak.
Ruslan

3

Dannas çözümleri yardımı ile bu, aşağıdaki kodla bir satırda yapılabilir:

python -c "from datetime import date as d; print(d.today() - d(2016, 7, 26))"

(Hem Python 2.x hem de Python 3'te çalışır.)


1
Yorumunuzu yazmak yerine yazınızı düzenleyebilirsiniz
Stephen Rauch

3

dateve bash tarih farklarını yapabilir (gösterilen OS X seçenekleri). Önce son tarihi yerleştirin.

echo $((($(date -jf%D "04/03/16" +%s) - $(date -jf%D "03/02/16" +%s)) / 86400))
# 31

1

GNU tarihiyle birlikte GNU biriminin zaman hesaplamaları da var:

$ gunits $(gdate +%s)sec-$(gdate +%s -d -1234day)sec 'yr;mo;d;hr;min;s'
        3 yr + 4 mo + 16 d + 12 hr + 37 min + 26.751072 s
$ gunits $(gdate +%s -d '2015-1-2 3:45:00')sec-$(gdate +%s -d '2013-5-6 7:43:21')sec 'yr;mo;d;hr;min;s'
        1 yr + 7 mo + 27 d + 13 hr + 49 min + 26.206759 s

(gunits Linux'ta birimlerdir, tarih tarihidir)


1

github üzerine datediff.sh: gist

#!/bin/bash
#Simplest calculator two dates difference. By default in days

# Usage:
# ./datediff.sh first_date second_date [-(s|m|h|d) | --(seconds|minutes|hours|days)]

first_date=$(date -d "$1" "+%s")
second_date=$(date -d "$2" "+%s")

case "$3" in
"--seconds" | "-s") period=1;;
"--minutes" | "-m") period=60;;
"--hours" | "-h") period=$((60*60));;
"--days" | "-d" | "") period=$((60*60*24));;
esac

datediff=$(( ($first_date - $second_date)/($period) ))
echo $datediff

1

camh'ın cevabı çoğunu önemser, ancak yuvarlama, zaman dilimleri vb. ile başa çıkma konusunda iyileştirmeler yapabiliriz, ayrıca bazı ekstra hassasiyetler ve birimlerimizi seçme yeteneğimizi elde ederiz:

datediff() {
#convert dates to decimal seconds since 1970-01-01 00:00:00 UTC
date1seconds=$(date +%s.%N -d "$date1")
date2seconds=$(date +%s.%N -d "$date2")

#Calculate time difference in various time units
timeseconds=$(printf "%0.8f\n" $(bc <<<"scale=9; ($date2sec-$date1sec)"))
timeminutes=$(printf "%0.8f\n" $(bc <<<"scale=9; ($date2sec-$date1sec)/60"))
  timehours=$(printf "%0.8f\n" $(bc <<<"scale=9; ($date2sec-$date1sec)/3600"))
   timedays=$(printf "%0.8f\n" $(bc <<<"scale=9; ($date2sec-$date1sec)/86400"))
  timeweeks=$(printf "%0.8f\n" $(bc <<<"scale=9; ($date2sec-$date1sec)/604800"))
}

-ddatedönüştürmek için bir tarih-zaman sağladığımızı söyler . +%s.%Ntarih saatini saniye cinsinden değiştirir. 1970-01-01 00:00:00 UTC'den itibaren saniye cinsinden saniye. bcİki sayı arasındaki farkı hesaplar ve bölücü faktörü bize farklı birimleri getirir. printfGerekirse ondalık basamağın önüne 0 ekler ( bcyapmaz) ve yuvarlamanın en yakınına gitmesini sağlar ( bcsadece keser). Ayrıca kullanabilirsiniz awk.

Şimdi bunu korkak bir test davasıyla çalıştıralım,

date1='Tue Jul  9 10:18:04.031 PST 2020'
date2='Wed May  8 15:19:34.447 CDT 2019'
datediff "$date1" "$date2"

echo $timeseconds seconds
-36971909.584000000 seconds

echo $timeminutes minutes
-616198.493066667 minutes

echo $timehours hours
-10269.974884444 hours

echo $timedays days
-427.915620185 days

echo $timeweeks weeks
-61.130802884 weeks

Bir ayın veya yılın uzunluğu her zaman aynı olmadığından, bugünlerde tek bir "doğru" cevap yoktur, ancak bugünlerde 365.24 gün makul bir yaklaşım olarak kullanılabilir.


0

Awk Velor kütüphanesini kullanabilirsiniz :

velour -n 'print t_secday(t_utc("2017-4-12") - t_utc("2017-4-5"))'

Veya:

velour -n 'print t_secday(t_utc(ARGV[1]) - t_utc(ARGV[2]))' 2017-4-12 2017-4-5

Sonuç:

7
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.