Все остальные вопросы в сети SE касаются сценариев, в которых предполагается, что дата является now
( Q ) или указывается только дата ( Q ).
То, что я хочу сделать, это указать дату и время, а затем вычесть время из этого.
Вот что я попробовал первым:
date -d "2018-12-10 00:00:00 - 5 hours - 20 minutes - 5 seconds"
Это приводит к 2018-12-10 06:39:55
- Это добавило 7 часов. Затем вычитали 20:05 минут.
После прочтения man
и info
страницы date
, я думал, что это исправлено с этим:
date -d "2018-12-10T00:00:00 - 5 hours - 20 minutes - 5 seconds"
Но результат тот же. Откуда он вообще берет 7 часов?
Я пробовал и другие свидания, потому что думал, что в тот день у нас было 7200 високосных секунд, кто знает, лол. Но результаты те же.
Еще несколько примеров:
$ date -d "2018-12-16T00:00:00 - 24 hours" +%Y-%m-%d_%H:%M:%S
2018-12-17_02:00:00
$ date -d "2019-01-19T05:00:00 - 2 hours - 5 minutes" +%Y-%m-%d_%H:%M:%S
2019-01-19_08:55:00
Но тут становится интересно. Если я опущу время на вводе, он работает нормально:
$ date -d "2018-12-16 - 24 hours" +%Y-%m-%d_%H:%M:%S
2018-12-15_00:00:00
$ date -d "2019-01-19 - 2 hours - 5 minutes" +%Y-%m-%d_%H:%M:%S
2019-01-18_21:55:00
$ date --version
date (GNU coreutils) 8.30
Что мне не хватает?
Обновление: я добавил Z
в конце, и это изменило поведение:
$ date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
2019-01-19_04:00:00
Я все еще в замешательстве, хотя. На информационной странице GNU о дате не так много об этом .
Я предполагаю, что это проблема часового пояса, но цитирую The Calendar Wiki на ISO 8601 :
Если информация о соотношении UTC не указана в представлении времени, предполагается, что время указано в местном времени.
Что я и хочу. Мое местное время также установлено правильно. Я не уверен, почему дата вообще мешает с часовым поясом в этом простом случае, когда я предоставляю дату и хочу вычесть что-то из этого. Не следует ли сначала вычесть часы из строки даты? Даже если он сначала преобразует его в дату, а затем выполняет вычитание, если я пропускаю любые вычитания, я получаю именно то, что хочу:
$ date -d "2019-01-19T05:00:00" +%Y-%m-%d_%H:%M:%S
2019-01-19_05:00:00
Так что, если это действительно проблема с часовым поясом, откуда это безумие?
Ответы:
Этот последний пример должен был прояснить для вас: часовые пояса .
Поскольку выходные данные явно варьируются в зависимости от часового пояса, я подозреваю, что для строки времени не указан какой-то неочевидный параметр по умолчанию без указания часового пояса. Тестируя пару значений, кажется, что это UTC-05: 00 , хотя я не уверен, что это такое.
Используется только при выполнении арифметики даты.
Кажется, проблема в том, что
- 2 hours
это не арифметика, а спецификатор часового пояса :Таким образом, не только не выполняется арифметика, но, по-видимому, происходит
переходналетнее время на1 час, что приводит к несколько бессмысленному времени для нас.Это также относится к сложению:
Отладка немного больше, синтаксический анализ выглядит следующим образом:
2019-01-19T05:00:00 - 2
(-2
будучиhours
часовым поясом) и (= 1 час), с подразумеваемым дополнением. Становится легче увидеть, если вместо этого вы используете минуты:Так, ну, арифметика с датами уже выполняется, но не та, о которой мы просили. ¯ \ (ツ) / ¯
источник
TZ=UTC date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
противTZ=UTC date -d "2019-01-19T05:00:00 - 2 hours" +%Y-%m-%d_%H:%M:%S
)date
соответствии со стандартом ISO 8601 может быть возможной ошибкой , если часовой пояс не указан, следует использовать местное время (часовой пояс), а в случае арифметической операции это не так. Очень странная проблема для меня, хотя.- 2 hours
здесь указывается часовой пояс.--debug
выборе даты ! Отличное объяснение.Он работает правильно, когда вы сначала конвертируете дату ввода в ISO 8601:
источник
date
это испортится, поскольку без каких-либо вычитаний, часовой пояс остается нетронутым, и все также, как и ожидалось, без необходимости предоставлять какие-либо информация о часовом поясе или преобразование.date -I
также выводит спецификатор часового пояса (например2018-12-10T00:00:00+02:00
), который устраняет проблему, описанную в ответеTLDR: это не ошибка. Вы только что обнаружили одно из тонких, но задокументированных действий
date
. При выполнении арифметики времениdate
используйте независимый от часового пояса формат (например, время Unix) или очень внимательно прочитайте документацию, чтобы узнать, как правильно использовать эту команду.GNU
date
использует ваши системные настройки (TZ
переменная среды или, если не установлено, системные значения по умолчанию), чтобы определить часовой пояс даты, заданной параметром-d
/,--date
и даты, сообщаемой+format
аргументом. Вариант также позволяет переопределить часовой пояс для своего собственного опционного-аргумента , но это не отменяет часовой пояс . Это корень путаницы, ИМХО.--date
+format
Учитывая, что мой часовой пояс UTC-6, сравните следующие команды:
Первый использует мой часовой пояс для обоих
-d
и+format
. Второй использует UTC для,-d
но мой часовой пояс для+format
. Третий использует UTC для обоих.Теперь сравните следующие простые операции:
Даже если время Unix говорит мне то же самое, «Нормальное» время отличается из-за моего собственного часового пояса.
Если бы я хотел сделать ту же операцию, но используя исключительно мой часовой пояс:
источник
-08:00
), просто добавьте это для ввода даты-времени ... больше ничего не нужно возиться. Пример:date -d '2019-02-28 14:05:36-08:00 +2 days 4 hours 3 seconds' +'local: %F %T'
дает местное: 2019-03-02 18:05:36+format
аргументом. Например, в моей системе, то же команда выводит:local: 2019-03-02 20:05:39
(если добавить%:z
к+format
, то становится очевидным , что информация верна и расхождение связано с часовых поясов).-d
и+format
Unix-времени, как я сказал в ответе, чтобы избежать неожиданных результатов.GNU
date
поддерживает простую арифметику дат, хотя вычисления времени эпохи, как показано в ответе @sudodus, иногда более понятны (и более переносимы).Использование +/-, когда не указан часовой пояс, указанный в метке времени, инициирует попытку сопоставить часовой пояс в следующем, прежде чем что-либо еще будет проанализировано.
Вот один из способов сделать это, использовать «назад» вместо «-»:
или
(Хотя вы не можете произвольно использовать «Z», он работает в моей зоне, но это делает его временной меткой зоны UTC / GMT - используйте свою собственную зону или% z /% Z, добавив
${TZ:-$(date +%z)}
вместо нее временную метку.)Добавляя дополнительные сроки, эти формы корректируют время:
Можно использовать многие сложные корректировки в любом порядке (хотя относительные и переменные термины, такие как «14 недель, следовательно, последний понедельник», вызывают проблемы ;-)
(Здесь есть еще один маленький beartrap,
date
который всегда будет давать правильную дату, поэтомуdate -d "2019-01-31 1 month"
дает 2019-03-03, как и «в следующем месяце»)Учитывая большое разнообразие поддерживаемых форматов времени и даты, разбор часового пояса обязательно небрежный: это может быть суффикс из одной или нескольких букв, смещение часа или часа: минута, имя «Америка / Денвер» (или даже имя файла). в случае
TZ
переменной).Ваша
2018-12-10T00:00:00
версия не работает, потому что «T» - это просто разделитель, а не часовой пояс, добавление «Z» в конце делает эту работу (в зависимости от правильности выбранной зоны) также ожидаемой.См. Https://www.gnu.org/software/tar/manual/html_node/Date-input-formats.html и, в частности, раздел 7.7.
источник
date -d "2018-12-10 00:00:00 now -5 hours
или,today
или0 hour
вместоnow
, все, что говоритdate
о том, что маркер после времени не является смещением часового пояса.Это решение легко понять, но немного сложнее, поэтому я показываю его в виде шелл-скрипта.
date
командной строкиShellscript:
источник