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


18

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

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


답변:


20

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

$ 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

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


1
@confetti 그것은 실제로 않습니다; 이 기본 시간대는 더하기 / 빼기 (비교 TZ=UTC date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%Svs TZ=UTC date -d "2019-01-19T05:00:00 - 2 hours" +%Y-%m-%d_%H:%M:%S) 시에만 사용됩니다.
Olorin

2
dateISO 8601 표준에 따라 가능한 버그 일 수 있습니다. 시간대가 제공되지 않으면 현지 시간 (지역)을 가정해야합니다. 산술 연산의 경우에는 그렇지 않습니다. 그래도 매우 이상한 문제입니다.
색종이 조각

1
@ confetti는 문제를 발견했습니다 : - 2 hours여기에서 시간대 지정자로 사용됩니다.
Olorin

2
와. 이제는 어떤 의미가 있습니다. 글쎄, 적어도 그것을 설명합니다. 알아 내셔서 감사합니다. 나에게 그것은 그들의 파서가 업데이트를 필요로하는 것처럼 들리지만, 이와 같은 형식과 공백을 사용하면 시간대를`-2 시간 '으로 지정하고 싶지 않으며 혼란을 초래합니다. 그들이 파서를 업데이트하고 싶지 않다면 적어도 매뉴얼은 이것에 대해 메모해야합니다.
색종이 조각

1
오늘은 날짜 --debug옵션 에 대해 배웠습니다 ! 좋은 설명입니다.
Jeff Schaller

6

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

감사합니다. 실제로 작동하지만 이에 대한 설명이 있습니까? 내 질문에 ISO 8601에 대한 정보를 더 추가했으며 date뺄셈을 제공하지 않고 어디서 엉망이 될지 알지 못하며 시간대는 그대로 유지되며 모든 것은 공급하지 않아도 예상대로 시간대 정보 또는 변환.
색종이 조각

말할 수 없어요, 미안 다른 사람이 이것에 대답 할 수 있다면 너무 궁금해서 기뻐할 것입니다.
pLumo

나도 기쁠 것이지만 내 문제를 해결하기 때문에 지금은 이것을 받아 들일 것입니다!
색종이 조각

3
이 작품 때문에 date -I또한 시간대 지정자 (예를 들어, 출력 2018-12-10T00:00:00+02:00문제가 설명 수정) Olorin, 응답
ilkkachu

6

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

4
epoch / Unix 시간에 대한 언급으로 imo는 시간 산술을하는 유일한 방법입니다
Rui F Ribeiro

1
TL; DR 만약 Zulu 시간으로부터 현지 시간 오프셋을 알고 있다면 (예 : 미국 서해안은 -8 시간 또는 -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
B Layer

1
@BLayer 당신이 맞습니다, 그것은 그 시나리오에서 예상대로 작동합니다. 그러나 해당 접근법을 사용하는 지정된 스크립트가 다른 시간대가있는 장소에서 실행되는 상황을 상상해보십시오. 기술적으로 올바른 결과는 +format인수가 제공 한 정보에 따라 잘못 보일 수 있습니다 . 예를 들어, 내 시스템에 동일한 명령 출력은 : local: 2019-03-02 20:05:39(내가 추가 할 경우 %:z+format,이 정보가 정확하고 불일치가 시간대로 인해 분명하게).
nxnev

@ BLayer IMHO, 더 나은 일반적인 접근 방식은 예기치 않은 결과를 피하기 위해 대답에서 말했듯이 유닉스 시간 -d+format유닉스 시간 모두에 동일한 시간대를 사용하는 것 입니다.
nxnev

1
@nxnev Agreed, 게시 / 공유 할 스크립트를 작성하는 경우 문자 그대로의 의미 외에 "자신의 시간대를 알고있는 경우"라는 단어는 캐주얼 / 개인적인 사용을 의미합니다. 자신의 시스템을 알고있는 것처럼 어리석은 것에 의존하는 스크립트를 게시하는 사람은 아마도 스크립트 공유 게임에 있어서는 안됩니다. :) 반면에 나는 모든 개인 환경에서 내 자신의 명령을 사용합니다.
B 레이어

4

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을 참조하십시오 .


1
다른 옵션은 다음과 같습니다 date -d "2018-12-10 00:00:00 now -5 hours, 또는 today0 hour대신 now말해 무엇이든, date시간 이후 토큰이 오프셋 시간대가 아니라고.
Stéphane Chazelas

1
또는 철저하게하기 위해 인수를 다시 정렬하여 날짜-시간 이후에 아무것도 남기지 마십시오. date -d "-5 hours 2018-12-10 00:00:00"`
B Layer

2

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

  • '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"
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.