Câu trả lời:
Bạn có thể lấy dấu thời gian unix hiện tại với date "+%s"
, tìm một phần tư giờ hiện tại với một số phép toán đơn giản (ví dụ của tôi là bash
) và in lại với định dạng tốt hơn với date
:
curdate=`date "+%s"`
curquarter=$(($curdate - ($curdate % (15 * 60))))
date -d"@$curquarter"
Các @
cú pháp để thiết lập ngày hiện tại và thời gian từ một timestamp là một extention GNU đến nay, nếu nó không hoạt động trên hệ điều hành của bạn, bạn có thể làm điều tương tự như thế này (đừng quên để xác định tính theo giờ UTC, nếu không, nó đã giành' t làm việc):
date -d"1970-01-01 $curquarter seconds UTC"
Các phương pháp sau đây khiến bạn không cần phải gọi date
hai lần.
Chi phí của một cuộc gọi hệ thống có thể khiến lệnh "đơn giản" chậm hơn 100 lần so với bash làm điều tương tự trong môi trường cục bộ của chính nó.
CẬP NHẬT Chỉ cần một đề cập nhanh về nhận xét trên của tôi: "chậm hơn 100 lần". Bây giờ nó có thể đọc " chậm hơn 500 lần" ... Gần đây tôi đã rơi (không, đi một cách mù quáng) vào chính vấn đề này. Đây là liên kết: Cách nhanh chóng để xây dựng một tệp thử nghiệm
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
hoặc là
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
Cả hai phiên bản sẽ chỉ trở lại
2011.02.23 01:00
2011.02.23 01:15
2011.02.23 01:30
2011.02.23 01:45
Đây là cái đầu tiên có vòng TEST cho tất cả 60 giá trị {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
printf
hoặc sed
và cat
tập tin "không cần thiết" so với <không tạo ra sự khác biệt lớn về thời gian thực tế. khi lặp, như trong ví dụ "chậm hơn 500 lần" của tôi .. Vì vậy, dường như việc sử dụng shell bất cứ khi nào có thể, và cho phép một chương trình như date
xử lý hàng loạt là điều tôi muốn nói .. vd. Ví dụ Left-Pad-0 của Gilles, so với printf
Đây là một cách để làm việc vào ngày trong vỏ. Cuộc gọi đầu tiên date
để nhận các thành phần và điền các tham số vị trí ( $1
, $2
v.v.) bằng các thành phần (lưu ý rằng đây là một trong những trường hợp hiếm hoi mà bạn muốn sử dụng $(…)
bên ngoài dấu ngoặc kép, để ngắt chuỗi thành từ). Sau đó thực hiện arithologists, kiểm tra, hoặc bất cứ điều gì bạn cần làm trên các thành phần. Cuối cùng lắp ráp các thành phần.
Phần số học có thể hơi khó khăn vì shell được coi 0
là tiền tố bát phân; ví dụ ở đây $(($5/15))
sẽ thất bại lúc 8 hoặc 9 phút trước giờ. Vì có nhiều nhất một hàng đầu 0
, ${5#0}
an toàn cho số học. Thêm 100 và sau đó tước bỏ 1
là một cách để có được một số chữ số cố định trong đầu ra.
set $(date "+%Y %m %d %H %M")
m=$((100+15*(${5#0}/15)))
last_quarter_hour="$1.$2.$3 $4:${m#1}"
Có lẽ nó không còn quan trọng nữa nhưng bạn có thể dùng thử ngày của riêng tôi . Làm tròn (xuống) đến phút được thực hiện với dround
và một đối số phủ định:
dround now /-15m
=>
2012-07-11T13:00:00
Hoặc để tuân thủ định dạng của bạn:
dround now /-15m -f '%Y.%m.%d %H:%M'
=>
2012.07.11 13:00
dateutils.dround '2018-11-12 13:55' -15m
tạo ra . 2018-11-12T13:15:00
2018-11-12T13:45:00
/-15m
, tức là làm tròn xuống bội số tiếp theo của 15 phút trong giờ. Tính năng này có cú pháp rườm rà hơn vì nó chấp nhận ít giá trị hơn, ví dụ / -13m không thể thực hiện được vì 13 không phải là ước số của 60 (phút trong giờ)
Một số shell có thể thực hiện công việc mà không cần gọi date
lệnh bên ngoài :
ksh
a=$(printf '%(%s)T\n'); printf '%(%Y.%m.%d %H:%M)T\n' "#$((a-a%(15*60)))"
bash a=$(printf '%(%s)T\n'); printf '%(%Y.%m.%d %H:%M)T\n' "$((a-a%(15*60)))"
zsh zmodload zsh/datetime; a=$EPOCHSECONDS; strftime '%Y-%m-%d %H:%M' $((a-a%(15*60)))
Ba ở trên cung cấp thời gian địa phương (không phải UTC). Sử dụng TZ = UTC0 hàng đầu nếu cần.
Cú pháp ksh và bash gần như giống hệt nhau (ngoại trừ yêu cầu #
trong ksh). Zsh yêu cầu tải một mô-đun (kèm theo phân phối zsh).
Cũng có thể làm điều đó với (GNU) awk:
chim ưng awk 'BEGIN{t=systime();print strftime("%Y.%m.%d %H:%M",t-t%(15*60),1)}'
Điều này cung cấp kết quả UTC (thay đổi lần cuối 1
thành 0
) nếu cần cục bộ. Nhưng việc tải một awk bên ngoài hoặc một mô-đun zsh bên ngoài có thể chậm như chính ngày gọi:
ngày tháng a=$(date +%s); date -ud "@$((a-a%(15*60)))" +'%Y.%m.%d %H:%M'
Một thực thi nhỏ như busybox
có thể cung cấp kết quả tương tự:
ngày bận rộn a=$(busybox date +%s);busybox date -ud "@$((a-a%(15*60)))" +'%Y.%m.%d %H:%M'
Lưu ý rằng từ busybox hàng đầu có thể bị bỏ qua nếu busybox được liên kết với các tên đó trong một thư mục của PATH.
Cả hai date
và busybox date
trên sẽ in lần UTC. Xóa -u
tùy chọn cho giờ địa phương.
Nếu hệ điều hành của bạn có phiên bản giới hạn hơn (và đó là những gì bạn phải sử dụng) thì hãy thử:
a=$(date +%s); a=$(( a-a%(15*60) ))
date -d"1970-01-01 $a seconds UTC" +'%Y.%m.%d %H:%M'
Hoặc, nếu trong FreeBSD, hãy thử:
a=$(date +%s); a=$(( a-a%(15*60) ))
date -r "$a" +'%Y.%m.%d %H:%M'
Nếu bạn có thể sống với cuộc gọi hai lần, thì cuộc gọi này sẽ hoạt động trong bash trên Solaris:
date +"%Y.%m.%d %H:$(( $(date +'%M') / 15 * 15 ))"
Chỉnh sửa thay mặt cho nhận xét để:
date +"%Y.%m.%d %H:$(( $(date +'%M') / 15 * 15 ))" | sed 's/:0$/:00/'
Tôi không chắc chắn về yêu cầu chính xác của bạn. Tuy nhiên, nếu bạn muốn tạo thời gian sau 15 phút, thì bạn có thể sử dụng một cái gì đó như date -d '+15 min'
. Đầu ra được hiển thị dưới đây:
$ date; date -d '+15 min'
Tue Feb 22 18:12:39 IST 2011
Tue Feb 22 18:27:39 IST 2011