Почему`-`(минус )интерпретация даты GNU отличается от интуитивной, когда дата указана?

Этот скрипт перехватывает stdout и stderr и снова выводит их на stdout, если код выхода равен 0, и на stderr в противном случае.

Если строка содержит «ошибка :409 уже содержит версию», функция возвращает 0, а в противном случае исходный код выхода.

#!/bin/bash

function do_nuget ()
{
        # save stdout and stderr
        out=$(dotnet nuget push "$1" --source "$2" --api-key "$3" 2>&1)
        exitcode=$?

        # if out is not empty...
        if [ -n "$out" ]; then
                if [ $exitcode -eq 0 ]; then
                        # echo to stdout
                        echo "$out"
                else
                        # echo to stderr
                        echo "$out" >&2
                fi
        fi
        if [ "$out" != "${out/error: 409 already contains version}" ]; then
                return 0
        fi
        return $exitcode
}
do_nuget "package.1.2.3.nupkg" "mysource" "mykey"
echo "got exit code: $?"
12
19.04.2021, 22:42
3 ответа

Вкратце :Дата, которую вы указываете с помощью --date, берется по местному времени, если вы не укажете часовой пояс, и что-то вроде +/- NNNпринимается за единицу. Только все, что после этого, даже если это просто hour, принимается как относительный модификатор. Таким образом, - 1 hourозначает не отнять один час от заданного времени, а указать, что время находится в часовом поясе UTC -01, а затем к добавить к нему один час.


То, что я думаю, должно работать для того, что вы пытаетесь, это либо явно указать часовой пояс перед смещением, либо поставить смещение первым , чтобы его нельзя было спутать с часовым поясом.

Здесь используется часовой пояс Центральноевропейского летнего времени (CEST )и сегодняшняя дата с добавлением %Zк выходным данным для отображения часового пояса. (Вы также можете использовать %zдля вывода числового часового пояса или здесь +0200.)

$ date +'%F %T %Z' -d '2021-04-19 12:00:00 CEST + 5 hours'
2021-04-19 17:00:00 CEST
$ date +'%F %T %Z' -d '+ 5 hours 2021-04-19 12:00:00'
2021-04-19 17:00:00 CEST

Хотя, конечно, для январской даты, как в вопросе, летний -часовой пояс, такой как CEST, не будет допустимым. Но перестановка двух по-прежнему работает, время, которое вы указываете, просто принимается за местное время в это время.

$ date +'%F %T %Z' -d '+ 5 hours 2021-01-01 12:00:00'
2021-01-01 17:00:00 CET

(А для 2021-10-31 02:30:00я получаю CET, хотя это время также существует в CEST...)

(См. старые версии этого ответа для получения дополнительных примеров того, как он интерпретирует различные входные данные.)


Согласно ответу @muru на другой вопрос , мы также можем использовать опцию --debug, чтобы программа действительно сообщала нам, что она сделала. Обратите внимание на вторую и третью строки:

$ date --debug +'%F %T %Z' -d '2021-04-19 12:00:00 - 1 hour'
date: parsed date part: (Y-M-D) 2021-04-19
date: parsed time part: 12:00:00 TZ=-01:00
date: parsed relative part: +1 hour(s)
date: input timezone: -01:00 (set from parsed date/time string)
date: using specified time as starting value: '12:00:00'
date: starting date/time: '(Y-M-D) 2021-04-19 12:00:00 TZ=-01:00'
date: '(Y-M-D) 2021-04-19 12:00:00 TZ=-01:00' = 1618837200 epoch-seconds
date: after time adjustment (+1 hours, +0 minutes, +0 seconds, +0 ns),
date:     new time = 1618840800 epoch-seconds
date: output timezone: +01:00 (set from TZ="Europe/Berlin" environment value)
date: final: 1618840800.000000000 (epoch-seconds)
date: final: (Y-M-D) 2021-04-19 14:00:00 (UTC0)
date: final: (Y-M-D) 2021-04-19 16:00:00 (output timezone TZ=+01:00)
2021-04-19 16:00:00 CEST

В справочной странице говорится:

The date string format is more complex than is easily documented here [...]

Что действительно кажется вполне уместным. Более полная документация находится на информационных страницах или в Интернете :https://www.gnu.org/software/coreutils/manual/html_node/Date-input-formats.html

.
19
28.04.2021, 22:52

Да, когда значение -d простое, его эффект можно легко понять.
Да, -d '- 1 hour'сместит время на 1 час назад.

$ date ; date -d '- 1 hour'
Mon 19 Apr 2021 07:58:52 AM EDT
Mon 19 Apr 2021 06:58:52 AM EDT

Часовой пояс

Строка, которую генерирует date, указывает "момент времени".
По умолчанию этот «момент времени» записывается по местному времени. Но это также может быть записано в UTC0:

$ date ; date -u
Mon 19 Apr 2021 12:43:04 PM WAT
Mon 19 Apr 2021 11:43:04 AM UTC

Предположим, что ваше местное время – WAT -Западноафриканское время (WAT ).

Разумеется, такой же «момент времени» мог произойти и в других часовых поясах:

$ TZ=Asia/Kolkata date -d "Mon 19 Apr 2021 12:43:04 PM WAT"
Mon 19 Apr 2021 05:13:04 PM IST

Обратите внимание, что внутри значения -dнаходится именно та дата, которая напечатана выше.

Это означает, что «момент времени» является полным только тогда, когда включен часовой пояс.

Вот почему рекомендуется печатать даты с добавлением %zили %Z. Формат %F %Rв этом смысле неполный, лучше использовать +'%F %R %z'.

строка даты

Когда вы использовали дату 2000/1/2 03:04:05, вы не указали часовой пояс.
Вот почему команда dateпринимает следующий - 1за часовой пояс :

.
$ date -u -d '2000/1/2 03:04:05'; date -u -d '2000/1/2 03:04:05 - 1'
Sun 02 Jan 2000 03:04:05 AM WAT
Sun 02 Jan 2000 05:04:05 AM WAT

Это предполагает, что ваше местное время — WAT (и не меняется на летнее время, без летнего времени ). Я не могу сказать, так как вы не использовали ни %z, ни %Z. Изменение часового пояса изменило значение -dс+1(WAT )на -1, разница в два часа.

Кроме того, вы написали hourпосле этого, что это дополнительный час:

$ date -d '2000/1/2 03:04:05'; date -d '2000/1/2 03:04:05 - 1 hour'
Sun 02 Jan 2000 03:04:05 AM WAT
Sun 02 Jan 2000 06:04:05 AM WAT

Подтверждаю результаты.

И, наконец, +1:

$ date -d '2000/1/2 03:04:05 - 1 hour'; date -d '2000/1/2 03:04:05 + 1 hour ago'
Sun 02 Jan 2000 06:04:05 AM WAT
Sun 02 Jan 2000 02:04:05 AM WAT

+1не изменяет значение времени (, как в WAT, или +1,уже ), но hour agoсдвигает время на 1 час назад (с 3 на 2 ).

Решения

Поместите часовой пояс в значение времени -d.
Или поставьте сначала относительную часть- 1 hour

$ date -d '2000/1/2 03:04:05 +0100 - 1 hour'
  Sun 02 Jan 2000 02:04:05 AM WAT


$ date -d '-1 hour 2000/1/2 03:04:05'
  Sun 02 Jan 2000 02:04:05 AM WAT
7
28.04.2021, 22:52

Многие другие инструменты обработки даты выполняют синтаксический анализ и арифметику даты как отдельные этапы. Например, с Perl:

perl -sE '
    use Time::Piece;
    use Time::Seconds;

    $t = Time::Piece->strptime($timestamp, $format);
    say $t->cdate;

    $s = $t + ONE_HOUR;
    say $s->cdate;

    $s = $t - ONE_HOUR;
    say $s->cdate;
' -- -timestamp='2000/1/2 03:04:05' -format='%Y/%m/%d %T'
Sun Jan  2 03:04:05 2000
Sun Jan  2 04:04:05 2000
Sun Jan  2 02:04:05 2000
1
28.04.2021, 22:52

Теги

Похожие вопросы