秒を日/時/分/秒に変換する方法

秒を日/時/分/秒に変換する方法

21410.912099この時間形式を次に変換しようとしています。12d 1h 14m 17.912 s

このようなスクリプトを試しましたが、うまくいきません(ドットを解析できません):(

converts() {
t=$1
d=$((t/60/60/24))
h=$((t/60/60%24))
m=$((t/60%60))
s=$((t%60))

if [ $d -gt 0 ]; then
        [ $d = 1 ] && printf "%d day " $d || printf "%d days " $d
fi
if [ $h -gt 0 ]; then
        [ $h = 1 ] && printf "%d hour " $h || printf "%d hours " $h
fi
if [ $m -gt 0 ]; then
        [ $m = 1 ] && printf "%d minute " $m || printf "%d minutes " $m
fi
if [ $d = 0 ] && [ $h = 0 ] && [ $m = 0 ]; then
        [ $s = 1 ] && printf "%d second" $s || printf "%d seconds" $s
fi
printf '\n' 
}

答え1

区切り文字を使用して値を配列に分割します.

Bashの組み込み機能を使用して、printfエポック後の秒を間隔で再フォーマットします。

$ Input=1721410.912099
$ IFS='.' s_ms=( ${Input} )
$ declare -p s_ms
declare -a s_ms=([0]="1721410" [1]="912099")
$ printf -v Out '%(%-dd %-Hh %-Mm %-S)T.%s s' "${s_ms[0]}" "${s_ms[1]:0:3}"
$ declare -p Out
declare -- Out="20d 23h 10m 10.912 s"

編集:申し訳ありません。これは少なくとも3つの点で問題があります。でテストしてみました3707.001234

(1) 基準は 1970-01- であるため、日付に 1 回限りのエラーがあります。01

(2)すぐに見えない時間に1回限りのエラーがあります(GMT基準ですが、時間帯が有力な容疑者です)。date -d @0レポートトヨThu 1 Jan 01:00:00 BST 1970。 1月のBST? ? ?

(3)上記の間隔は、26784001ヶ月全体を削除します。

難しいのは、これらの日付です。とても申し訳ありません。ただし、1秒の数分の1秒を処理する方法は正確です。解析して部分文字列を指定することです。

Googleの付録:BSTとイギリスの実験

英国サマータイム(BST)は、1968年2月から1971年10月まで、年間を通して適用されます。

答え2

時間の小数部の場合、値は拡張を使用して分割できます${var##prefix}${var%%suffix}値から最も長い一致プレフィックスとサフィックスを削除します$var

だから、2行のコメントが追加されました。

converts() {
    t=$1
    case $t in
        *.*) tfrac=${t##*.}       # fractional seconds
             t=${t%%.*}           # full seconds
             ;;
          *) tfrac=0              # no decimal point
             ;;
    esac

    d=$((t/60/60/24))
    h=$((t/60/60%24))
    m=$((t/60%60))
    s=$((t%60))
    
    if [ $d -gt 0 ]; then
            [ $d = 1 ] && printf "%d day " $d || printf "%d days " $d
    fi
    if [ $h -gt 0 ]; then
            [ $h = 1 ] && printf "%d hour " $h || printf "%d hours " $h
    fi
    if [ $m -gt 0 ]; then
            [ $m = 1 ] && printf "%d minute " $m || printf "%d minutes " $m
    fi
    if [ $d = 0 ] && [ $h = 0 ] && [ $m = 0 ]; then
            [ $s = 1 ] && printf "%d second" $s || printf "%d seconds" $s
    fi
    printf '\n' 
}

私たちは、例えば

$ converts $(( 1*86400 + 23*3600 + 45*60 + 6))
1 day 23 hours 45 minutes 

入力の一部を削除する前に、入力に小数点があることを確認する必要があります。小数点がないと、ただ${t##*.}返されるからです$t

どこに使用したいのかを決めるようにしますtfrac。たぶん良い

printf "%d.%s seconds" $s $tfrac

(使用しないでください%d.%d。先行ゼロが削除されます。123.05たとえば123.5


または、次の12d 1h 14m 17.912s形式で使用してください。

converts() {
    t=$1
    case $t in
        *.*) tfrac=${t##*.}       # fractional seconds
             t=${t%%.*}           # full seconds
             ;;
          *) tfrac=0              # no decimal point
             ;;
    esac
    d=$((t/60/60/24))
    h=$((t/60/60%24))
    m=$((t/60%60))
    s=$((t%60))

    printf "%dd %dh %dm %d.%ss\n" "$d" "$h" "$m" "$s" "$tfrac"
}

そして

$ converts  $(( 1*86400 + 23*3600 + 45*60 + 6)).987
1d 23h 45m 6.987s

関連情報