目次
前
次
年月日補正(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で割った商が月、余りが日になるように
してあります。これで関数が返す値をひとつ
にできます。
テキストファイルには、フィールドごとに
次のパラメータを設定。
- 1st 週の差分値
- 2nd 西暦年の4桁中の下2桁
- 3rd 1月1日からの経過日数
この仕様で、次のようにテキストファイルの
内容を与えます。
1024 18 132
テキストファイルの内容を読み込んでから
結果を出力するまでのシーケンスを、次の
ように決定。
- 入力パラメータから差分となる年と日数計算
- 現在の年月日を表示
- 現在の年月日から1年ずつ減らして、うるう年の数をカウント
- 差分日数を補正
- 目的の年月日を計算
- 目的の年月日を表示
まとめると、以下。
# 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)
}
}
テストすると、以下。
目次
前
次