GNU 도구를 사용하여 결과 날짜 대신 날짜 기간을 계산하고 형식을 지정하려면 어떻게 해야 합니까?

GNU 도구를 사용하여 결과 날짜 대신 날짜 기간을 계산하고 형식을 지정하려면 어떻게 해야 합니까?

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

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

다른 Q&A 에서 datediff이것은 제가 참조하고 싶은 날짜/시간 기간 결과에 가깝습니다. 이는 기본적으로 이전 변환과 함께 Unix 타임스탬프 수학을 사용하지만 세분성을 초 단위로 낮추기를 원합니다. 이것이 바로 나누지 않는 이유입니다. 86400.

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

나는 모든 것이 본질적으로 Unix epoch 날짜/시간 기간이라는 것을 알고 있지만 이제 내가 겪고 있는 문제는 일, 월, 연도 숫자가 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

(날짜는 UTC이며 --from-zone=Europe/London적절한 시간대의 현지 시간과 유사한 날짜를 추가합니다. --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셸로 사용하면 date내장 도구로 작동합니다). date -E단위가 포함된 2개의 숫자를 제공하는 형식을 사용하여 두 날짜 간의 차이를 얻을 수 있습니다.

$ 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년 3월 26일에 일광 절약 시간제로 전환됨)인 경우어느 날어떤 경우에는 24시간이고 다른 경우에는 23시간입니다.

즉, 연, 월, 주 또는 일의 기간에 대한 참조는 적용하려는 경계(및 시간대) 중 하나와 관련해서만 의미가 있습니다. 따라서 적용하려는 시간(시작 또는 끝)을 모르는 경우 일(24시간), 월(30*24시간) 또는 연을 사용하지 않는 한 초를 해당 기간으로 변환할 수 없습니다. (365*24시간)).

초 단위의 지속 시간조차 어느 정도 모호합니다. 단순화를 위해 Unix epoch 시간의 1초는 주어진 지구의 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을 표시합니다. 유일한 예외는 윤초가 도입되는 경우입니다. 여기서 Unix 초는 2초 동안 지속되거나 몇 초가 더 오래 지속되어 추가 초가 더 오랜 기간에 걸쳐 분산됩니다.

따라서 두 Unix 타임스탬프(원자 시계와 동기화된 시스템에 의해 게시됨) 사이의 정확한 기간(원자 초)을 알 수 있습니다. 두 타임스탬프 사이의 Unix 에포크 시간 차이를 구하고 초 사이의 도약 수를 추가합니다.

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시간입니다. 따라서 주어진 기간이 몇 일 더하기 분 더하기 초인지 알고 싶다면 윤초가 있는지 또는 심지어 윤초가 있는지 알 수 있도록 해당 기간을 실시간 어딘가에 고정해야 합니다. 4월이면 해당 기간 어딘가에 29일이 존재합니까?

더욱 특이한 점은 매달 일수가 같은 것이 아니라는 점입니다.

문제가 되지 않으면 기본 산술로 초를 계산하면 됩니다. date에포크 이후의 초로 변환하려면 86400으로 나누어 일 수를 구하고 나머지를 3600으로 나누어 시간 수를 구하고 나머지는 숫자를 구합니다. 분 등.

관련 정보