결과 날짜가 아닌 GNU 도구를 사용하여 날짜 기간을 어떻게 계산하고 형식을 지정할 수 있습니까?

결과 날짜가 아닌 GNU 도구를 사용하여 날짜 기간을 어떻게 계산하고 형식을 지정할 수 있습니까?

지금까지 내가 찾은 수많은 기사는 모두 결과 날짜를 얻는 데 초점을 맞춘 것 같았습니다. 이는 여전히 유용하지만 이 경우에는 내가 원하는 것이 아닙니다.

예시 링크:Unix & Linux SE - 날짜 차이를 빠르게 계산.

다른 Q&A 에서 datediff이는 날짜/시간 기간 결과를 언급하고 싶은 내용에 더 가깝고 기본적으로 이전 변환과 함께 Unix 타임스탬프 수학을 사용하지만 세분성을 초 단위까지 원하므로 그렇게 하지 않습니다. 86400으로 나누지 마세요.

사용 가능한 시간(초)을 사용하여 이제 date다음과 같이 GNU 명령을 사용하는 것과 같은 형식으로 지정하고 싶습니다.date -d "@69600" "+ %Y years %m months %e days %H:%M:%S"

나는 모든 것이 본질적으로 Unix 시대의 날짜/시간 기간이라는 것을 알고 있지만 이제는 일, 월, 연도 숫자가 0부터 시작하지 않아 내가 원하는 기간 값을 올바르게 나타내지 못하는 문제가 있습니다.

이 형식을 잘라내고 더 많은 expr명령을 적용하여 기본적으로 각 값에서 1 또는 1970을 뺄 수 있지만, 수학 연결 외에 기간 결과를 얻기 위해 날짜/시간 계산을 처리하는 더 쉽고 간단한 방법이 있는지 궁금합니다. 단계를 함께 포맷합니다. 어쩌면 date내가 활용할 수 있는 GNU의 다른 옵션이나 2개의 날짜/시간 인수를 허용하고 내가 찾고 있는 결과를 즉시 제공하는 다른 도구가 있을 수도 있습니다 .

Mac용 Homebrew에서 사용할 수 있다는 것은 장점이 될 것입니다 :).

간단한 날짜 수학 링크:Walker 뉴스 - Linux 쉘 스크립트의 날짜 산술

임의의 날짜 형식 링크:

답변1

와 함께날짜 유틸리티'에스datediff(GNU 죄송하지 않음), (이전의 ddiff데비안 dateutils.ddiff에서는 ):

$ dateutils.ddiff -f '%Y years, %m months, %d days, %H:%0M:%0S' \
    '2012-01-23 15:23:01' '2017-06-01 09:24:00'
5 years, 4 months, 8 days, 18:00:59

--from-zone=Europe/London(날짜는 UTC로 사용되며 해당 시간대에서 현지 시간으로 사용되는 날짜 와 같은 것을 추가합니다 . --from-zone=localtime시스템의 기본 시간대에 대해 작동할 수 있습니다. IANA 시간대 파일의 경로를 지정하는 --from-zone="${TZ#:}"한 작동합니다 (예 : POSIX 스타일 TZ 사양이 아님 )).$TZTZ=:Europe/LondonTZ=GMT0BST,M3.5.0/1:00:00,M10.5.0/2:00:00

와 함께완전 개방date, 그래서 여전히 GNU 도구를 사용하지 않습니다. 죄송합니다( ksh93쉘로 사용하는 경우 내장으로 사용할 수 있음) . 단위가 있는 2개의 숫자를 제공하는 형식으로 두 날짜 간의 차이를 얻는 데 date사용할 수 있습니다 .date -E

$ date -E 1970-01-01 2017-06-01
47Y04M
$ date -E 2017-01-01 2017-06-01
4M29d
$ date -E 12:12:01 23:01:43
10h49m

위의 내용을 참고하세요.시간DST(23, 24 또는 25)가 있는 로케일에서는 일의 시간 수가 다양하고 월과 연도의 일 수가 다양하므로 위의 두 단위보다 더 높은 정밀도를 갖는 것이 의미가 없을 수 있으므로 모호합니다.

예를 들어, 2015-01-01 00:00:00과 2016-01-01 00:00:00 또는 2016-01-01 00:00:00과 2017-01-01 00 사이에는 정확히 1년이 있습니다. 00:00이지만 동일한 지속 시간이 아닙니다(한 경우에는 365*24시간, 다른 경우에는 366*24시간).

2017-03-24 12:00:00과 2017-03-25 12:00:00 또는 2017-03-25 12:00:00과 2017-03-26 12:00:00 사이에 정확히 하루가 있습니다. 하지만 유럽 국가의 현지 시간(2017-03-26에 서머타임으로 전환됨)인 경우어느 날한 경우에는 24시간이고 다른 경우에는 23시간입니다.

즉, 연도, 월, 주 또는 일을 언급하는 기간은 적용할 경계(및 시간대) 중 하나와 연결될 때만 의미가 있습니다. 따라서 (일(24시간), 월(30*24시간) 또는 월(30*24시간) 또는 년(365*24시간)).

어느 정도는 초 단위의 지속 시간조차 모호합니다. 단순화를 위해 Unix epoch 시간의 초는 주어진 지구의 날 1 의 86400번째 부분으로 정의됩니다 . 지구가 회전함에 따라 그 초는 점점 더 길어지고 있습니다.

따라서 (GNU 사용) 다음과 같습니다 date.

d1='2016-01-01 00:00:00' d2='2017-01-01 00:00:00'
eval "$(date -d "@$(($(date -d "$d2" +%s) - $(date -d "$d1" +%s)))" +'
  delta="$((%-Y - 1970)) years, $((%-m - 1)) months, $((%-d - 1)) days, %T"')"
echo "$delta"

또는 fish:

date -d@(expr (date -d $d2 +%s) - (date -d $d1 +%s)) +'%Y %-m %-d %T' | \
  awk '{printf "%s years, %s months, %s days, %s\n", $1-1970, $2-1, $3-1, $4, $5}'

실제 시작 날짜인 2016년 대신 1970년에 시간 델타가 적용되므로 일반적으로 올바른 정보를 제공하지 않습니다.

예를 들어, 위의 내용은 (유럽/런던 시간대) 다음과 같습니다.

1 years, 0 months, 1 days, 01:00:00

대신에

1 years, 0 months, 0 days, 00:00:00

(그것은 여전히 ​​당신에게 충분한 근사치일 수 있습니다).


1 기술적으로 하루는 86400 Unix 초이지만 네트워크에 연결된 시스템은 일반적으로 SI 초를 사용하여 시계를 원자 시계와 동기화합니다. 원자 시계가 12:00:00.00을 표시하면 해당 Unix 시스템도 12:00:00.00을 표시합니다. 예외는 윤초 도입 시에만 해당됩니다. 여기서는 2초 동안 지속되는 1개의 Unix 초가 있거나 더 긴 기간에 추가 초를 번지기 위해 조금 더 오래 지속되는 몇 초가 있습니다.

따라서 두 Unix 타임스탬프(원자 시계에 동기화된 시스템에서 발행) 사이의 정확한 기간(원자 초 단위)을 알 수 있습니다. 두 타임스탬프 사이의 Unix epoch 시간 차이를 구하고 도약 횟수를 더합니다. 그 사이에 초가 추가되었습니다.

datediff또한-f %rS진짜두 날짜 사이의 초:

$ dateutils.ddiff -f %S '1990-01-01 00:00:00' '2010-01-01 00:00:00'
631152000
$ dateutils.ddiff -f %rS '1990-01-01 00:00:00' '2010-01-01 00:00:00'
631152009

차이점은 1990년과 2010년 사이에 추가된 9개의 윤초입니다.

이제 그 숫자는진짜초는 일수가 일정하지 않기 때문에 일수를 계산하는 데 도움이 되지 않습니다.진짜초. 두 날짜 사이에는 정확히 20년이 있으며 9초의 윤초는 오히려 그 값에 도달하는 데 방해가 됩니다. 또한 은 ddiff다른 %rS형식 지정자와 결합되지 않은 경우에만 작동합니다. 또한 미래 윤초는 오래 전에 알려지지 않았지만 최근 윤초에 대한 정보도 이용 가능하지 않을 수 있습니다. 예를 들어, 내 시스템은 2012-07-01 이후의 시스템에 대해 알지 못합니다.

답변2

date좋아요, 그러면 그 사이의 기간을 계산하려는 두 시점을 정의하는 두 개의 호환 가능한 문자열이 있다고 가정해 보겠습니다 .

echo $(($(date +%s -d "3 days ago")-$(date +%s -d "4 weeks 2 hours 1 minutes 33 seconds ago"))) | sed 's/-//'

하지만 더 읽기 쉽게 만들고 싶다고 더 자세히 말해 보겠습니다.

convertsecs() {
    hours=$(($1/3600))
    minutes=$(($1%3600/60))
    seconds=$(($1%60))
}
totalduration="$(($(date +%s -d "3 days ago")-$(date +%s -d "4 weeks 2 hours 1 minutes 33 seconds ago"))) | sed 's/-//'"
convertsecs "$totalduration"
echo "Duration was ${hours} hours, ${minutes} minutes, and ${seconds} seconds."

답변3

시간은 복잡한 것이므로 계산하면서 기대치를 관리하는 것이 중요합니다. 나는 일반적인 경우에 당신이 요구하는 것을 정확하고 정확하게 수행하는 것이 기술적으로 가능하다고 믿지 않습니다. 왜냐하면 윤초와 같은 것을 고려하면 주어진 초가 다른 분 수에 해당할 수 있기 때문입니다. 전적으로 예측 가능합니다.

다르게 말하면 하루는 24시간이 아니라 24시간이다.모든일은 정확히 24시간입니다. 따라서 주어진 기간이 몇 일 더하기 분 더하기 초였는지 알고 싶다면 윤초가 있었는지 여부를 알 수 있도록 해당 기간을 실시간 어딘가에 고정해야 합니다. 4월 29일이 그 기간 어딘가에 존재했든 아니든 말이죠.

더욱 이색적인 점은 매달 일수가 같은 것은 아닙니다.

그것이 문제가 되지 않는다면 간단히 기본 산술을 통해 초를 계산해 보십시오. date에포크 이후 초로 변환하는 데 사용하고 , 일수를 얻으려면 86400으로 나누고, 나머지는 시간을 얻기 위해 3600으로 나누고, 나머지는 분을 얻는 식으로 나눕니다.

관련 정보