Giây
Để đo thời gian trôi qua (tính bằng giây), chúng ta cần:
- một số nguyên biểu thị số giây đã trôi qua và
- một cách để chuyển đổi số nguyên như vậy sang một định dạng có thể sử dụng.
Một giá trị nguyên của giây trôi qua:
Chuyển đổi số nguyên như vậy sang định dạng có thể sử dụng
Bash nội bộ printf
có thể làm điều đó trực tiếp:
$ TZ=UTC0 printf '%(%H:%M:%S)T\n' 12345
03:25:45
tương tự
$ elapsedseconds=$((12*60+34))
$ TZ=UTC0 printf '%(%H:%M:%S)T\n' "$elapsedseconds"
00:12:34
nhưng điều này sẽ thất bại trong thời gian hơn 24 giờ, vì chúng tôi thực sự in thời gian trên đồng hồ, không thực sự là thời lượng:
$ hours=30;mins=12;secs=24
$ elapsedseconds=$(( ((($hours*60)+$mins)*60)+$secs ))
$ TZ=UTC0 printf '%(%H:%M:%S)T\n' "$elapsedseconds"
06:12:24
Dành cho những người yêu thích chi tiết, từ bash-hackers.org :
%(FORMAT)T
xuất chuỗi thời gian ngày kết quả từ việc sử dụng FORMAT làm chuỗi định dạng cho strftime(3)
. Đối số được liên kết là số giây kể từ Epoch hoặc -1 (thời gian hiện tại) hoặc -2 (thời gian khởi động hệ vỏ). Nếu không có đối số tương ứng được cung cấp, thời gian hiện tại được sử dụng làm mặc định.
Vì vậy, bạn có thể chỉ muốn gọi textifyDuration $elpasedseconds
nơi textifyDuration
thực hiện in thời lượng khác:
textifyDuration() {
local duration=$1
local shiff=$duration
local secs=$((shiff % 60)); shiff=$((shiff / 60));
local mins=$((shiff % 60)); shiff=$((shiff / 60));
local hours=$shiff
local splur; if [ $secs -eq 1 ]; then splur=''; else splur='s'; fi
local mplur; if [ $mins -eq 1 ]; then mplur=''; else mplur='s'; fi
local hplur; if [ $hours -eq 1 ]; then hplur=''; else hplur='s'; fi
if [[ $hours -gt 0 ]]; then
txt="$hours hour$hplur, $mins minute$mplur, $secs second$splur"
elif [[ $mins -gt 0 ]]; then
txt="$mins minute$mplur, $secs second$splur"
else
txt="$secs second$splur"
fi
echo "$txt (from $duration seconds)"
}
Ngày GNU.
Để có được thời gian hình thành, chúng ta nên sử dụng một công cụ bên ngoài (ngày GNU) theo nhiều cách để có thời lượng lên tới gần một năm và bao gồm cả Nanoseconds.
Toán bên trong ngày.
Không cần số học bên ngoài, hãy làm tất cả trong một bước bên trong date
:
date -u -d "0 $FinalDate seconds - $StartDate seconds" +"%H:%M:%S"
Vâng, có một 0
số không trong chuỗi lệnh. Nó là cần thiết.
Giả sử bạn có thể thay đổi date +"%T"
lệnh thành date +"%s"
lệnh để các giá trị sẽ được lưu trữ (in) sau vài giây.
Lưu ý rằng lệnh được giới hạn ở:
- Giá trị dương
$StartDate
và $FinalDate
giây.
- Giá trị trong
$FinalDate
lớn hơn (về sau) $StartDate
.
- Thời gian chênh lệch nhỏ hơn 24 giờ.
- Bạn chấp nhận một định dạng đầu ra với Giờ, Phút và Giây. Rất dễ thay đổi.
- Có thể chấp nhận sử dụng -u lần UTC. Để tránh "DST" và hiệu chỉnh thời gian cục bộ.
Nếu bạn phải sử dụng 10:33:56
chuỗi, chỉ cần chuyển đổi nó thành giây,
đồng thời, từ giây có thể được viết tắt là giây:
string1="10:33:56"
string2="10:36:10"
StartDate=$(date -u -d "$string1" +"%s")
FinalDate=$(date -u -d "$string2" +"%s")
date -u -d "0 $FinalDate sec - $StartDate sec" +"%H:%M:%S"
Lưu ý rằng chuyển đổi thời gian giây (như được trình bày ở trên) có liên quan đến ngày bắt đầu của "ngày này" (Hôm nay).
Khái niệm này có thể được mở rộng đến nano giây, như thế này:
string1="10:33:56.5400022"
string2="10:36:10.8800056"
StartDate=$(date -u -d "$string1" +"%s.%N")
FinalDate=$(date -u -d "$string2" +"%s.%N")
date -u -d "0 $FinalDate sec - $StartDate sec" +"%H:%M:%S.%N"
Nếu được yêu cầu tính chênh lệch thời gian dài hơn (tối đa 364 ngày), chúng ta phải sử dụng bắt đầu (một số) năm làm tham chiếu và giá trị định dạng %j
(số ngày trong năm):
Tương tự như:
string1="+10 days 10:33:56.5400022"
string2="+35 days 10:36:10.8800056"
StartDate=$(date -u -d "2000/1/1 $string1" +"%s.%N")
FinalDate=$(date -u -d "2000/1/1 $string2" +"%s.%N")
date -u -d "2000/1/1 $FinalDate sec - $StartDate sec" +"%j days %H:%M:%S.%N"
Output:
026 days 00:02:14.340003400
Đáng buồn thay, trong trường hợp này, chúng ta cần trừ 1
MỘT cách thủ công khỏi số ngày. Lệnh date xem ngày đầu tiên của năm là 1. Không khó lắm ...
a=( $(date -u -d "2000/1/1 $FinalDate sec - $StartDate sec" +"%j days %H:%M:%S.%N") )
a[0]=$((10#${a[0]}-1)); echo "${a[@]}"
Việc sử dụng số giây dài là hợp lệ và được ghi lại ở đây:
https://www.gnu.org/software/coreutils/manual/html_node/Examples-of-date.html#Examples-of-date
Ngày bận rộn
Một công cụ được sử dụng trong các thiết bị nhỏ hơn (một tệp thực thi rất nhỏ để cài đặt): Busybox.
Tạo liên kết đến busybox được gọi là ngày:
$ ln -s /bin/busybox date
Sử dụng nó sau đó bằng cách gọi nó date
(đặt nó trong một thư mục bao gồm PATH).
Hoặc tạo một bí danh như:
$ alias date='busybox date'
Ngày Busybox có một tùy chọn đẹp: -D để nhận định dạng của thời gian nhập. Điều đó mở ra rất nhiều định dạng được sử dụng như thời gian. Sử dụng tùy chọn -D, chúng ta có thể chuyển đổi trực tiếp thời gian 10:33:56:
date -D "%H:%M:%S" -d "10:33:56" +"%Y.%m.%d-%H:%M:%S"
Và như bạn có thể thấy từ đầu ra của Lệnh ở trên, ngày được coi là "hôm nay". Để có được thời gian bắt đầu trên epoch:
$ string1="10:33:56"
$ date -u -D "%Y.%m.%d-%H:%M:%S" -d "1970.01.01-$string1" +"%Y.%m.%d-%H:%M:%S"
1970.01.01-10:33:56
Ngày Busybox thậm chí có thể nhận được thời gian (ở định dạng trên) mà không có -D:
$ date -u -d "1970.01.01-$string1" +"%Y.%m.%d-%H:%M:%S"
1970.01.01-10:33:56
Và định dạng đầu ra thậm chí có thể là vài giây kể từ epoch.
$ date -u -d "1970.01.01-$string1" +"%s"
52436
Đối với cả hai lần và một chút bash math (busybox chưa thể làm toán):
string1="10:33:56"
string2="10:36:10"
t1=$(date -u -d "1970.01.01-$string1" +"%s")
t2=$(date -u -d "1970.01.01-$string2" +"%s")
echo $(( t2 - t1 ))
Hoặc được định dạng:
$ date -u -D "%s" -d "$(( t2 - t1 ))" +"%H:%M:%S"
00:02:14
time
lệnh?