윤년 - 추정된 값

윤년 - 추정된 값

다음과 같은 테이블(table.txt)이 있습니다.

YEAR MONTH DAY RES
1971 1     1   1345
1971 1     2   1265
1971 1     3   1167

각 시계열의 길이는 에서 1.1.1971까지 입니다 31.12.2099. 불행하게도 일부 시계열에는 윤년과 해당 값이 누락되어 있습니다(예를 들어 1972년은 윤년이므로 2월은 29일이어야 하지만 내 시계열은 1972년 2월에 28일만 있습니다). 예를 들어, 현재 테이블에서 1972년 2월 말의 상황은 다음과 같습니다.

YEAR MONTH DAY RES
1972 2     27  100
1972 2     28  101
1972 3     1   102

이는 윤년을 고려하지 않기 때문에 잘못된 것입니다. 대신 다음과 같이 이전 날짜와 다음 날짜의 값을 추정하여 각 윤년(분명히 2월 29일)의 누락된 날짜를 시계열에 포함하고 싶습니다.

YEAR MONTH DAY RES
1972 2     27  100
1972 2     28  101
1972 2     29  101.5
1972 3     1   102

shell/bash를 사용하여 이를 수행할 수 있는 방법이 있습니까?

답변1

어쩌면 다음과 같은 것일 수도 있습니다.

awk '
  function isleap(y) {
    return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)
  }
  $2 == 3 && $3 == 1 && isleap($1) && last_day != 29 {
    print $1, 2, 29, (last_data + $4) / 2
  }
  {print; last_day = $3; last_data = $4}' file

답변2

그냥 이게 궁금해서 찾아봤는데 윤년은 짝수년마다 번갈아가기 때문에 다음이 성립합니다.

([13579][26]|[02468][048]) == leap year

기본적으로 홀수년의 윤년은 2년과 6년에 발생하고, 짝수년의 윤년은 4년과 8년에 발생하며, 격년으로 10년마다 발생합니다.

그래서 당신은 이것을 할 수 있습니다 :

sed -e'  /[02468] * 2 * 28 /!b'\
    -e'h;/[13579][26] * 2 / G' \
    -e'  /[02468][048] * 2 /G' \
    -e'  /\n/s/ 28 / 29 /2'    \
    -eP\;D <in >out

...교대 주기의 시작점에 관계없이 윤년 동안만 입력에서 2월 28일의 모든 행을 찾아서 두 배로 늘린 다음 수정합니다.


이것이 나의 첫 번째 본능입니다.

sed -e'/\([02648] * 2 * 2\)8 /!b' \
    -e:n -e'n;//!bn' -e'p;s//\19 /' <in

...이것은 귀하에게 드리는 답변을 약간 수정한 것입니다.다른 문제, 그러나 첫 번째 짝수 연도가 번갈아가기 때문에 윤년이 아닌 모든 계열에 대해서만 작동합니다.

sed귀하의 테스트 파일을 기반으로 이 두 가지를 테스트했습니다.다른 문제. 물론 infile에는 이미 윤년이 있고 이를 생성하는 데 사용한 코드도 답변에 있지만 둘 다 1970년에 시작된 시리즈에서 작동하지만 첫 번째 코드는 어쨌든 깨지지 않습니다.


1970  2   27  58
1970  2   28  59
1970  3   1   60
1972  2   27  58
1972  2   28  59
1972  2   29  59
1972  2   29  60
1972  3   1   61
1974  2   27  58
1974  2   28  59
1974  3   1   60
1976  2   27  58
1976  2   28  59
1976  2   29  59
1976  2   29  60
1976  3   1   61
1978  2   27  58
1978  2   28  59
1978  3   1   60
1980  2   27  58
1980  2   28  59
1980  2   29  59
1980  2   29  60
1980  3   1   61

답변3

펄 솔루션:

#!/usr/bin/perl
use warnings;
use strict;

use Time::Piece;

print scalar <>; # Skip the header.

while (<>) {
    my ($year, $month, $day, $res) = split;
    my $t = 'Time::Piece'->strptime("$year $month $day", '%Y %m %d');
    if ($t->is_leap_year && 2 == $month && 28 == $day) {
        print;
        $_ = <>;
        my ($year2, $month2, $day2, $res2) = split;
        die "Expected March the 1st: $_"
            unless $year == $year2 && 3 == $month2 && 1 == $day2;
        print join("\t", $year, 2, 29, ($res + $res2) / 2), "\n";
    }
    print;
}

다른 이름으로 저장 fix_feb29.pl. 그런 다음 실행

for file in *.txt ; do
    fix_feb29.pl -i~ "$file"
done

관련 정보