如何使用 GNU 工具計算和格式化日期持續時間,而不是結果日期?
到目前為止,我發現的所有大量文章似乎都集中在獲得結果日期上,這仍然有用,但在這種情況下不是我想要的。
範例連結:Unix & Linux SE - 快速計算日期差異。
在
datediff
其他問答中,這更多是我想要指的日期/時間持續時間結果,它基本上使用 Unix 時間戳數學和前面的轉換,但我希望我的粒度下降到秒,這就是我不這樣做的原因t 除以 86400。有了可用的秒數,我現在想將其格式化為類似使用 GNU
date
命令的方式:date -d "@69600" "+ %Y years %m months %e days %H:%M:%S"
我意識到一切本質上都是 Unix 紀元的日期/時間持續時間,但現在我遇到了日期、月份和年份數字不是從 0 開始的問題,這不能正確表示我想要的持續時間值。
我可以削減這種格式並應用更多
expr
命令從每個值中減去 1 或 1970,但我想知道除了連結數學之外是否還有其他更簡單的方法來處理日期/時間計算以實現持續時間結果和格式化步驟一起。也許在 GNUdate
中有一些其他選項可以利用,或者其他工具可以接受 2 個日期/時間參數並立即給我我正在尋找的結果。讓它在 Mac 的 Homebrew 中可用將是一個加號:)。
簡單的日期數學連結:Walker News - Linux Shell 腳本中的日期算術
隨機日期格式連結:
使用dateutils(
datediff
對不起,不是 GNU),(以前ddiff
,dateutils.ddiff
在 Debian 上):$ dateutils.ddiff -f '%Y years, %m months, %d days, %H:%0M:%0S' \ '2012-01-23 15:23:01' '2017-06-01 09:24:00' 5 years, 4 months, 8 days, 18:00:59
(日期以 UTC 為單位,添加類似
--from-zone=Europe/London
在相應時區作為本地時間的日期。--from-zone=localtime
可能適用於系統中的預設時區;--from-zone="${TZ#:}"
只要$TZ
指定 IANA 時區文件的路徑(如TZ=:Europe/London
,不是TZ=GMT0BST,M3.5.0/1:00:00,M10.5.0/2:00:00
POSIX 風格的 TZ 規範))。使用ast-open
date
,所以仍然不能使用 GNU 工具抱歉(如果ksh93
用作您的 shell,date
雖然它可能作為內置工具提供),您可以使用date -E
以提供 2 個帶單位的數字的格式來獲取兩個日期之間的差異:$ date -E 1970-01-01 2017-06-01 47Y04M $ date -E 2017-01-01 2017-06-01 4M29d $ date -E 12:12:01 23:01:43 10h49m
請注意,小時以上的任何內容都是模棱兩可的,因為在 DST(23、24 或 25)的區域設置中,天數的小時數不同,而月份和年份的天數也不同,因此具有更高的精度可能沒有多大意義上面那兩個單位。
例如,在 2015-01-01 00:00:00 和 2016-01-01 00:00:00 或 2016-01-01 00:00:00 和 2017-01-01 00 之間恰好有一年: 00:00,但持續時間不同(一種情況下為 36524 小時,另一種情況下為 36624 小時)
2017-03-24 12:00:00 和 2017-03-25 12:00:00 或 2017-03-25 12:00:00 和 2017-03-26 12:00:00 之間正好有一天,但是當這些是歐洲國家的當地時間時(在 2017-03-26 切換到夏令時),一天是 24 小時,另一種是 23 小時。
換句話說,提及年、月、週或日的持續時間僅在與它要應用於的邊界之一(和時區)相關聯時才有意義。因此,您不能在不知道要應用於什麼時間(從或直到)的情況下將秒數轉換為這樣的持續時間(除非您想使用日(24 小時)、月(3024 小時)或年(36524 小時))。
在某種程度上,即使以秒為單位的持續時間也是模棱兩可的。為簡化起見,Unix 紀元時間中的秒數定義為給定地球日1的第 86400 部分。隨著地球自轉,這些秒數越來越長。
所以像(使用 GNU
date
):d1='2016-01-01 00:00:00' d2='2017-01-01 00:00:00' eval "$(date -d "@$(($(date -d "$d2" +%s) - $(date -d "$d1" +%s)))" +' delta="$((%-Y - 1970)) years, $((%-m - 1)) months, $((%-d - 1)) days, %T"')" echo "$delta"
或在
fish
:date -d@(expr (date -d $d2 +%s) - (date -d $d1 +%s)) +'%Y %-m %-d %T' | \ awk '{printf "%s years, %s months, %s days, %s\n", $1-1970, $2-1, $3-1, $4, $5}'
由於時間增量適用於 1970 年而不是 2016 年的實際開始日期,因此通常不會為您提供正確的資訊。
例如,上面,這給了我(在歐洲/倫敦時區):
1 years, 0 months, 1 days, 01:00:00
代替
1 years, 0 months, 0 days, 00:00:00
(這對你來說可能仍然是一個足夠好的近似值)。
1從技術上講,雖然一天有 86400 Unix 秒長,但聯網系統通常使用 SI 秒將其時鐘與原子鐘同步。當原子鐘說 12:00:00.00 時,那些 Unix 系統也會說 12:00:00.00。只有在引入閏秒時才有例外,其中有一個 Unix 秒持續 2 秒,或者有幾秒持續更長的時間,以在更長的時間段內塗抹額外的一秒。
因此,可以知道兩個 Unix 時間戳(由與原子鐘同步的系統發出)之間的確切持續時間(以原子秒為單位):獲取兩個時間戳之間的 Unix 紀元時間差並添加跳躍數之間添加的秒數。
datediff
還-f %rS
可以獲取兩個日期之間的實際秒數:$ dateutils.protected -f% S '1990-01-01 00:00:00' '2010-01-01 00:00:00' 631152000 $ dateutils.protected -f% rS '1990-01-01 00:00:00' '2010-01-01 00:00:00' 631152009
不同之處在於 1990 年至 2010 年間添加的 9 個閏秒。
現在,實際秒數並不能幫助您計算天數,因為天數沒有恆定的實際秒數。這兩個日期和這 9 個閏秒之間正好有 20 年的時間,而不是阻礙達到那個值。另請注意,
ddiff
’%rS
僅在不與其他格式說明符組合時才有效。此外,未來的閏秒不會提前很長時間知道,而且關於最近的閏秒的資訊也可能不可用。例如,我的系統不知道 2012-07-01 之後的那些。