Cepat menghitung perbedaan tanggal

84

Saya sering ingin membuat beberapa perhitungan tanggal cepat, seperti:

  • Apa perbedaan antara kedua tanggal ini?
  • Apa tanggal dan minggu setelah tanggal lainnya?

Saya biasanya membuka kalender dan menghitung hari, tetapi saya pikir harus ada program / skrip yang dapat saya gunakan untuk melakukan perhitungan semacam ini. Ada saran?

daniel kullmann
sumber
3
Lihat juga Alat di UNIX untuk mengurangi tanggal ketika tanggal GNU tidak tersedia.
Gilles

Jawaban:

107

"N minggu setelah kencan" mudah dengan tanggal GNU (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

Saya tidak tahu cara sederhana untuk menghitung perbedaan antara dua tanggal, tetapi Anda dapat membungkus sedikit logika sekitar tanggal (1) dengan fungsi shell.

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

Tukar d1dan d2jika Anda menginginkan perhitungan tanggal dengan cara lain, atau dapatkan pemain yang lebih menarik untuk membuatnya tidak masalah. Lebih lanjut, jika ada transisi non-DST ke DST dalam interval, satu hari hanya akan panjang 23 jam; Anda dapat menggantinya dengan menambahkan ½ hari ke jumlah.

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

Untuk satu set alat portabel coba dateutils saya sendiri . Dua contoh Anda akan menjadi satu baris:

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

atau dalam beberapa minggu dan hari:

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

dan

dadd 2011-11-15 21w
=>
  2012-04-10
hroptatyr
sumber
3
Memberi +1 batu alat Anda (meskipun dateadd -i '%m%d%Y' 01012015 +1dtampaknya tidak berfungsi, itu hanya menggantung di sana tanpa batas waktu ... itu berfungsi jika spesifikasi tanggal dipisahkan oleh char, ada char ... ada ide apa yang salah?)
don_crissti
2
@don_crissti Parser tidak dapat membedakan antara tanggal dan durasi hanya angka, itu tetap di master saat ini (d0008f98)
hroptatyr
Apakah Anda memiliki distribusi biner dateutils pada jendela?
mosh
@ oh tidak, dan saya tidak punya fasilitas untuk mencoba.
hroptatyr
Terlambat ke pesta di sini, tetapi dateutils ada di cygwin jika Anda perlu menggunakan Windows.
gregb212
30

Contoh python untuk menghitung jumlah hari saya berjalan di planet ini:

$ python
>>> from datetime import date as D
>>> print (D.today() - D(1980, 6, 14)).days
11476
Daniel Näslund
sumber
2
Untuk berjaga-jaga jika seseorang ingin ini berperilaku seperti perintah tunggal, alih-alih mengetikkan juru bahasa interaktif: ychaouche@ychaouche-PC ~ $ python -c "from datetime import date as d; print (d.today() - d(1980, 6, 14)).days" 12813 ychaouche@ychaouche-PC ~ $
ychaouche
1
ini bekerja untuk saya python3 -c "dari tanggal impor datetime sebagai d; print (d.today () - d (2016, 1, 9))" hari pada akhirnya tidak diperlukan
Kiran K Telukunta
13

Saya biasanya lebih suka memiliki waktu / tanggal dalam format utime unix (jumlah detik sejak zaman, ketika tujuh puluhan dimulai, UTC). Dengan cara itu selalu bermuara pada pengurangan atau penambahan detik.

Masalahnya biasanya mengubah tanggal / waktu menjadi format ini.

Dalam lingkungan shell / skrip Anda bisa mendapatkannya dengan date '+%s' Pada saat penulisan, waktu saat ini adalah 1321358027.

Untuk membandingkan dengan 2011-11-04 (ulang tahun saya) date '+%s' -d 2011-11-04,, menghasilkan 1320361200. Kurangi: expr 1321358027 - 1320361200beri 996827detik, yaitu expr 996827 / 86400= 11 hari yang lalu.

Mengubah dari utime (format 1320361200) menjadi tanggal sangat mudah dilakukan misalnya C, PHP atau perl, menggunakan pustaka standar. Dengan GNU date, -dargumennya dapat diawali dengan @untuk menunjukkan format "Detik sejak Zaman".

MattBianco
sumber
7
Dengan tanggal GNU, date -d @1234567890konversi dari detik sejak zaman ke format tanggal apa pun yang Anda tentukan.
Gilles
1
@Gilles: itu brilian. Tidak dapat menemukannya di halaman manual. Di mana Anda belajar itu?
MattBianco
1
@MattBianco, lihat info date, terutama Detik sejak node Epoch : "Jika Anda mendahului nomor dengan` @ ', itu mewakili cap waktu internal sebagai hitungan detik. "
manatwork
8

Jika alat grafis OK untuk Anda, saya sungguh-sungguh merekomendasikan qalculate(kalkulator dengan penekanan pada konversi unit, ia dilengkapi dengan antarmuka GTK dan KDE, IIRC). Di sana Anda bisa mengatakan misalnya

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

untuk mendapatkan jumlah hari (140, sejak 1900 bukan tahun kabisat) antara tanggal, tetapi tentu saja Anda juga dapat melakukan hal yang sama untuk kali:

17:12:45 − 08:45:12

menghasilkan 8.4591667jam atau, jika Anda mengatur output ke format waktu 8:27:33,.

quazgar
sumber
3
Itu hebat, dan bahkan lebih lagi karena qalculate memang memiliki CLI. Coba kalau qalcbegitu help days.
Sparhawk
qcalccontoh: qalc -t 'days(1900-05-21, 1900-01-01)'-> 140
sierrasdetandil
8

Ini muncul ketika menggunakan date -d "$death_date - $y years - $m months - $d days"untuk mendapatkan tanggal lahir (untuk silsilah). Perintah itu SALAH. Bulan tidak semuanya sama, jadi (date + offset) - offset != date. Usia, dalam tahun / bulan / hari, adalah langkah maju dari tanggal lahir.

$ 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)

Date memberikan output yang benar dalam kedua kasus, tetapi dalam kasus kedua Anda menanyakan pertanyaan yang salah. Itu penting YANG 11 bulan dalam setahun dari penutup +/- 11, sebelum menambah / mengurangi hari. Sebagai contoh:

$ 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

Untuk mengurangi menjadi operasi terbalik dari penambahan, urutan operasi harus dibalik. Menambahkan menambahkan tahun, MAKA bulan, MAKA hari. Jika mengurangi menggunakan urutan yang berlawanan, maka Anda akan kembali ke titik awal Anda. Tidak, jadi Anda tidak, jika hari offset melintasi batas bulan di bulan panjang yang berbeda.

Jika Anda perlu bekerja mundur dari tanggal dan usia akhir, Anda dapat melakukannya dengan beberapa pemanggilan date. Pertama kurangi hari, lalu bulan, lalu tahun. (Saya pikir tidak aman untuk menggabungkan tahun dan bulan dalam satu datedoa tunggal , karena tahun kabisat mengubah panjang Februari.)

Peter Cordes
sumber
4

Cara lain untuk menghitung perbedaan antara dua tanggal pada tahun kalender yang sama Anda bisa menggunakan ini:

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"
  • Baris 1 menyatakan ke shell mana juru bahasa harus digunakan.
  • Baris 2 memberikan nilai dari keluar dateke variabel DATEfirstnum. The -dbendera menampilkan string dalam format waktu dalam hal ini 14 Mei 2014 dan +"%j"memberitahu dateuntuk memformat output untuk hanya hari tahun (1-365).
  • Baris 3 sama dengan Baris 2 tetapi dengan tanggal dan format berbeda untuk string, 31 Desember 2014.
  • Baris 4 memberikan nilai DAYSdifpada perbedaan dua hari.
  • Baris 5 menampilkan nilai DAYSdif.

Ini berfungsi dengan versi GNU date, tetapi tidak pada versi PC-BSD / FreeBSD. Saya menginstal coreutilsdari port ports dan menggunakan perintah /usr/local/bin/gdatesebagai gantinya.

Justin Holcomb
sumber
1
Script ini tidak akan berjalan. Ada kesalahan ketik pada baris terakhir dan spasi di sekitar penugasan variabel, jadi bash berusaha untuk menjalankan program yang disebut DATEfirst name dengan dua argumen. Coba ini: DATEfirstnum=$(date -d "$1" +%s) DATElastnum=$(date -d "$2" +%s) Juga, skrip ini tidak akan dapat menghitung perbedaan antara dua tahun yang berbeda. +%jmengacu pada hari tahun (001..366) sehingga ./date_difference.sh 12/31/2001 12/30/2014output -1. Seperti jawaban lain yang dicatat, Anda perlu mengubah kedua tanggal menjadi detik sejak 1970-01-01 00:00:00 UTC.
Enam
Anda tidak perlu $di dalam ekspresi aritmatika: $((DATElastnum - DATEfirstnum))juga akan berfungsi.
Ruslan
3

Saya sering menggunakan SQL untuk perhitungan tanggal. Misalnya MySQL , PostgreSQL atau 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

Lain kali saya hanya merasa ingin untuk JavaScript. Misalnya SpiderMonkey , WebKit , Seed atau 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

(Awas saat melewati bulan ke Datekonstruktor objek JavaScript . Mulai dengan 0.)

manatwork
sumber
3

Dengan bantuan solusi dannas ini dapat dilakukan dalam satu baris dengan kode berikut:

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

(Bekerja di Python 2.x dan Python 3.)

Kiran K Telukunta
sumber
1
Anda dapat mengedit posting Anda alih-alih berkomentar
Stephen Rauch
3

datedan bash dapat melakukan perbedaan tanggal (opsi OS X ditampilkan). Tempatkan tanggal yang terakhir lebih dulu.

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

Ada juga perhitungan waktu unit GNU yang dikombinasikan dengan tanggal GNU:

$ 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 adalah unit di Linux, gdate adalah tanggal)

Larry
sumber
1

datediff.sh di github: 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
pengguna178063
sumber
1

jawaban camh menangani sebagian besar dari itu, tetapi kita dapat meningkatkan untuk berurusan dengan pembulatan, zona waktu, dll, ditambah kita mendapatkan beberapa presisi ekstra dan kemampuan untuk memilih unit kami:

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"))
}

-dmemberi tahu datebahwa kami menyediakan tanggal untuk dikonversi. +%s.%Nmengubah tanggal-waktu ke detik.nanoseconds sejak 1970-01-01 00:00:00 UTC. bcmenghitung perbedaan antara dua angka, dan faktor pembagian memberi kita unit yang berbeda. printfmenambahkan 0 sebelum tempat desimal jika diperlukan ( bctidak) dan memastikan pembulatan pergi ke terdekat ( bchanya terpotong). Anda juga bisa menggunakannya awk.

Sekarang mari kita jalankan ini dengan test case yang funky,

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

Perhatikan bahwa karena panjang bulan atau tahun tidak selalu sama, tidak ada jawaban "benar" di sana, meskipun orang dapat menggunakan 365,24 hari sebagai perkiraan yang masuk akal saat ini.

TTT
sumber
0

Anda dapat menggunakan perpustakaan Velk awk :

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

Atau:

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

Hasil:

7
Steven Penny
sumber