tanggal: dapatkan interval 15 menit saat ini

15

Apakah ada cara saya bisa mendapatkan interval 15 menit saat ini menggunakan perintah tanggal atau serupa?

misalnya sesuatu seperti tanggal %Y.%m.%d %H:%M akan memberi saya 2011.02.22 10:19, saya perlu sesuatu yang menghasilkan 2011.02.22 10:15dalam rentang waktu dari 10:15hingga 10:29.

tidak
sumber

Jawaban:

17

Anda bisa mendapatkan cap waktu unix saat ini dengan date "+%s", temukan kuartal saat ini dengan beberapa matematika sederhana (contoh saya ada di bash) dan mencetaknya kembali dengan format yang lebih baik dengan date:

curdate=`date "+%s"`
curquarter=$(($curdate - ($curdate % (15 * 60))))
date -d"@$curquarter"

The @sintaks untuk mengatur tanggal dan waktu dari timestamp adalah extention GNU sampai saat ini, jika tidak bekerja pada OS Anda, Anda dapat melakukan hal yang sama seperti ini (jangan lupa untuk menentukan UTC, jika tidak, itu memenangkan' t kerja):

date -d"1970-01-01 $curquarter seconds UTC"
jon_d
sumber
5

Metode berikut membuatnya tidak perlu menelepon datedua kali.
Overhead panggilan sistem dapat membuat perintah "sederhana" 100 kali lebih lambat daripada bash melakukan hal yang sama di lingkungan lokalnya sendiri.

UPDATE Hanya menyebutkan singkat tentang komentar saya di atas: "100 kali lebih lambat". Sekarang dapat membaca " 500 kali lebih lambat" ... Saya baru-baru ini jatuh (tidak, berjalan membabi buta) ke dalam masalah ini. di sini adalah tautannya: Cara cepat untuk membuat file uji

eval $(date +Y=%Y\;m=%m\;d=%d\;H=%H\;M=%M)
[[ "$M" < "15" ]] && M=00 # cater for octal clash
M=$(((M/15)*15))
((M==0)) && M=00 # the math returns 0, so make it 00  
echo $Y.$m.$d $H:$M  

atau

eval $(date +Y=%Y\;m=%m\;d=%d\;H=%H\;M=%M)
if   [[ "$M" < "15" ]] ; then M=00
elif [[ "$M" < "30" ]] ; then M=15
elif [[ "$M" < "45" ]] ; then M=30
else M=45
fi
echo $Y.$m.$d $H:$M

Kedua versi hanya akan kembali

2011.02.23 01:00
2011.02.23 01:15
2011.02.23 01:30
2011.02.23 01:45   

Ini yang pertama dengan loop TEST untuk semua 60 nilai {00..59}

for X in {00..59} ;                         ###### TEST
do                                          ###### TEST 
  eval $(date +Y=%Y\;m=%m\;d=%d\;H=%H\;M=%M)
  M=$X                                      ###### TEST 
  [[ "$M" < "15" ]] && M=00 # cater for octal clash
  M=$(((M/15)*15))
  ((M==0)) && M=00 # the math returns 0, so make it 00  
  echo $Y.$m.$d $H:$M 
done                                        ###### TEST 
Peter.O
sumber
1
Hanya untuk klarifikasi - dengan "system call", maksud Anda "fork / exec / wait, seperti system () call", bukan system call secara umum. (Saya menyebutkan ini karena membuat panggilan sistem juga memiliki overhead dalam suatu program, karena saklar pengguna / kernel. Itu bukan masalah khusus di sini.)
mattdm
mattdm ... Terima kasih .. Saya bekerja hanya dari 6 bulan pengalaman Linux, jadi saya sangat mungkin menggunakan frasa yang salah, tapi saya terus membaca tentang biaya overhead yang dikeluarkan oleh panggilan yang tidak perlu, dan dalam pengalaman saya sendiri menguji sendiri skrip, saya telah melihat banyak contoh di mana memanggil printfatau seddan juga bahwa "tidak perlu" catvs <file membuat perbedaan run-time aktual yang dramatis. ketika perulangan, seperti dalam contoh "500 kali lebih lambat" saya .. Jadi sepertinya menggunakan shell sedapat mungkin, dan memungkinkan program seperti dateuntuk proses batch adalah apa yang saya maksud .. misalnya. Contoh Gilles 'Left-Pad-0, vs printf
Peter.O
3

Inilah cara untuk bekerja pada tanggal di shell. Panggilan pertama dateuntuk mendapatkan komponen, dan mengisi parameter posisi ( $1,$2 dll) dengan komponen (perhatikan bahwa ini adalah salah satu kasus langka di mana Anda ingin menggunakan di $(…)luar tanda kutip ganda, untuk memecah string menjadi kata-kata). Kemudian lakukan aritmatika, tes, atau apa pun yang perlu Anda lakukan pada komponen. Akhirnya merakit komponen.

Bagian aritmatika bisa sedikit rumit karena cangkang diperlakukan 0sebagai awalan oktal; misalnya di sini $(($5/15))akan gagal pada 8 atau 9 menit melewati jam. Karena paling banyak ada satu yang memimpin 0, ${5#0}aman untuk berhitung. Menambahkan 100 dan kemudian melepaskannya 1adalah cara untuk mendapatkan jumlah digit yang tetap dalam output.

set $(date "+%Y %m %d %H %M")
m=$((100+15*(${5#0}/15)))
last_quarter_hour="$1.$2.$3 $4:${m#1}"
Gilles 'SO- berhenti menjadi jahat'
sumber
"Trik perdagangan" ... bagus. :)
Peter.O
2

Mungkin tidak masalah lagi tetapi Anda bisa mencoba dateutils saya sendiri . Pembulatan (turun) ke menit dilakukan dengan drounddan argumen negatif:

dround now /-15m
=>
  2012-07-11T13:00:00

Atau untuk mematuhi format Anda:

dround now /-15m -f '%Y.%m.%d %H:%M'
=>
  2012.07.11 13:00
hroptatyr
sumber
Apakah itu yang sebenarnya bagaimana utilitas Anda bekerja lagi? menggunakan -15m saya mendapatkan memutar ulang masukan ke terdekat 15 menit melewati jam: dateutils.dround '2018-11-12 13:55' -15mmenghasilkan 2018-11-12T13:15:00tidak 2018-11-12T13:45:00.
1
@JackDouglas Alat-alat telah berevolusi, yang Anda inginkan sekarang adalah:, /-15myaitu dibulatkan ke kelipatan 15 menit berikutnya dalam satu jam. Fitur ini mendapat sintaks yang lebih rumit karena menerima nilai yang lebih sedikit, / -13m tidak mungkin misalnya karena 13 bukan pembagi 60 (menit dalam satu jam)
hroptatyr
bagus, saya mendapatkan apa yang saya butuhkan sekarang dateutils.dround '2018-11-12 12:52:31' /450s /-15m, terima kasih!
2

Beberapa shell dapat melakukan pekerjaan tanpa memanggil dateperintah eksternal :

a=$(printf '%(%s)T\n'); printf '%(%Y.%m.%d %H:%M)T\n' "#$((a-a%(15*60)))"
a=$(printf '%(%s)T\n'); printf '%(%Y.%m.%d %H:%M)T\n' "$((a-a%(15*60)))"
zmodload zsh/datetime; a=$EPOCHSECONDS; strftime '%Y-%m-%d %H:%M' $((a-a%(15*60)))

Tiga di atas menyediakan waktu lokal (bukan UTC). Gunakan TZ terkemuka = ​​UTC0 jika perlu.

Sintaks ksh dan bash hampir identik (kecuali untuk yang diperlukan #dalam ksh). Zsh perlu memuat modul (termasuk dengan distribusi zsh).

Dimungkinkan juga untuk melakukannya dengan (GNU) awk:

awk 'BEGIN{t=systime();print strftime("%Y.%m.%d %H:%M",t-t%(15*60),1)}'

Ini memberikan hasil UTC (ubah yang terakhir 1ke 0) jika lokal diperlukan. Tetapi memuat awk eksternal atau modul zsh eksternal mungkin selambat tanggal panggilan itu sendiri:

a=$(date +%s); date -ud "@$((a-a%(15*60)))" +'%Y.%m.%d %H:%M'

Seperti dieksekusi kecil busybox dapat memberikan hasil yang serupa:

a=$(busybox date +%s);busybox date -ud "@$((a-a%(15*60)))" +'%Y.%m.%d %H:%M'

Perhatikan bahwa kata busybox terkemuka dapat dihilangkan jika busybox ditautkan ke nama-nama tersebut dalam direktori PATH.

Kedua datedan di busybox dateatas akan mencetak waktu UTC. Hapus -uopsi untuk waktu lokal.


Jika OS Anda memiliki versi tanggal yang lebih terbatas (dan itulah yang harus Anda gunakan) maka cobalah:

a=$(date +%s); a=$(( a-a%(15*60) ))
date -d"1970-01-01 $a seconds UTC" +'%Y.%m.%d %H:%M'

Atau, jika di FreeBSD, coba:

a=$(date +%s); a=$(( a-a%(15*60) ))
date -r "$a" +'%Y.%m.%d %H:%M'
Ishak
sumber
1

Jika Anda dapat hidup dengan tanggal panggilan dua kali, yang ini bekerja di bash pada Solaris:

date +"%Y.%m.%d %H:$(( $(date +'%M') / 15 * 15 ))"

Diedit atas nama komentar untuk:

date +"%Y.%m.%d %H:$(( $(date +'%M') / 15 * 15 ))" | sed 's/:0$/:00/'
ddeimeke
sumber
1
Di qurarter pertama jam ini, ini akan menghasilkan output menit dengan hanya 0 bukannya 00
Peter.O
Diperbaiki, ini adalah sed sederhana setelah perintah asli.
ddeimeke
Satu lagi bug: tidak berfungsi antara H: 08 dan H: 10. Lihat jawaban saya untuk alasan dan perbaikan.
Gilles 'SO- stop being evil'
-1

Tidak yakin dengan kebutuhan pasti Anda. Namun, jika Anda ingin menghasilkan waktu setelah 15 menit, maka Anda dapat menggunakan sesuatu seperti date -d '+15 min'. Output ditunjukkan di bawah ini:

$ date; date  -d '+15 min'
Tue Feb 22 18:12:39 IST 2011
Tue Feb 22 18:27:39 IST 2011
Barun
sumber
1
Anda salah paham pertanyaannya. Intinya adalah untuk membulatkan tanggal (turun) menjadi kelipatan 15 menit.
Gilles 'SO- stop being evil'