날짜와 bash를 사용하여 시간 빼기

날짜와 bash를 사용하여 시간 빼기

SE 네트워크의 다른 모든 질문에는 now(묻다) 또는 날짜만 지정하는 경우(묻다).

내가 원하는 것은 날짜와 시간을 제공한 다음 거기에서 시간을 빼는 것입니다.
이것이 내가 먼저 시도한 것입니다.

date -d "2018-12-10 00:00:00 - 5 hours - 20 minutes - 5 seconds"

결과는 2018-12-10 06:39:55- 7시간이 추가되었습니다. 그런 다음 20:05분을 뺍니다.

maninfo페이지를 읽은 후 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 정보 페이지날짜에 대해서.

시간대 문제인 것 같지만 인용하자면달력 위키존재하다ISO 8601:

시간 표현과 함께 UTC 관계 정보가 제공되지 않으면 시간은 현지 시간으로 간주됩니다.

이것이 내가 원하는거야. 현지 시간도 올바르게 설정되어 있습니다. 날짜/시간을 제공하고 그로부터 무언가를 빼려는 간단한 경우에 날짜가 시간대와 혼동되는 이유가 무엇인지 잘 모르겠습니다. 먼저 날짜 문자열에서 시간을 빼면 안 되나요? 먼저 날짜로 변환한 다음 빼더라도 빼기를 생략하면 원하는 결과를 얻을 수 있습니다.

$ date -d "2019-01-19T05:00:00" +%Y-%m-%d_%H:%M:%S
2019-01-19_05:00:00

그래서만약에이것은 실제로 시간대 문제입니다. 이 광기는 어디에서 오는 것입니까?

답변1

이 마지막 예에서는 다음 사항을 명확히 했습니다.시간대.

$ TZ=UTC date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
2019-01-19_03:00:00
$ TZ=Asia/Colombo date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S 
2019-01-19_08:30:00

출력은 시간대에 따라 분명히 다르기 때문에 시간대를 지정하지 않고 시간 문자열에 일부 불분명한 기본값이 적용되는 것으로 의심됩니다. 여러 값을 테스트한 결과UTC-05:00, 그게 뭔지는 모르겠지만요.

$ TZ=UTC date -d "2019-01-19T05:00:00 - 2 hours" +%Y-%m-%d_%H:%M:%S%Z
2019-01-19_08:00:00UTC
$ TZ=UTC date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S%Z
2019-01-19_03:00:00UTC
$ TZ=UTC date -d "2019-01-19T05:00:00" +%Y-%m-%d_%H:%M:%S%Z           
2019-01-19_05:00:00UTC

날짜 연산을 수행할 때만 사용됩니다.


여기서 문제 - 2 hours가 있는 것 같습니다아니요산술적으로 취급되지만시간대 지정자:

# TZ=UTC date -d "2019-01-19T05:00:00 - 2 hours" +%Y-%m-%d_%H:%M:%S%Z --debug
date: parsed datetime part: (Y-M-D) 2019-01-19 05:00:00 UTC-02
date: parsed relative part: +1 hour(s)
date: input timezone: parsed date/time string (-02)
date: using specified time as starting value: '05:00:00'
date: starting date/time: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02'
date: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02' = 1547881200 epoch-seconds
date: after time adjustment (+1 hours, +0 minutes, +0 seconds, +0 ns),
date:     new time = 1547884800 epoch-seconds
date: timezone: TZ="UTC" environment value
date: final: 1547884800.000000000 (epoch-seconds)
date: final: (Y-M-D) 2019-01-19 08:00:00 (UTC)
date: final: (Y-M-D) 2019-01-19 08:00:00 (UTC+00)
2019-01-19_08:00:00UTC

따라서 연산이 수행되지 않을 뿐만 아니라 일광 절약 시간제 에 따라 시간이 1시간 조정된 것처럼 나타나서 우리 시간이 다소 우스꽝스럽습니다.

이는 추가에도 적용됩니다.

# TZ=UTC date -d "2019-01-19T05:00:00 + 5:30 hours" +%Y-%m-%d_%H:%M:%S%Z --debug
date: parsed datetime part: (Y-M-D) 2019-01-19 05:00:00 UTC+05:30
date: parsed relative part: +1 hour(s)
date: input timezone: parsed date/time string (+05:30)
date: using specified time as starting value: '05:00:00'
date: starting date/time: '(Y-M-D) 2019-01-19 05:00:00 TZ=+05:30'
date: '(Y-M-D) 2019-01-19 05:00:00 TZ=+05:30' = 1547854200 epoch-seconds
date: after time adjustment (+1 hours, +0 minutes, +0 seconds, +0 ns),
date:     new time = 1547857800 epoch-seconds
date: timezone: TZ="UTC" environment value
date: final: 1547857800.000000000 (epoch-seconds)
date: final: (Y-M-D) 2019-01-19 00:30:00 (UTC)
date: final: (Y-M-D) 2019-01-19 00:30:00 (UTC+00)
2019-01-19_00:30:00UTC

추가로 디버깅하면 구문 분석은 (시간대) 및 ( 2019-01-19T05:00:00 - 2=1시간)이며 암시적으로 추가됩니다. 대신 분을 사용하면 확인하기가 더 쉽습니다.-2hours

# TZ=UTC date -d "2019-01-19T05:00:00 - 2 minutes" +%Y-%m-%d_%H:%M:%S%Z --debug
date: parsed datetime part: (Y-M-D) 2019-01-19 05:00:00 UTC-02
date: parsed relative part: +1 minutes
date: input timezone: parsed date/time string (-02)
date: using specified time as starting value: '05:00:00'
date: starting date/time: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02'
date: '(Y-M-D) 2019-01-19 05:00:00 TZ=-02' = 1547881200 epoch-seconds
date: after time adjustment (+0 hours, +1 minutes, +0 seconds, +0 ns),
date:     new time = 1547881260 epoch-seconds
date: timezone: TZ="UTC" environment value
date: final: 1547881260.000000000 (epoch-seconds)
date: final: (Y-M-D) 2019-01-19 07:01:00 (UTC)
date: final: (Y-M-D) 2019-01-19 07:01:00 (UTC+00)
2019-01-19_07:01:00UTC

따라서 날짜 산술이 수행되고 있지만 우리가 요청한 것은 아닙니다.  ̄\(ツ)/ ̄

답변2

입력 날짜를 ISO 8601로 처음 변환하면 정상적으로 작동합니다.

$ date -d "$(date -Iseconds -d "2018-12-10 00:00:00") - 5 hours - 20 minutes - 5 seconds"
So 9. Dez 18:39:55 CET 2018

답변3

GNU는 date간단한 날짜 산술을 지원하지만 @sudodus의 답변에 표시된 신기원 시간 계산이 때로는 더 깨끗하고 이식성이 뛰어납니다.

타임스탬프에 시간대가 지정되지 않은 경우 +/-를 사용하면 다른 콘텐츠를 구문 분석하기 전에 시간대를 일치시키려는 후속 시도가 트리거됩니다.

"-" 대신 "ago"를 사용하여 이를 수행하는 방법은 다음과 같습니다.

$ date -d "2018-12-10 00:00:00 5 hours ago 20 minutes ago 5 seconds ago"
Sun Dec  9 18:39:55 GMT 2018

또는

$ date -d "2018-12-10 00:00:00Z -5 hours -20 minutes -5 seconds"
Sun Dec  9 18:39:55 GMT 2018

("Z"를 임의로 사용할 수는 없지만 내 영역에서는 작동하지만 UTC/GMT 영역 타임스탬프가 됩니다. 자체 영역을 사용하거나 ${TZ:-$(date +%z)}타임스탬프에 추가하여 %z/%Z 를 바꾸세요.)

시간을 조정하려면 다음과 같은 형태의 추가 시간 항목을 추가하세요.

  • "5시간 전" - 5시간
  • "4시간"은 (암묵적으로) 4시간을 더합니다.
  • "3시간 후"는 (명시적으로) 3시간을 추가합니다(이전 버전에서는 지원되지 않음).

어떤 순서로든 많은 복잡한 조정을 사용할 수 있습니다("지난 월요일 이후 14주"와 같은 상대적이고 가변적인 용어는 문제를 야기하지만 ;-)

(여기에 또 다른 문제가 있습니다. date유효한 날짜는 항상 제공되므로 date -d "2019-01-31 1 month""다음 달"과 같이 2019-03-03이 제공됩니다.)

지원되는 시간 및 날짜 형식이 다양하기 때문에 시간대 구문 분석은 필연적으로 엉성합니다. 단일 또는 다중 문자 접미사, 시간 또는 시:분 오프셋, 이름 "America/Denver"(또는 파일 이름)일 수 있습니다. 변수에서 TZ).

"T"는 단지 구분 기호일 뿐이고 시간대가 아니기 때문에 버전 2018-12-10T00:00:00이 작동하지 않습니다. 끝에 "Z"를 추가하면 예상대로 작동합니다(선택한 구역의 정확성에 따라 다름).

바라보다: https://www.gnu.org/software/tar/manual/html_node/Date-input-formats.html 특히 섹션 7.7.

답변4

이 솔루션은 이해하기 쉽지만 약간 더 복잡하므로 쉘스크립트로 보여드리겠습니다.

  • "1970-01-01 00:00:00 UTC 이후의 초"로 변환
  • 차이를 더하거나 빼세요
  • date최종 명령줄을 사용하여 사람이 읽을 수 있는 형식으로 다시 변환

쉘 스크립트:

#!/bin/bash

startdate="2018-12-10 00:00:00"

ddif="0"          # days
diff="-5:-20:-5"  # hours:minutes:seconds

#-----------------------------------------------------------------------------

ss1970in=$(date -d "$startdate" "+%s")  # seconds since 1970-01-01 00:00:00 UTC
printf "%11s\n" "$ss1970in"

h=${diff%%:*}
m=${diff#*:}
m=${m%:*}
s=${diff##*:}
difs=$(( (((ddif*24+h)*60)+m)*60+s ))
printf "%11s\n" "$difs"

ss1970ut=$((ss1970in + difs))  # add/subtract the time difference
printf "%11s\n" "$ss1970ut"

date -d "@$ss1970ut" "+%Y-%m-%d %H:%M:%S"

관련 정보