日時
前回に引き続きシェルスクリプトのちょっとした関数で、日時の続きです。
日時をUNIX時間に変換する
UNIX 時間は、UTC の 1970年1月1日からの経過秒数(エポック秒)です。整数値なので経過時間の計算や比較がしやすくなります。
# $1 日時を表す文字列
function datetime_to_epoch() {
date -d "${1}" +'%s'
}
現在の日時をUNIX時間で出力する
「date +'%s'
」に名前を付けてスクリプトの可読性を良くするための関数です。
function epoch_now() {
date +'%s'
}
使用例(タイムアウトの処理)
ループ 1回ごとに現在時刻と制限時刻を比較して継続/終了の判定をする例です。UNIX 時間なので加算と比較が簡単にできます。
TIMEOUT_SECONDS=10 # タイムアウトの秒数
# 現在時刻にタイムアウトの秒数を加算して制限時刻を得る。
limit_time=$(( $(epoch_now) + ${TIMEOUT_SECONDS} ))
# 制限時刻まで処理を続ける。
while (( $(epoch_now) <= ${limit_time} ))
do
do_something
sleep 1
done
UNIX時間を日時に変換
逆変換の@
も忘れがちで、可読性も低いので関数にします。
# $1 日時を表す文字列
# $2 書式指定文字列(省略可 省略時は'yyyy-MM-dd hh:mm:ss'で出力する)
function epoch_to_datetime() {
date -d "@${1}" +"${2:-%F %T}"
}
日時の差分計算
前回の「日時の加算/減算」に対して、今回は 2つの日時の差分を求める関数です。端数は切り捨てられます。
# $1 出力する差分の単位 {day|hour|minute|second}
# $2 日時を表す文字列
# $3 日時を表す文字列 $2 < $3で正の値、$2 > $3で負の値を出力する
function diff_datetime() {
# UNIX時間に変換して、2つの日時の差分を秒単位で求める。
local formula=$(( $(datetime_to_epoch "${3}") - $(datetime_to_epoch "${2}") ))
case "${1}" in
second ) ;;
minute ) formula+=" / 60" ;;
hour ) formula+=" / 3600" ;;
day ) formula+=" / ( 3600 * 24 )" ;;
* ) return 1 ;;
esac
echo "${formula}" | bc
}
月初の日付
可読性のために、前回の「日時の書式設定」を使用します。
まず書式'%Y-%m-01'
を使って強制的に 1日の 0時にしてから、指定の書式があればフォーマットして出力します。
# $1 日時を表す文字列
# $2 書式指定文字列(省略可 省略時は'yyyy-MM-dd'で出力する)
function first_day_of_month() {
local first_day=$(format_datetime "${1}" '%Y-%m-01')
format_datetime "${first_day}" "${2:-%F}"
}
月末の日付
前回の「日時の加算/減算」を使用します。
月末は日が 28 〜 31 の間で変動するので、月初のように日の強制変換ができません。そのためまず翌月の月初を取得してから、その前日を求めて当月の月末にします。
# $1 日時を表す文字列
# $2 書式指定文字列(省略可 省略時は'yyyy-MM-dd'で出力する)
function last_day_of_month() {
# 月初の1か月後 = 翌月の月初
local next_1st_day=$(add_datetime "$(first_day_of_month "${1}")" 1 month)
# 翌月の月初の前日 = 当月の月末
add_datetime "${next_1st_day}" -1 day "${2:-%F}"
}