Wszystkie pozostałe pytania w sieci SE dotyczą scenariuszy, w których zakłada się, że data to now
( Q ) lub w których określono tylko datę ( Q ).
Chcę podać datę i godzinę, a następnie odjąć czas od tego.
Oto, co próbowałem najpierw:
date -d "2018-12-10 00:00:00 - 5 hours - 20 minutes - 5 seconds"
Powoduje to 2018-12-10 06:39:55
- Dodano 7 godzin. Następnie odjęto 20:05 minut.
Po przeczytaniu man
i info
stronie date
, myślałem, że to naprawić z tym:
date -d "2018-12-10T00:00:00 - 5 hours - 20 minutes - 5 seconds"
Ale ten sam wynik. Skąd bierze się nawet 7 godzin?
Próbowałem również innych dat, ponieważ myślałem, że może mieliśmy 7200 sekund przestępnych tego dnia, kto zna lol. Ale te same wyniki.
Kilka innych przykładów:
$ 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
Ale tutaj robi się ciekawie. Jeśli pominę czas na wejściu, działa dobrze:
$ 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
czego mi brakuje?
Aktualizacja: dodałem Z
na końcu i zmieniło to zachowanie:
$ date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
2019-01-19_04:00:00
Nadal jestem zdezorientowany. Na stronie informacyjnej GNU o dacie nie ma wiele na ten temat.
Zgaduję, że jest to problem związany ze strefą czasową, ale cytuję Wiki Wiki na temat ISO 8601 :
Jeśli nie podano informacji o relacji UTC z reprezentacją czasu, zakłada się, że czas jest czasem lokalnym.
Właśnie tego chcę. Mój czas lokalny jest również ustawiony poprawnie. Nie jestem pewien, dlaczego data miałaby w ogóle zadzierać ze strefą czasową w tym prostym przypadku, w którym dostarczam datę i godzinę i chcę ją odjąć. Czy nie powinien najpierw odjąć godzin od ciągu daty? Nawet jeśli najpierw przekształci go w datę, a następnie odejmie, jeśli pominę jakieś odejmowania, otrzymam dokładnie to, czego chcę:
$ date -d "2019-01-19T05:00:00" +%Y-%m-%d_%H:%M:%S
2019-01-19_05:00:00
Więc IF to naprawdę jest to kwestia stref czasowych, gdzie ma to szaleństwo pochodzi?
Odpowiedzi:
Ten ostatni przykład powinien był dla ciebie wyjaśnić: strefy czasowe .
Ponieważ dane wyjściowe wyraźnie różnią się w zależności od strefy czasowej, podejrzewam, że niektóre nieoczywiste wartości domyślne zostały przyjęte dla ciągu czasowego bez określonej strefy czasowej. Testując kilka wartości, wydaje się, że jest to UTC-05: 00 , chociaż nie jestem pewien, co to jest.
Jest używany tylko podczas wykonywania arytmetyki dat.
Wydaje się, że problemem jest to, że nie
- 2 hours
jest traktowany jako arytmetyka, ale jako specyfikator strefy czasowej :Tak więc nie tylko nie wykonuje się arytmetyki, ale wydaje się, że korekta czasu zajmuje 1 godzinę
czasu dziennego, co prowadzi do nieco nonsensownego czasu dla nas.Dotyczy to również dodania:
Trochę więcej debugowania wygląda na to, że parsowanie to:
2019-01-19T05:00:00 - 2
(-2
strefa czasowa) ihours
(= 1 godzina), z domniemanym dodatkiem. Łatwiej jest sprawdzić, czy zamiast tego używasz minut:No cóż, arytmetyka dat jest wykonywana, ale nie ta, o którą prosiliśmy. ¯ \ (ツ) / ¯
źródło
TZ=UTC date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
vsTZ=UTC date -d "2019-01-19T05:00:00 - 2 hours" +%Y-%m-%d_%H:%M:%S
)date
, zgodnie z normą ISO 8601, jeśli nie podano strefy czasowej, należy założyć czas lokalny (strefę), co w przypadku operacji arytmetycznej tak nie jest. Jednak bardzo dziwny problem.- 2 hours
jest brany jako specyfikator strefy czasowej tutaj.--debug
opcji randki ! Świetne wyjaśnienie.Działa poprawnie, jeśli najpierw przekonwertujesz datę wejścia na ISO 8601:
źródło
date
by to zepsuło, ponieważ bez dostarczonych żadnych odejmowań, strefa czasowa pozostaje nietknięta i wszystko jest zgodne z oczekiwaniami bez konieczności podawania żadnych informacje o strefie czasowej lub konwersja.date -I
również specyfikator strefy czasowej (np.2018-12-10T00:00:00+02:00
), Który rozwiązuje problem opisany w odpowiedziTLDR: To nie jest błąd. Właśnie znalazłeś jedno z subtelnych, ale udokumentowanych zachowań
date
. Wykonując arytmetykę czasudate
, użyj formatu niezależnego od strefy czasowej (takiego jak czas uniksowy) lub bardzo czytaj uważnie przeczytaj dokumentację, aby dowiedzieć się, jak poprawnie używać tego polecenia.GNU
date
wykorzystuje ustawienia systemowe (TZ
zmienna środowiskowa lub, jeśli nie jest ustawiona, domyślne ustawienia systemowe), aby określić strefę czasową zarówno daty podanej w opcji-d
/--date
, jak i daty podanej przez+format
argument. Opcja pozwoli również zastąpić strefę czasową dla własnej opcji-argumentu, ale nie zastępują strefie czasowej .--date
+format
To jest przyczyna zamieszania, IMHO.Biorąc pod uwagę, że moja strefa czasowa to UTC-6, porównaj następujące polecenia:
Pierwszy używa mojej strefy czasowej zarówno dla, jak
-d
i dla+format
. Drugi używa UTC tylko dla-d
mojej strefy czasowej+format
. Trzeci używa UTC dla obu.Teraz porównaj następujące proste operacje:
Nawet jeśli czas uniksowy mówi mi to samo, czas „normalny” różni się z powodu mojej własnej strefy czasowej.
Gdybym chciał wykonać tę samą operację, ale używając wyłącznie mojej strefy czasowej:
źródło
-08:00
), po prostu dołącz to, aby wprowadzić datę i godzinę ... nic innego, jak się bawić. Przykład:date -d '2019-02-28 14:05:36-08:00 +2 days 4 hours 3 seconds' +'local: %F %T'
podaje lokalnie: 2019-03-02 18:05:36+format
argument. Na przykład w moim systemie te same polecenia generują:local: 2019-03-02 20:05:39
(jeśli dodam%:z
do+format
, staje się oczywiste, że informacje są poprawne, a rozbieżność wynika ze stref czasowych).-d
i /+format
lub czasu uniksowego, jak powiedziałem w odpowiedzi, aby uniknąć nieoczekiwanych rezultatów.GNU
date
obsługuje prostą arytmetykę dat, chociaż obliczenia czasu epoki, jak pokazano w odpowiedzi @sudodus, są czasami jaśniejsze (i bardziej przenośne).Użycie +/-, gdy nie ma określonej strefy czasowej w sygnaturze czasowej, powoduje próbę dopasowania strefy czasowej, zanim cokolwiek innego zostanie przeanalizowane.
Oto jeden ze sposobów, aby to zrobić, użyj „temu” zamiast „-”:
lub
(Chociaż nie możesz arbitralnie użyć „Z”, działa w mojej strefie, ale to sprawia, że jest to sygnatura czasowa strefy UTC / GMT - użyj własnej strefy lub% z /% Z, dołączając
${TZ:-$(date +%z)}
zamiast niej sygnaturę czasową).Dodając dodatkowe terminy tych formularzy dostosuj czas:
Można zastosować wiele złożonych korekt, w dowolnej kolejności (choć terminy względne i zmienne, takie jak „14 tygodni od ostatniego poniedziałku”, wymagają kłopotów ;-)
(Jest tu także kolejny mały beartrap,
date
zawsze poda prawidłową datę, więcdate -d "2019-01-31 1 month"
podaje 2019-03-03, podobnie jak „następny miesiąc”)Biorąc pod uwagę szeroką gamę obsługiwanych formatów czasu i daty, parsowanie strefy czasowej jest niekoniecznie niechlujne: może to być pojedynczy lub wieloliterowy sufiks, przesunięcie godziny lub godziny: minuty, nazwa „America / Denver” (lub nawet nazwa pliku w przypadku
TZ
zmiennej).Twoja
2018-12-10T00:00:00
wersja nie działa, ponieważ „T” jest tylko separatorem, a nie strefą czasową, a dodanie „Z” na końcu powoduje, że działa (zależnie od poprawności wybranej strefy) zgodnie z oczekiwaniami.Zobacz: https://www.gnu.org/software/tar/manual/html_node/Date-input-formats.html, w szczególności sekcja 7.7.
źródło
date -d "2018-12-10 00:00:00 now -5 hours
albotoday
albo0 hour
zamiastnow
, wszystkiego, co mówidate
, że token po czasie nie jest przesunięcie stref czasowych.To rozwiązanie jest łatwe do zrozumienia, ale nieco bardziej skomplikowane, więc pokazuję je jako skrypt powłoki.
date
wiersza poleceńSkrypt powłoki:
źródło