日付マジック3


--------------------- 日付マジック3 --------------------------


はじまり、はじまり~。


<解説せよ!>
10行なのに?

<お願い。>
しゃぁないな~~。
ポイントの小技をね。

<ホイ ①ダブルdim設定。から>
dimで宣言しながら変数で代入できるところを行っています。2つに分けているのは、その間に処理した変数を使う為です。

<②条件replace上書き。は?>
本来IF文で判断するところをreplaceで代用。条件が単純で文字列代入の場合のみだけどね。

<③Gettimeで日付妥当性チェック?>
面倒な計算を避けるために、比較的チェックのしやすい年月を確定してから日にちを"01"に固定する。
そこから何日後かを計算させて、その後 G_TIME_DD2 の値で確かめる。

<なるほどぉ。やるじゃない!・・・月チェックから表示まで2行ですか!>
全部で10行・・・修行が足らんね。いまいち綺麗でないし。

<あっ。 そうそう。この見かけない単なる代入の連想配列は?>
日にちをキーにしたオリジナル版。今日を基準に60日後から明日まで年月日が入る。

<で? 無駄じゃないの?>
連想配列の性質から同じキーは新しいもに上書きされる。つまり今日以前は来月の年月日なわけ。

<へっ? 代入しているだけなのに? ・・・そっかぁ!だから逆順なんだ。>
60日後から行うことで無駄も多いが、確実に01~31に値が入る。
しかもその後、HASH_EXISTS でチェックするから妙な入力はシャットアウト。

<なる~~。 その上、呼び出し一発で年月日確定=終了~ですか。エライ!>
説明はもういい?

<そういう時は、他にもあるのよねぇ?>
この質問者は、一行野郎5(日付計算)の人だ。 入力・範囲確定・出勤日計算の全てに返答するとなると・・・

<Liners流で頭爆発ね。>
これ以上は静観しとこか。

<まだあるでしょ~~~。>
ここからは、推測なんだが半年以上に渡り似たカテゴリの質問を繰返している。期間と内容ら見て会社での比較的大きな
Webシステムを頻繁に操作する立場にあり、それの自動化の為、分割して質問しているように見える。

<だから?>
何か気付かないかい?

<特には・・・でも、なんかいつもと答え方が微妙に違うよね。何処が違うのだろう?>
<あれ? 投稿したバージョンと違うのでは?>
アレは1ヵ月限定版。こっちは、チェックが多少甘いけど限定解除の行数削除優先版。

違うのは「流れ」を考慮しているからだ。
<「流れ」とは?>

今回は当然入力部ではあるが、日にちのみの入力を許す辺りから見て、かなり頻繁に入力するのだろう。
その最初の部分で一ヶ月間に限定したいのでは? そこから出勤日を算出、Webシステムに送り処理、結果を読み取って
Excelなどで解析。 生産計画・在庫調整・レポート作成などに活用するのだろう。

<なるほろ。だから投稿は、使い勝手重視の限定版なのね?>
変数も抑えて、組み込み易くしている。出勤日計算・Web操作は終了しているから。後はExcelがらみか、CSVファイル処理ぐらいかな?

<一行・再帰・置換代入・連想配列・妥当性・番兵・完全一致全文検索・・・それに、見えないけど一連の「流れ」まで考慮>
<しかも今回に至ってはチェック込みなのに7倍以上の圧縮率。一体どうなってるの?>

<質問者自身から「狐に摘まれた感じです」「望みの日にちが出るのにびっくりです。」「凄すぎます」・・・何度驚かせれば気が済むの?>
いや、そんなつもりは、ないんだが。

<・・・それにしても信じられない。その技のどれもが良く効いて光って、まるで魔法を見ているような・・・>
<はっ!!! 「日付マジック」 その名に偽りなし!>



おしまい。



-----------------------------------------------------------------------------------------------

提供は: 日付マジック = Liners でした。

-----------------------------------------------------------------------------------------------

hashtbl day
dim 納期 = replace(format(STRCONV( INPUT("納期"), SC_HALFWIDTH), 6), " ","0"), 納期日 = copy(納期, 5, 2), 仮納期年月日
for i = 60 to 1 step -1
  Gettime(i)
  day[G_TIME_DD2] = G_TIME_YY2 + G_TIME_MM2 + G_TIME_DD2
next
if day[納期日, HASH_EXISTS] then 仮納期年月日 = day[納期日] else exit
dim 納期月 = replace(copy(納期, 3, 2), "00", copy(仮納期年月日, 3, 2)), 納期年 = replace(copy(納期, 1, 2), "00", copy(仮納期年月日, 1, 2)), 納期年月日 = 納期年 + 納期月 + 納期日
if (val(納期月) < 1) or (val(納期月) > 12) then exit else gettime(val(納期日)-1, "20" + 納期年 + 納期月 + "01")
if G_TIME_DD2 = 納期日 then msgbox("納期年月日 : " + 納期年月日) else msgbox("日付が存在しません")

-----------------------------------------------------------------------------------------------
    次の日にちを算出 sen    
    日にちだけでも月日でも納期をキチンと入力させたくて、下記の様なのを考えてみました。「15」と入力すると、今日から後なので当然「110515」と入力させたいのですが、長々となりました。もう少しスマートなのはないでしょうか?

Gettime()
今日 = G_TIME_YY2 + G_TIME_MM2 + G_TIME_DD2
今日年 = G_TIME_YY2
今日月 = G_TIME_MM2
今日日 = G_TIME_DD2
納期年 = 0
納期月 = 0
納期日 = 0
納期 = INPUT("納期")
納期 = STRCONV( 納期,SC_HALFWIDTH)// 半角文字
ifb length(納期) = 1 then //日にちだけ入力
納期日 = "0"+ 納期
for i=1 to 60
Gettime(i)
ifb 納期日 = G_TIME_DD2 then
納期月 = G_TIME_MM2
納期年 = G_TIME_YY2
Sleep(0.1)
break
endif
next
納期年月日 = 納期年 + 納期月 + 納期日
elseif length(納期) = 2 then
納期日 = copy(納期,1,2)
for i=1 to 60
Gettime(i)
ifb 納期日 = G_TIME_DD2 then
納期月 = G_TIME_MM2
納期年 = G_TIME_YY2
Sleep(0.1)
break
endif
next
納期年月日 = 納期年 + 納期月 + 納期日
elseif length(納期) = 3 then
納期月 = "0"+ copy(納期,1,1)
納期日 = copy(納期,2,2)
for i=1 to 60
Gettime(i)
ifb 納期日 = G_TIME_DD2 then
納期年 = G_TIME_YY2
Sleep(0.1)
break
endif
next
納期年月日 = 納期年 + 納期月 + 納期日
elseif length(納期) = 4 then
納期月 = copy(納期,1,2)
納期日 = copy(納期,3,2)
for i=1 to 60
Gettime(i)
ifb 納期日 = G_TIME_DD2 then
納期年 = G_TIME_YY2
Sleep(0.1)
break
endif
next
納期年月日 = 納期年 + 納期月 + 納期日
elseif length(納期) = 5 then
納期年 = "0"+ copy(納期,1,1)
納期月 = copy(納期,2,2)
納期日 = copy(納期,4,2)
納期年月日 = 納期年 + 納期月 + 納期日
elseif length(納期) = 6 then
納期年 = copy(納期,1,2)
納期月 = copy(納期,3,2)
納期日 = copy(納期,5,2)
納期年月日 = 納期年 + 納期月 + 納期日
endif

PRINT "納期年月日"+納期年月日
DATE:2011/5/7(Sat) 01:46 No.3614    
   
    RE:次の日にちを算出 Liners    
   
    へえ~・・・こんな考え方もあるんだ。向こう60日を先読みして日付を補完するのか。・・・現場ならでの発想?でも入力チェックは厳しい方がよいのでは?
無駄な変数や、同じ場所をまとめて短くすることは出来るが、コレは大きなIF文ブロックであり、構造ごと考え直した方が得策かと思います。

とりあえず、 納期 = replace(format(STRCONV( INPUT("納期"), SC_HALFWIDTH), 6), " ","0") で0付の6桁として2桁づつ分割。
各 日、月、年ごとに処理すれば、行数は半減します。

しかし、私としてはやはり、入力チェックを厳しくして行数が増えても、せめて "45","1302","231" は、はねてもらいたい。
DATE:2011/5/7(Sat) 13:50    
   
    RE:次の日にちを算出 sen    
   
    ありがとうございました。
ご指導賜った点を検討して、下記の様に書き換えてみました。
合ってますでしょうか?

Gettime()
今日年 = G_TIME_YY2
今日月 = G_TIME_MM2
今日日 = G_TIME_DD2
Gettime(30)
翌月 = G_TIME_MM2
Gettime(365)
翌年 = G_TIME_YY2
納期年月日 = 0
納期年 = 0
納期月 = 0
納期日 = 0
repeat
正解 = 0
納期 = replace(format(strconv(input("納期"), sc_halfwidth), 6), " ","0")
納期年 = copy(納期,1,2)
納期月 = copy(納期,3,2)
納期日 = copy(納期,5,2)
ifb val(納期日) <= 31
正解 = 正解 + 1
else
msgbox("1 間違った日にちを入力していませんか?")
endif
ifb val(納期月) <= 12
正解 = 正解 + 1
else
msgbox("2 間違った月を入力していませんか?")
endif
ifb val(納期年) = val(今日年) or val(納期年) = val(翌年) or val(納期年) = 0 then
正解 = 正解 + 1
else
msgbox("3 間違った年を入力していませんか?")
endif
ifb val(納期月) = val(今日月) or val(納期月) = val(翌月) or val(納期月) = 0 then
正解 = 正解 + 1
else
msgbox("4 先過ぎる月を入力していませんか?")
endif
for i=1 to 32
Gettime(i)
ifb 納期日 = G_TIME_DD2 then
納期月 = G_TIME_MM2
納期年 = G_TIME_YY2
納期年月日 = 納期年 + 納期月 + 納期日
Sleep(0.1)
break
endif
next
print "正解"+正解
until 正解 = 4
print "納期年月日"+納期年月日
DATE:2011/5/8(Sun) 16:48    
   
    RE:次の日にちを算出 Liners    
   
    残念ながらOKは出せません。確かに"1302" は通りませんが、この意味は、日付の妥当性をチェックしてほしという意味です。つまり、"1202" は "111202"として通るという意味なのです。
また、"0630"は、警告も出ず、強制的に"110530" とされてしまいます。入力範囲を明確にすべきです。

もし、入力範囲が1ヵ月以内で良いのなら、全数チェックを掛ける方が良いでしょう。連想配列を使うとさらに簡単になります。
当方でも、1ヵ月以内&連想配列版に若干の制限を掛けたものを試しますが、スマートさ=行数と変数の削減 で良いですか? (目的が「スマートさ」なので)
DATE:2011/5/8(Sun) 20:54    
   
    RE:次の日にちを算出 free    
   
    暇だったので作ってみました。間違っていたらすいません。

GETTIME()
DIM 月の日数[13]=0,31,28,31,30,31,30,31,31,30,31,30,31
今年 = VAL(G_TIME_YY2)
今月 = VAL(G_TIME_MM2)
今日 = VAL(G_TIME_DD2)
IFB VAL(G_TIME_MM2)<>12 THEN
翌月 = VAL(G_TIME_MM2)+1
ELSE
翌月 = 1
ENDIF
翌年 = VAL(G_TIME_YY2)+1
納期年 = 0
納期月 = 0
納期日 = 0
納期 = REPLACE(FORMAT(STRCONV(INPUT("納期"), SC_HALFWIDTH), 6), " ","0")
納期年 = VAL(COPY(納期,1,2))
納期月 = VAL(COPY(納期,3,2))
納期日 = VAL(COPY(納期,5,2))

IFB 納期月=0 AND 納期日 >= 今日 THEN
納期月=今月
ELSEIF 納期月=0 AND 納期日 < 今日 THEN
納期月=翌月
ENDIF

IFB 納期年=0 AND 納期月=翌月 AND 翌月=1 THEN
納期年=翌年
ELSE
納期年=今年
ENDIF

IFB 納期日 > 月の日数[納期月] OR 納期月 > 12 THEN
MSGBOX("入力が間違っていませんか?")
EXITEXIT
ENDIF
PRINT "納期年月日:"+REPLACE(FORMAT(納期年,2)+FORMAT(納期月,2)+FORMAT(納期日,2), " ","0")
DATE:2011/5/8(Sun) 23:36    
   
    RE:次の日にちを算出 sen    
   
    はい。お願いします。
DATE:2011/5/8(Sun) 23:53    
   
    RE:次の日にちを算出 sen    
   
    おー。これが、憧れの連想配列ですね。
勉強になります。
ありがとうございました。
DATE:2011/5/9(Mon) 00:24    
   
    RE:次の日にちを算出 Liners    
   
    下記は、連想配列版のサンプル。入力範囲は翌月の同日まで、範囲外は再入力。終了は0入力。
う~ん。使い易さと読み易さのバランスで、行数削減はこのくらいで止めておこう。

入力チェックも完璧ではないが、まあ何とか使えるでしょう。
連想配列は、納期日をキーに納期を向こう1ヶ月先から前日まで逆順に格納。こうすることで、上書きされ直近が優先となる。
また、Gettimeで生成された納期を1ヶ月間全て格納するのでこの間は、翌月、翌年、うるう年など日付の妥当性を考えなくて済む。

hashtbl day
repeat
  納期 = replace(format(strconv(input("納期(1ヶ月以内 終了=0)"), sc_halfwidth), 6), " ","0")
  if 納期 = "000000" then exitexit else 納期日 = copy(納期,5,2)
  day = HASH_REMOVEALL
  for i = 32 to 1 step -1
    Gettime(i)
    day[G_TIME_DD2] = G_TIME_YY2 + G_TIME_MM2 + G_TIME_DD2
  next
  if day[納期日, HASH_EXISTS] then 仮納期 = day[納期日] else continue
  納期 = replace(copy(納期, 1, 2), "00", copy(仮納期, 1, 2)) + replace(copy(納期, 3, 2), "00", copy(仮納期, 3, 2)) + 納期日
until 納期 = 仮納期
msgbox("納期年月日 " + 納期)
DATE:2011/5/9(Mon) 05:07    
   
    RE:次の日にちを算出 sen    
   
    失礼しました。これが連想配列ですね。
それにしても、チェックなしで70行が、チェックありで13行になってしまうとは、凄すぎます。
勉強になります。
ありがとうございました。
DATE:2011/5/10(Tue) 00:12