ngày: nhận khoảng thời gian 15 phút hiện tại


15

Có cách nào để tôi có thể có được khoảng thời gian 15 phút hiện tại bằng cách sử dụng lệnh date hoặc tương tự không?

ví dụ như một cái gì đó như ngày %Y.%m.%d %H:%M sẽ cho tôi 2011.02.22 10:19, tôi cần một cái gì đó mang lại 2011.02.22 10:15trong khoảng thời gian từ 10:15đến 10:29.

Câu trả lời:


17

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"

5

Các phương pháp sau đây khiến bạn không cần phải gọi datehai 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 

1
Chỉ cần làm rõ - bằng "cuộc gọi hệ thống", bạn có nghĩa là "fork / exec / Wait, giống như cuộc gọi system ()", không phải cuộc gọi hệ thống nói chung. (Tôi đề cập đến điều này bởi vì thực hiện các cuộc gọi hệ thống cũng có chi phí hoạt động trong một chương trình, vì chuyển đổi người dùng / kernel. Đó không phải là vấn đề cụ thể ở đây.)
mattdm

mờdm các tập lệnh, tôi đã thấy nhiều ví dụ trong đó việc gọi printfhoặc sedcattậ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ư datexử 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
Peter.O

3

Đâ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, $2v.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 0là 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ỏ 1là 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}"

"Thủ đoạn của thương mại" ... một cách tốt. :)
Peter.O

2

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 droundvà 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

đó thực sự là cách mà dụng cụ của bạn hoạt động nữa? sử dụng -15m Tôi nhận được đầu vào lại trong 15 phút gần nhất sau một giờ: không dateutils.dround '2018-11-12 13:55' -15mtạo ra . 2018-11-12T13:15:002018-11-12T13:45:00

1
@JackDoumund Các công cụ đã phát triển, những gì bạn muốn bây giờ là : /-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ờ)
hroptatyr

tốt, tôi nhận được những gì tôi cần bây giờ với dateutils.dround '2018-11-12 12:52:31' /450s /-15m, cảm ơn!

2

Một số shell có thể thực hiện công việc mà không cần gọi datelệnh bên ngoài :

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

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:

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 1thà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:

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

Một thực thi nhỏ như busyboxcó thể cung cấp kết quả tương tự:

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 datebusybox datetrên sẽ in lần UTC. Xóa -utù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'

1

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/'

1
Trong qurarter đầu tiên của giờ, điều này sẽ tạo ra một đầu ra phút chỉ với một 0 thay vì 00
Peter.O

Sửa chữa, nó là một sed đơn giản sau lệnh ban đầu.
ddeimeke

Thêm một lỗi nữa: nó không hoạt động giữa H: 08 và H: 10. Xem câu trả lời của tôi cho lý do tại sao và một sửa chữa.
Gilles 'SO- ngừng trở nên xấu xa'

-1

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

1
Bạn đã hiểu nhầm câu hỏi. Vấn đề là làm tròn ngày (xuống) thành bội số của 15 phút.
Gilles 'SO- ngừng trở nên xấu xa'
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.