22 23 00 01のように24時間周期で並べ替える方法

22 23 00 01のように24時間周期で並べ替える方法

指定された時間(8時間など)のみを出力し、UTCタイムゾーンの変更に応じて時間を移動する必要があります。

私が見たい結果は次のとおりです。

Athens     15 16 17 18 19 20 21 22 (+2)
Hong_Kong  21 22 23 00 01 02 03 04 (+8)

date私は命令で遊んで発見しました。SuperUserのこの興味深いコード。私には学ぶことがたくさんあります。私はそれを自分のニーズに合わせて調整しました。しかし、タイムゾーンの変更で論理的な問題を発見しました。ループが24時間の範囲を超えて継続時間を増やすことです。したがって、上記の例ではなく、次のように印刷されます。

Athens     15 16 17 18 19 20 21 22 (+2)
Hong_Kong  21 22 23 24 25 26 27 28 (+8)

これは明らかに間違っています。

コードはソートでネストされたループを使用します。生涯にわたって時間範囲を24桁に制限する方法はわかりません。

これは、作者のコードで何が起こっているのかについてのおおよそのアイデアです。 24時間以上屋根を防ぎ、23時から00時まで屋根をする方法は?

#!/bin/bash
timezones="2" #In the actual script this is a variable generated by a provided array of cities.
workday="08 20" #This specifies the displayed range of hours e.g working hours

for tz in `seq $timezones`
do
    printf "City-$tz  " # Just a placeholder, instead of an actual city from timezone file
    timediff[$tz]=6.    # This is a simplified command. IN the actual script time difference calculated from deducting my local time from enquiring city time zone

    for h in `seq $workday` #loop hours
        do
            printf "%02d " $(($h++${timediff[$tz]}))
        done
        printf " \n" 
done

出力

%
City-1  14 15 16 17 18 19 20 21 22 23 24 25 26  
City-2  14 15 16 17 18 19 20 21 22 23 24 25 26 

PS上記の例では、タイムラインのタイムゾーンの変更は表示されません。私はそれを実行する方法を知りません。

答え1

timediff[$tz]=6.整数演算のみをサポートするBashでは、ドット入力が機能しないため、スクリプトは実行されません。

とにかく、数列を22、23、0、1、...にするには、概念はモジュラー算術であり、C系列言語の演算子は%。例えば

for i in 1 2 3 4 5; do
    echo $(( i % 3 ))
done

印刷1 2 0 1 2% 24もちろん、使う時間と同じです。もちろん、ユーザーは表示された時間がどの日かを知る必要があります。たとえば、UTC+0200からUTC+1200に変換されます。

mytz=2 othertz=12
for h in {8..16}; do
    printf "%02d ($mytz) == %02d ($othertz)\n" "$h" "$(( (h - mytz + othertz) % 24))";
done

08 (+2) == 18 (+12)などを与える

タイムゾーンの正しいファイル名がわかっている場合は、date翻訳に環境変数を使用することもできます。TZGNUの日付はここで使用されます:

hour=08
tz=Asia/Hong_Kong
printf "local: %s\nother: %s\n" "$(date +"%F %T %Z (%z)" -d "@$ts")" "$(TZ=$tz date +"%F %T %Z (%z)" -d "@$ts")"

出力:

local: 2021-12-08 08:00:00 EET (+0200)
other: 2021-12-08 14:00:00 HKT (+0800)

答え2

実際のタイムゾーンのリストを取得できる場合は、次のことができます(GNU仮定date)。

#!/bin/bash

timezones=("Europe/Athens" "Asia/Hong_Kong");

workday="08 20" #This specifies the displayed range of hours e.g working hours

printf '%-30s' "Here"
for myHour in $(seq $workday); do
  printf '%02d ' "$myHour"
done
printf '\n'

for tz in "${timezones[@]}"; do
  printf '%-30s' "$tz"
  for myHour in $(seq $workday); do
    theirHour=$(TZ="$tz" date -d "@$(date -d "$myHour" +%s)" +%H);
    printf '%02d ' "$theirHour"
  done
  printf '\n'  
done

次を生成します。

$ foo.sh
Here                          08 09 10 11 12 13 14 15 16 17 18 19 20 
Europe/Athens                 10 11 12 13 14 15 16 17 18 19 20 21 22 
Asia/Hong_Kong                16 17 18 19 20 21 22 23 00 01 02 03 04 

タイムゾーンを取得できず、自分のタイムゾーンに基づいてオフセットを使用する必要があり、質問に正確な出力を表示するには、次のことを試してください。

#!/bin/bash

offsets=("2" "8");
workday="08 20" #This specifies the displayed range of hours e.g working hours

for offset in "${offsets[@]}"; do
  for myHour in $(seq $workday); do
    theirHour=$(date -d "@$(date -d "$myHour + $offset hours" +%s)" +%H)
    printf '%s ' "$theirHour"  
  done
  printf '(+%s)\n' "$offset"
done

次を生成します。

$ foo.sh
10 11 12 13 14 15 16 17 18 19 20 21 22 (+2)
16 17 18 19 20 21 22 23 00 01 02 03 04 (+8)

答え3

すでに良い答えがありますが、コードを少し変更して、24時間で時間を再び00にリセットする必要があると思いました。結果をモジュロ24にインポートします。

printf "%02d " $((($h++${timediff[$tz]})%24))

また、構文エラーを修正して変更してください。

timediff[$tz]=6.

到着

timediff[$tz]=6

Bashは浮動小数点演算を理解していないので、6.有効な数値ではありません。

答え4

次のbashスクリプトは、コマンドラインから複数のタイムゾーンを取得し、現在の時刻から8時間後にそのタイムゾーンの時刻を印刷します。

スクリプトがオプションの-tオプション引数としてUnixタイムスタンプを指定した場合は、現在の時間ではなくその時間をオフセットに使用します。

スクリプトはローカルタイムゾーンを探し、最初の行に出力します。

スクリプトを実行します。

$ ./script UTC Europe/Zurich Asia/Kabul Africa/Harare
CET            20:39  21:39  22:39  23:39  00:39  01:39  02:39  03:39  (+0100)
UTC            19:39  20:39  21:39  22:39  23:39  00:39  01:39  02:39  (+0000)
Europe/Zurich  20:39  21:39  22:39  23:39  00:39  01:39  02:39  03:39  (+0100)
Asia/Kabul     00:09  01:09  02:09  03:09  04:09  05:09  06:09  07:09  (+0430)
Africa/Harare  21:39  22:39  23:39  00:39  01:39  02:39  03:39  04:39  (+0200)

GNUを使用してdate現地時間(今日)08:00のタイムスタンプを取得します。

$ ./script -t "$(date -d '08:00' +%s)"  UTC Europe/Zurich Asia/Kabul Africa/Harare
CET            08:00  09:00  10:00  11:00  12:00  13:00  14:00  15:00  (+0100)
UTC            07:00  08:00  09:00  10:00  11:00  12:00  13:00  14:00  (+0000)
Europe/Zurich  08:00  09:00  10:00  11:00  12:00  13:00  14:00  15:00  (+0100)
Asia/Kabul     11:30  12:30  13:30  14:30  15:30  16:30  17:30  18:30  (+0430)
Africa/Harare  09:00  10:00  11:00  12:00  13:00  14:00  15:00  16:00  (+0200)

スクリプト:

#!/bin/bash

unset -v t0
while getopts t: opt; do
        case $opt in
                t)      t0=$OPTARG ;;
                *)      echo 'Error' >&2; exit 1
        esac
done
shift "$(( OPTIND - 1 ))"

# Use current time if t0 is still unset.
if [ "${t0:+set}" != set ]; then
    printf -v t0 '%(%s)T' -1
fi

# Try to figure out local time zone.
printf -v local_zone '%(%Z)T' "$t0"

# Prepend local time zone to list if set.
set -- ${local_zone:+"$local_zone"} "$@"

export TZ

for TZ do
        {
                printf '%s\n' "$TZ"
                for (( offset = 0; offset < 8; ++offset )); do
                        printf '%(%H:%M)T\n' "$(( t0 + 3600*offset ))"
                done
                printf '(%(%z)T)\n' "$t0"
        } | paste -s -
done | column -t

このスクリプトはprintfフォーマット%(...)T文字列を使用してタイムスタンプ形式を指定します。このフォーマット文字列はbashバージョン4.2で導入されました。これにより、GNUを持たないシステムでもスクリプトを使用できますdate

タイムゾーン別の環境変数を順番に設定して、TZ希望のタイムゾーンのタイムスタンプを出力できます。内部ループは現在の時間(または与えられた時間)と次の8時間を繰り返して、別の行にフォーマットされた時間を出力します。次に、を使用して行全体に整理し、次に「pasteFormat to Table」を使用しますcolumn

関連情報