날짜와 bash를 사용하여 시간 빼기 seconds” 그러나 같은 결과입니다. 7 시간

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 분을 뺍니다.

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 끝에 a 를 추가 했으며 동작이 변경되었습니다.

$ date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
2019-01-19_04:00:00

그래도 여전히 혼란 스러워요. 날짜에 관한 GNU 정보 페이지 에는 그다지 많지 않습니다 .

나는 이것이 시간대 문제라고 생각하지만 ISO 8601의 The Calendar Wiki 를 인용한다 .

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

내가 원하는 것입니다. 내 현지 시간도 올바르게 설정되어 있습니다. 날짜 시간을 제공하고 그로부터 무언가를 빼고 싶어하는이 간단한 경우에 왜 날짜가 시간대와 엉망인지 잘 모르겠습니다. 날짜 문자열에서 시간을 먼저 빼면 안됩니까? 그것이 먼저 날짜로 변환 한 다음 빼기를 수행하더라도 빼기를 빼면 내가 원하는 것을 정확하게 얻습니다.

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

그래서 경우 이 진정으로 시간대 문제입니다, 어디 그 광기에서 오는가?



답변

그 마지막 예는 시간대 를 명확하게 보여 주어야 합니다 .

$ 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( -2표준 시간대 임) hours. 대신 분을 사용하는지 쉽게 알 수 있습니다.

# 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

자, 날짜 계산은 우리가 요청한 것이 아니라 수행됩니다. ¯ \ (ツ) / ¯


답변

입력 날짜를 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


답변

TLDR : 이것은 버그가 아닙니다. 의 미묘하지만 문서화 된 동작 중 하나를 발견했습니다 date. 함께 시간 연산을 수행 할 때 date, (유닉스 시간 같은) 시간대에 독립적 인 형식을 사용 또는 읽기 매우 적절이 명령을 사용하는 방법을 알고주의 깊게 문서를.


GNU date는 시스템 설정 ( TZ환경 변수 또는 설정되지 않은 경우 시스템 기본값)을 사용하여 -d/ --date옵션을 제공 한 날짜와 +format인수 가보고 한 날짜 의 시간대를 결정합니다 . --date옵션을 사용하면 자체 옵션 인수의 시간대를 재정의 할 수 있지만의 시간대는 재정의하지 않습니다 +format.이것이 혼동의 근원입니다. IMHO.

내 시간대가 UTC-6임을 고려하여 다음 명령을 비교하십시오.

$ date -d '1970-01-01 00:00:00' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-01 00:00:00 -06:00
Unix: 21600
$ date -d '1970-01-01 00:00:00 UTC' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1969-12-31 18:00:00 -06:00
Unix: 0
$ TZ='UTC0' date -d '1970-01-01 00:00:00 UTC' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-01 00:00:00 +00:00
Unix: 0

첫 번째는 모두 내 시간대 사용 -d+format. 두 번째는 UTC를 사용 -d하지만 내 시간대는에 사용 +format합니다. 세 번째는 UTC를 모두 사용합니다.

이제 다음 간단한 조작을 비교하십시오.

$ date -d '1970-01-01 00:00:00 UTC +1 day' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-01 18:00:00 -06:00
Unix: 86400
$ TZ='UTC0' date -d '1970-01-01 00:00:00 UTC +1 day' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-02 00:00:00 +00:00
Unix: 86400

유닉스 시간이 똑같은 것을 말해도 “표준”시간은 내 시간대로 인해 다릅니다.

동일한 작업을 원하지만 내 시간대를 독점적으로 사용하려는 경우 :

$ TZ='CST+6' date -d '1970-01-01 00:00:00 -06:00 +1 day' '+Normal: %F %T %:z%nUnix: %s'
Normal: 1970-01-02 00:00:00 -06:00
Unix: 108000


답변

date@sudodus의 답변에 표시된 획기적인 시간 계산이 때로는 더 명확하고 이식성이 뛰어나지 만 GNU 는 간단한 날짜 산술을 지원합니다.

타임 스탬프에 지정된 시간대가없는 경우 +/-를 사용하면 다른 항목을 구문 분석하기 전에 다음 시간대와 일치하는 시도가 트리거됩니다.

이를 수행하는 한 가지 방법이 있습니다. “-“대신 “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을 제공합니다)

지원되는 다양한 시간 및 날짜 형식을 감안할 때 시간대 구문 분석은 반드시 느슨합니다. 단일 또는 다중 문자 접미사, 시간 또는 시간 : 분 오프셋, 이름 “미국 / 덴버”(또는 파일 이름) 일 수 있습니다. TZ변수 의 경우 ).

귀하의 2018-12-10T00:00:00“T”는 말에 “Z”를 추가, 단지 구분이 아닌 시간대이기 때문에 버전은 너무 예상대로 작업 (선택 영역의 정확성에 따라)를 만드는 작업을하지 않습니다.

https://www.gnu.org/software/tar/manual/html_node/Date-input-formats.html
및 특히 ​​섹션 7.7을 참조하십시오
.


답변

이 솔루션은 이해하기 쉽지만 조금 더 복잡하므로 셸 스크립트로 표시합니다.

  • ‘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"


답변