目次

年月日補正(AWK)

 GPSの出力してくる年月日の情報が、1024週前と
 なっているようなので、確認スクリプトを作成
 してみました。

 1024週前というのは、途中にうるう年を挟むこと
 があるので、西暦年4桁を入力すると、うるう年
 か否かの判定をする関数を最初に考えました。

 巷に流布されている、うるう年の判定を
 関数にすると、以下。

function is_wyear(x) {
  # default
  result = 0
  # judge
  if ( (x % 4) == 0 ) {
    result = 1
  } else {
    if ( (x % 400) == 0 && (x % 100) == 0 ) { result = 1 }
  }

  return result
}

 西暦年が4で割り切れると、無条件でうるう年です。
 400で割り切れて、かつ100で割り切れるとしたなら
 うるう年となります。

 1024週の差があると、1年を365日で計算していては
 ズレが発生するので、基点となる年から1年ずつずら
 していき、うるう年とわかれば、366を減算する補正を
 入れます。

 補正は、次のように処理。

  # calculate years and days
  x = $1 * 7
  q = int(x / 365)
  r = x % 365
  if ( r >= $3 ) { r = r - $3 }
  # show correct year month day
  x = $3
  year = $2+2000
  # judge 
  yy = year
  cnt = 0
  q = int(($1 * 7)/ 365)
  for ( i = 0 ; i <= q ; i++ ) {
    # judge
    cnt = cnt + is_wyear(yy)
    # decrement
    yy = yy - 1
  }
  # adjust
  r = r - cnt
  mx = 365 - r + is_wyear(yy)

 フィールド1には、週で1024を指定している
 ので、日数に変換するために、7を乗算して
 います。

 年と日に分けるために、365で割った商と余り
 を計算で求めていきます。

 西暦年は、現在21世紀に入っているので
 2000を加算。これは暗黙のルールとして
 適用。

 開始の西暦年が決められたなら、1年ずつ
 減らして、うるう年と平年の判断をしつつ
 1024週に相当する日数を減算して補正する
 ことを繰り返します。

 日数から月日を計算するために、1月から11月
 までの経過日数を、うるう年と平年で区別して
 求めてあると仮定し、算出しています。

 上のシーケンスを走らせた後、1月1日からの
 経過日数を与えて、月日を計算する関数を定義
 しておきます。

function calc_md(x,y) {
  # copy
  xx = x
  # default
  mx = "3128313031303131303130"
  mm = 1 ; dd = 1
  # local value
  mx0  = 0
  mx1  = mx0 + substr(mx,1,2)
  mx2  = mx1 + substr(mx,3,2) + y
  mx3  = mx2 + substr(mx,5,2)
  mx4  = mx3 + substr(mx,7,2)
  mx5  = mx4 + substr(mx,9,2)
  mx6  = mx5 + substr(mx,11,2)
  mx7  = mx6 + substr(mx,13,2)
  mx8  = mx7 + substr(mx,15,2)
  mx9  = mx8 + substr(mx,17,2)
  mx10 = mx9 + substr(mx,19,2)
  mx11 = mx10 + substr(mx,21,2)
  # calculate area
  q = int(xx / 100)
  # Oct - Dec
  if ( q == 3 ) {
    if ( xx > mx11 ) {
      mm = 12 ; dd = xx - mx11
    } else {
      mm = 10 ; dd = xx - mx9
      if ( xx > mx10 ) {
        mm = 11 ; dd = xx - mx10
      }
    }
  }
  # Jul - Sep
  if ( q == 2 ) {
    if ( xx > mx9 ) {
      mm = 10 ; dd = xx - mx9
    } else {
      if ( xx > mx8 ) {
        mm = 9 ; dd = xx - mx8
      } else {
        mm = 7 ; dd = xx - mx6
        if ( xx > mx7 ) {
          mm = 8  dd = xx - mx7
        }
      }
    }
  }
  # Apr - Jun
  if ( q == 1 ) {
    if ( xx > mx5 ) {
      mm = 6 ; dd = xx - mx5
    } else {
      mm = 4 ; dd = xx - mx3
      if ( xx > mx4 ) {
        mm = 5 ; dd = xx - mx4
      }
    }
  }
  # Jan - Mar
  if ( q == 0 ) {
    if ( xx > mx3 ) {
      mm = 4 ; dd = xx - mx3
    } else {
      if ( xx > mx2 ) {
        mm = 3 ; dd = xx - mx2
      } else {
        mm = 1 ; dd = xx
        if ( xx > mx1 ) {
          mm = 2 ; dd = xx - mx1
        }
      }
    }
  }
  # adjust (start with 1)
  if ( mm == 1 && dd == 0 ) { dd = dd + 1 }
  # concatenate
  result = mm * 100 + dd

  return result
}

 100で割った商が月、余りが日になるように
 してあります。これで関数が返す値をひとつ
 にできます。

 テキストファイルには、フィールドごとに
 次のパラメータを設定。

 この仕様で、次のようにテキストファイルの
 内容を与えます。

1024 18 132

 テキストファイルの内容を読み込んでから
 結果を出力するまでのシーケンスを、次の
 ように決定。
  1. 入力パラメータから差分となる年と日数計算
  2. 現在の年月日を表示
  3. 現在の年月日から1年ずつ減らして、うるう年の数をカウント
  4. 差分日数を補正
  5. 目的の年月日を計算
  6. 目的の年月日を表示
 まとめると、以下。 # usage # gawk -f ttx.awk ttx.txt{enter} # function is_wyear(x) { # default result = 0 # judge if ( (x % 4) == 0 ) { result = 1 } else { if ( (x % 400) == 0 && (x % 100) == 0 ) { result = 1 } } return result } # function calc_md(x,y) { # copy xx = x # default mx = "3128313031303131303130" mm = 1 ; dd = 1 # local value mx0 = 0 mx1 = mx0 + substr(mx,1,2) mx2 = mx1 + substr(mx,3,2) + y mx3 = mx2 + substr(mx,5,2) mx4 = mx3 + substr(mx,7,2) mx5 = mx4 + substr(mx,9,2) mx6 = mx5 + substr(mx,11,2) mx7 = mx6 + substr(mx,13,2) mx8 = mx7 + substr(mx,15,2) mx9 = mx8 + substr(mx,17,2) mx10 = mx9 + substr(mx,19,2) mx11 = mx10 + substr(mx,21,2) # calculate area q = int(xx / 100) # Oct - Dec if ( q == 3 ) { if ( xx > mx11 ) { mm = 12 ; dd = xx - mx11 } else { mm = 10 ; dd = xx - mx9 if ( xx > mx10 ) { mm = 11 ; dd = xx - mx10 } } } # Jul - Sep if ( q == 2 ) { if ( xx > mx9 ) { mm = 10 ; dd = xx - mx9 } else { if ( xx > mx8 ) { mm = 9 ; dd = xx - mx8 } else { mm = 7 ; dd = xx - mx6 if ( xx > mx7 ) { mm = 8 ; dd = xx - mx7 } } } } # Apr - Jun if ( q == 1 ) { if ( xx > mx5 ) { mm = 6 ; dd = xx - mx5 } else { mm = 4 ; dd = xx - mx3 if ( xx > mx4 ) { mm = 5 ; dd = xx - mx4 } } } # Jan - Mar if ( q == 0 ) { if ( xx > mx3 ) { mm = 4 ; dd = xx - mx3 } else { if ( xx > mx2 ) { mm = 3 ; dd = xx - mx2 } else { mm = 1 ; dd = xx if ( xx > mx1 ) { mm = 2 ; dd = xx - mx1 } } } } # adjust (start with 1) if ( mm == 1 && dd == 0 ) { dd = dd + 1 } # concatenate result = mm * 100 + dd return result } { # calculate years and days x = $1 * 7 q = int(x / 365) r = x % 365 if ( r >= $3 ) { r = r - $3 } # show correct year month day x = $3 year = $2+2000 zz = calc_md(x,is_wyear(year)) mm = zz / 100 dd = zz % 100 printf("%s : %4d %02d %02d ",$0,year,mm,dd) # judge yy = year cnt = 0 q = int(($1 * 7)/ 365) for ( i = 0 ; i <= q ; i++ ) { # judge cnt = cnt + is_wyear(yy) # decrement yy = yy - 1 } # adjust r = r - cnt mx = 365 - r + is_wyear(yy) # show incorrect year month day zz = calc_md(mx,is_wyear(yy)) mm = zz / 100 dd = zz % 100 # show result printf("=> %4d %02d %02d\n",yy,mm,dd) }  使い方は、以下。  左に、指定の年月日を  右に、週差から求める  年月日を表示します。  つぎのTLEファイルの中から元期と日数を取得して  日付変換の関数が正しいかを調べました。 NOAA 14 1 23455U 94089A 97320.90946019 .00000140 00000-0 10191-3 0 2621 2 23455 99.0090 272.6745 0008546 223.1686 136.8816 14.11711747148495 MIDORI (ADEOS) 1 24277U 96046A 09116.47337938 -.00000023 00000-0 73445-5 0 432 2 24277 98.3597 83.2073 0002090 64.7512 295.3886 14.28595439661547 ORBCOMM FM08 [+] 1 25112U 97084A 09116.51259343 .00000203 00000-0 12112-3 0 2154 2 25112 45.0199 241.1109 0010042 194.4473 165.6089 14.34380830592834 ISS (ZARYA) 1 25544U 98067A 18132.86061566 +.00025713 +00000-0 +39219-3 0 9998 2 25544 051.6404 194.8124 0003863 060.5700 091.3717 15.54278325113026  TLEでは、2行に分けて衛星に関係するパラメータを  格納しています。1行目に元期と日数が含まれます。  フィールド4の文字列に元期と日数が、2桁と3桁になって含まれます。 97320.90946019 09116.47337938 09116.51259343 18132.86061566  元期と月日を表示するAWKスクリプトは、以下。 # function is_wyear(x) { # default result = 0 # judge if ( (x % 4) == 0 ) { result = 1 } else { if ( (x % 400) == 0 && (x % 100) == 0 ) { result = 1 } } return result } function calc_md(x,y) { # copy xx = x # default mx = "3128313031303131303130" mm = 1 ; dd = 1 # local value mx0 = 0 mx1 = mx0 + substr(mx,1,2) mx2 = mx1 + substr(mx,3,2) + y mx3 = mx2 + substr(mx,5,2) mx4 = mx3 + substr(mx,7,2) mx5 = mx4 + substr(mx,9,2) mx6 = mx5 + substr(mx,11,2) mx7 = mx6 + substr(mx,13,2) mx8 = mx7 + substr(mx,15,2) mx9 = mx8 + substr(mx,17,2) mx10 = mx9 + substr(mx,19,2) mx11 = mx10 + substr(mx,21,2) # calculate area q = int(xx / 100) # Oct - Dec if ( q == 3 ) { if ( xx > mx11 ) { mm = 12 ; dd = xx - mx11 } else { mm = 10 ; dd = xx - mx9 if ( xx > mx10 ) { mm = 11 ; dd = xx - mx10 } } } # Jul - Sep if ( q == 2 ) { if ( xx > mx9 ) { mm = 10 ; dd = xx - mx9 } else { if ( xx > mx8 ) { mm = 9 ; dd = xx - mx8 } else { mm = 7 ; dd = xx - mx6 if ( xx > mx7 ) { mm = 8 ; dd = xx - mx7 } } } } # Apr - Jun if ( q == 1 ) { if ( xx > mx5 ) { mm = 6 ; dd = xx - mx5 } else { mm = 4 ; dd = xx - mx3 if ( xx > mx4 ) { mm = 5 ; dd = xx - mx4 } } } # Jan - Mar if ( q == 0 ) { if ( xx > mx3 ) { mm = 4 ; dd = xx - mx3 } else { if ( xx > mx2 ) { mm = 3 ; dd = xx - mx2 } else { mm = 1 ; dd = xx if ( xx > mx1 ) { mm = 2 ; dd = xx - mx1 } } } } # adjust (start with 1) if ( mm == 1 && dd == 0 ) { dd = dd + 1 } # concatenate result = mm * 100 + dd return result } { if ( $1 == "1" ) { xcar = substr($4,1,5) year = substr(xcar,1,2) # adjust if ( year < 30 ) { year = year + 2000 } else { year = year + 1900 } xday = substr(xcar,3,3) # judge zz = calc_md(xday,is_wyear(year)) xm = zz / 100 xd = zz % 100 printf("year = %4d : days = %03d yyyy/mm/dd = %04d/%02d/%02d\n",year,xday,year,xm,xd) } }  テストすると、以下。

目次

inserted by FC2 system