一括表示

− 野ざらし言 −

[3630] UNIXTIMEをJSTに変換

めざら 2010/03/16(Tue) 23:24
http://homepage3.nifty.com/mezala/
 この2週間を費やして,結局昔作ったマクロの部品を流用するしか
解決方法が見つかりませんでした。タイトルで探せなくなるので,
新規発言にします。

----^ UNIXTIME.DEF ( date:2010-03-15 time:00:22 ) ----< cut here
= unixtime.def v0.22 =
#if 0
UNIXtimeをローカル時刻(1970/01/01:09:00:00以降)に変換
数字列の任意の位置にカーソルを置いて起動(前後に英字と_不可)
#endif
* mad for vz!
1 ^^ "" ?.
        (cd>47 && cd<58)?{ #d #a }?.    ;(cd>='0' && cd<='9')?
        u[, p[, q[, l[, i[, o[,         ;push var
        &s &> o4+q4+p16+u0=r,           ;b<u>f, <p><q><o>

        ; ---- get str ----
        mp[, ps[=u, #G ps], mp],        ;UNIXtime 前後に英字不可
        &Sn(u) l=r, i-,                 ;<l>ength <i>:counter
        (l<3)?>s                        ;2桁以下は数値化をスキップ

        ; ---- str to val ----
        ;32bitに納めるために末尾の2桁は別途取得
        &Im(p,0) &Im(q,0)               ;reset <p><q>
        &Ia(p,u.0-$30)                  ;先頭1桁を事前セット
        (l>3)?{                         ;4桁以上で数値化
                (l-3){
                        &Im(p,10) i++,
                        &Ia(p,u.i-$30)
                }
        }

        ; ---- local time ----
 :s     &Ia(p,324)                      ;地域標準時との差+09:00を足す
        &Id(p,864)                      ;1970/01/01からの経過日数確定
        &Ia(q,r) &Im(q,100)             ;残りを秒に
        r=10*(u.(i+1)-$30)+u.(i+2)-$30, ;末尾2桁をrに取得
        &Ia(q,r)                        ;1日以下の秒確定
        o..0=$FA6D, o..1=$A,            ;[$AFA6D](719469)をセット
        &La(p,o)                        ;基準日定数を加算

        ; ---- hour,min,sec ----
        (2){ &Id(q,60) r[, }            ;順に余りを保存
        o..3=q..0,                      ;時
        o..4=0],                        ;分
        o..5=0],                        ;秒

        ; ---- days to date ---- (前日までの経過日数+1)
        ;閏年対応のため0000年3月0日を仮想基準日とする
        y[, x[, m[,
;       &Le(q,p)                        ;set q
        &Im(p,4) &Is(p,1)               ;割切れ抑止
        &Id(p,1461) y=p..0, x=r/4,      ;365.25で割る(x:日数)
        x+=y/100-y/400,                 ;閏年調整を再現
        (x>364)?{                       ;満ちたら繰り上げる
                y++,
                x-=365+(y%4==0 && (y%100!=0 || y%400==0)),
        }
        (x<0)?{ y-=1, x+=366, }         ;減ることはないはずだが
        m=(x*10+5)/306,                 ;m:[0-11]
        (m>9)?{                         ;月確定[0-11]->[4-12,1-2]
                y+=1, o..1=m-9,         ;10-11は翌年の1-2
        }?{
                o..1=m+3,               ;0-9は3-12
        }
        o..2=1+x-m*30+(m*6+5)/10,       ;日確定
        o..0=y,                         ;年確定
        m], x], y],

        ; ---- output ----
        &m("%02d %3s %d:%02d:%02d:%02d",
        o..2,
        "JanFebMarAprMayJunJulAugSepOctNovDec"+o..1*3-3,
        o..0,o..3,o..4,o..5)
;       &m("%4d/%02d/%02d: %02d:%02d:%02d",o..0,o..1,o..2,o..3,o..4,o..5)

 :z     ; ---- exit ----
        o], i], l], q], p], u],         ;pop var
        &d #] .

00:     ; ---- str buf[16] / long int buf *2 / y-m-d_h:m:s ----
        (5+$).
        "$(10,0)$[16]$[20]"
        ;       u    p q o
*
[Variables]
        u       str buf ptr
        p,q     long int buf ptr
        l       str length
        i       counter
        o       "0123456789AB"
                ;年月日時分秒 output用
        y,m,x   作業用(年月日)
[Buffers]
        u       [2][16] as ps
        p,q     [4]*2   long int
        o       [2]*6   年月日時分秒
[History]
2010/02/27 0.01 暫定版(各年初期値を持つ構造が恥ずかしいので却下)
2010/02/28 0.10 初版
2010/03/01 0.11 バッファの指定式が不正で暴走するのを修正,変数の整理
2010/03/02 0.12 バッファの指定を整理
--------------- 標準時差の設定を間違える根本的な誤りにより一から見直し
2010/03/14 0.20 1978/03/00を仮想基準日として閏年関係のずれを回避
2010/03/14 0.21 3桁以下のUTが変換できなかったのを修正
2010/03/15 0.22 閏年関係のずれを克服できず0000/03/00を仮想基準日に
[Notes]
何故か合わないので悩むこと数時間,仮想基準日を03/00でなく03/01にしていた。
さらに合わないので悩み,世界標準時との時間差に気付く。
変数の保存や内容など清書し,セーブせずに大きな数値上で実行したら暴走した。
複数バッファ指定の式が不正で,オフセット0をバッファにして書込みしていた。
そして修正したと思ったら毎年末に合わないことが判明し,悩み続けること1週間。
ようやく,根本的な誤り(+9:00でなく-15:00にして1日調整していた)が判明。
閏年がずれるので1968年を仮想基準日としたが,それでも割切れ繰り上がる。
結局,0000/03/00を仮想基準日にする定数を導入。
----$ UNIXTIME.DEF ( lines:110 ) ---------------------< cut here

 やれやれ。

[3631] 日時からUNIXTIMEに変換

めざら 2010/03/16(Tue) 23:28
[3630]へのコメント http://homepage3.nifty.com/mezala/
 続きです。こちらはしっかり32ビットの壁があります。


----^ DATE2UT.DEF ( date:2010-03-16 time:00:10 ) -----< cut here
= Date2UT.def v0.10 = by H_ear
#if 0
日時をUNIXTIMEに変換
※要高橋版VZ[以降]
32bitの範囲のため上限が2038年程度
但しoverflowを!で告知するため,表示された数値+4294967296と推定可能
#endif
* mad for vz!
1 ^\ "" ?.
        i[, p[, q[, o[, y[, m[, d[, l[,

        ; ---- 日付の取得 ----
 :g     &m("日時を【YYYY/MM/DD/HH:MM:SS】の形式で入力.(年必須)")
        &g("YYYY/MM/DD/HH:MM:SS") &Cr
        (r|1+1)??{                      ;[ESC]/[CR]のみ
        :c      &m("! Canceled") >z
        }

        ; ---- バッファの確保と初期化 ----
        &> q4+p12+o0=r,                 ;<o><p><q> buffers
        i-, (5){ &Im(o+i,0) i+=4, }     ;<i> counter

        ; ---- 数字列を数値化 ----
        i-, #J #e #<                    ;pw dummy text winow
 :l     (cd<'0' || cd>'9')?>v           ;数字なら取得
        &n o..i=r,
        i++, #f                         ;要するに/や:でなくても可
        (i<6)?>l                        ;6回まで取得
 :v     (s)?#[                          ;close #J window

        ; ---- 不正な年月日をチェック ----
        (o..0<1970)?{
                &a("年が不正です.再入力します")
                (r>0)?>g >c
        }
        (o..1<1 || o..1>12)?o..1=1,     ;月
        (o..2<1 || o..2>31)?o..2=1,     ;日
        y[=o..0, &01 y],                ;日の整合性チェック
        (o..2>r.o..1)?o..2=r.o..1,      ;超えていれば最大値
        (o..0==1970 && o..1==1 && o..2==1 && o..3<9)?{
                &a("1970/01/01/09:00:00以降のみ. 再入力します")
                (r>0)?>g >z
        }
;       &m("%d/%02d/%02d/%02d:%02d:%02d",o..0,o..1,o..2,o..3,o..4,o..5)

        ; ---- 日数算出 ----
        ; 0000/03/00を基準とする日数を算出
        ; 1月と2月を前年の13月と14月として扱い3月から1年を開始
        ; 月平均日数定数30.6を使用
        ; --> *p = 総日数
        y[=o..0, m[=o..1, d[=o..2,
        &Im(p,0)                        ;reset p
        (m<3)?{ y--, m+=9, }?{ m-=3, }  ;仮年月を設定
        &Ia(p,y) &Im(p,365)             ;年数分の日数
        &Ia(p,m*30+(m*6+5)/10+d)        ;月平均日数と日を足す
        &Ia(p,y/4)                      ;閏年を足す
        &Is(p,y/100)                    ;百年非閏年を引く
        &Ia(p,y/400)                    ;四百年閏年を足す
        d], m], y],

        ; ---- 1970/01/01以降の日数にして標準時差を調整 ----
        ; 1970/01/01以降の日数を確定(非汎用定数を使用)
        ; 1日の秒数86400,標準時差9時間分の秒数32400
        ; いずれも100未満の端数がないうちに処理を済ませる
        ; <-- *p = 基準日からの総日数
        ;     *q = 定数(基準日から1970/01/01未満の日数)
        ;     *p -= *q : 1970/01/01以降の日数
        ; --> *p = 日数分の秒数の100分の1
        q..1=$A, q..0=$FA6D,            ;719469/65536=10_64109 1970/01/01〜
        &Ls(p,q)                        ;定数(0000〜1969)を引く
        &Im(p,864)                      ;p*86400 :日数分の秒数/100
        &Is(p,324)                      ;地域標準時の差/100を引く

        ; ---- 日数から秒数へ ----
        ; overflowを予測して超過するならフラグを立てる
        ; *pと定数$28F5C28($FFFFFFFF/100)を比較し
        ; *pが小さい:オーバーフロウしない
        ; *pが大きい:オーバーフロウする -> largeフラグを立てる
        q..1=$28F, q..0=$5C28,          ;定数 $28F5C28 * 100 < $FFFFFFFF
        &Lc(q,p)                        ;long比較(※高橋版以降のみ)
        l=r<0,                          ;<l> too large(32bit)フラグ
        &Im(p,100)                      ;フラグが立っていると丸められる

        ; ---- 時刻を秒数に ----
        ; 時刻の入力は必須ではないので入力なくば処理省略
        ; --> *q = 時刻の秒数
        (i<4)?>p                        ;時刻を入力していないなら出力
        &Im(q,0)
        &Ia(q,o..3) &Im(q,60)           ;時->分
        &Ia(q,o..4) &Im(q,60)           ;分->秒
        &Ia(q,o..5)                     ;秒

        ; ---- 合計 ----
        ; 日数分の秒数に時刻分の秒数を加算
        ; 加算した値よりも小さくなればoverflowと判断できる
        ; overflowしたらフラグを立てる
        &La(p,q)                        ;時刻分の秒数を足す
        &Lc(p,q) l=r<0,                 ;足した値よりも少なければoverflow

        ; ---- print [flag] *p o..0〜o..5 ----
        ;overflowがあれば数値に'!'を前置して示す
 :p     &m("%c %lu <- %d/%02d/%02d/%02d:%02d:%02d",' '+l,p..0,p..1,o..0,o..1,o..2,o..3,o..4,o..5)

 :z     ; ---- exit ----
        l], d], m], y], o], q], p], i],
        &d #] .

00:     ; ---- buffer ----
        (3+$)."$[20]"

01:     ; ---- 日の整合性確認 ----      ;from calendar.def
        r=" $(1f,1c,1f,1e,1f,1e,1f,1f,1e,1f,1e,1f,)",
;              1__2__3__4__5__6__7__8__9__a__b__c
        (y%4==0 && (y%100!=0 || y%400==0))?r.2=29, ?r.2=28,     ;閏年
        (r)
*

[Variables]
        i       counter
        p,q     long int ptr
        o       buf word*6 (output)
        y,m,d   作業用年月日
        l       large flag
[Buffers]
        pw      #g/#J 日付入力/取得
        p,q     [8]double*2
        o       [12]word*6
[History]
2010/03/16 0.10 初版
[Notes]
結局,仮想基準日0000/03/00を使った。
----$ DATE2UT.DEF ( lines:131 ) ----------------------< cut here

↑ このページの先頭