日付時間関数の形式相違によるエラー回避方法

解決


サンデープログラマー  2006-05-25 05:06:36  No: 21785

大変お世話になっています。WinXP+Delphi6  パーソナルで始めたばかりの者ですがよろしくお願いします。

日付の表示形式がPCの設定に適合しないと「日付または時刻ではありません」とのエラーが出ます。使用PCは各国のロケールが特定されておらず、また処理するファイルにある日付データの形式もバラバラという環境のもとでそれぞれの日付時刻をsecondspanなどで処理したいのですがデータの形式によって上手く動いたりエラーが出たりで困っています。

使用するPCの設定が同一であればソフトで文字を入れ替えるなどの処理も考えましたがPCが同一でない、ということで行き詰ってしまいました。何か方法があったら教えてください。


igy  2006-05-25 05:31:52  No: 21786

具体的には、何をしたときに
>「日付または時刻ではありません」と
出ますか?


  2006-05-25 10:22:26  No: 21787

>secondspan
って知らないんですが、秒数の差分か何かですよね。(D5には無い)
パラメータを指定するには、TDateTimeにしないと
いけないようなので、TDateTimeにさえ変換できれば
問題なさそうに思えます。

極端な話、PC側のロケールが 
1776/7/4 00:00:00で
ファイルに記録されているものが 
July,4 1776 00:00:00
1776年 7月 4日 0時 0分 0秒
だったりするわけですよね?

これらTDateTimeに変換するには、どうすればいいか
っていう話?


サンデープログラマー  2006-05-25 18:53:22  No: 21788

む様、早速ありがとうございます。
具体的な質問でなかったようなのでコードを書かせていただきます。

procedure TForm1.Button2Click(Sender: TObject);
var
str:string;
d:tdatetime;

begin

str:='03-APR-05 01:33:09';         // 1--駄目
str:='03/05/2005 01:33:09';        // 2--駄目
str:='05/05/03 01:33:09';          // 3--OK
str:='2005/05/03 01:33:09';        // 4--OK
str:=July,4 1776 01:33:09';        // 5--駄目

d:=strtodatetime(str);
edit1.Text:=datetimetostr(d);

end;

上記の「駄目」で結果を書かせようとすると「日付または時刻ではありません」というエラーが出てしまいます。不特定のPCで作成された日付時刻が入ったデータを不特定な他の使用者がそのデータを使って処理するというものです。どのような日付形式のデータでもエラーとならないように処理できるようにしたいというのが質問の内容です。よろしくお願いします。

ちなみにSecondSpanは次のようにして使っています。(これを作ったときはまだRound関数など知りませんでしたので--失笑--  Delphiでは時間差を
求めても差が正か負か判定できない?のには驚きつつCompareDatetimeで補っていますがスマートなやり方はあるのでしょうか?)

procedure Jikansa(TT1:tdatetime; TT2:tdatetime);

        var
                kstr:string;

        begin

               kstr:=floattostr(int(secondSpan(Tt2,Tt1)+0.5));
               tdiff:=strtoint(kstr);    //グローバル

               if comparedatetime(Tt2,Tt1)<0 then tdiff:=-tdiff;

        end;


igy  2006-05-25 19:30:22  No: 21789

>不特定のPCで作成された日付時刻が入ったデータ

を出力するプログラムを サンデープログラマー さんが作る場合、

出力するほうのデータを

procedure TForm1.FormCreate(Sender: TObject);
var
    Year, Month, Day, Hour, Min, Sec, MSec: Word;
begin
    // 現在の日付・時間を取得
    DecodeDate(Now, Year, Month, Day);
    DecodeTime(Now, Hour, Min, Sec, MSec);
    
    Label1.Caption := Format('%.4d/%.2d/%.2d %.2d:%.2d:%.2d', [Year, Month, Day, Hour, Min, Sec]);
end;

のように、

>str:='2005/05/03 01:33:09';        // 4--OK

の形式で統一して、出力させるようにすることはダメですか?


HOta  2006-05-25 20:34:10  No: 21790

それぞれのPCのShortDateFormatによって変換しますので、
バラバラの場合は、それぞれ別にTDate型に直さないとだめでしょう。

igyさんの様に、出力形式を統一すれば簡単になります。


Basser  2006-05-25 20:36:52  No: 21791

エラーは発生しませんが、変換結果がどうでしょうか?

procedure TForm1.Button1Click(Sender: TObject);
const
  DateStrings: array[0..4] of String = (
    '03-APR-05 01:33:09',
    '03/05/2005 01:33:09',
    '05/05/03 01:33:09',
    '2005/05/03 01:33:09',
    'July,4 1776 01:33:09'
  );
var
  I: Integer;
  V: Variant;
begin
  Memo1.Lines.Clear;
  for I:= Low(DateStrings) to High(DateStrings) do
  begin
    V:= DateStrings[I];
    V:= VarAsType(V, varDate);
    Memo1.Lines.Add(DateTimeToStr(V));
  end;
end;


サンデープログラマー  2006-05-25 21:36:22  No: 21792

igy様,HOta様,Bassar様、大変貴重なアドバイスをありがとうございました。既にデータが出来上がっていますので出力データの統一は今後の課題として読み方の方法で対処するBassar様の技で試しましたところ見事全部通りました。こんなに簡単に解決するとは思ってもみませんで大感謝です。

現在は理屈も分からずに結果オーライですが考え方としては「一度バリアントにするとPC内部でシステム時間で解釈され、それを各PC固有に設定されたLocaleInfoに従った形式で出力して表示される」と解釈して宜しいでしょうか?  とにかくVB時代から解決していなかった問題が氷解して大進歩しました。あらためてお礼を申し上げます。コードは下記の通りです。(今後のニューカマーのご参考まで)

procedure TForm1.Button2Click(Sender: TObject);
var
str:string;
d:tdatetime;
v:variant;
begin
str:='03/05/2005 01:33:09';        // 駄目==>>通りました
str:='05/05/03 01:33:09';          // OK
str:='2005/05/03 01:33:09';        // OK
str:='JULY,4 1776 01:33:09';        // 駄目==>>通りました
str:='03-APR-05 01:33:09';         // 駄目==>>通りました

v:=str;
d:= VarAsType(V, varDate);
edit1.Text:=datetimetostr(d);
end;


気づいたこと  2006-05-25 22:22:18  No: 21793

インデントの無いソースは、間違いの元。

あと、
>不特定のPCで作成された日付時刻が入ったデータを
>不特定な他の使用者がそのデータを使って処理するというものです

団体職員等で商用/業務だとまずいと思います。
この辺は問題ないのでしょうか?

# 公務員の業務は「商用」なのか?


Basser  2006-05-25 23:06:18  No: 21794

>    V:= VarAsType(V, varDate);

が行う処理は日付時刻値への変換迄です。

>PC固有に設定されたLocaleInfoに従った形式で出力して表示

この処理を行っているのは DateTimeToStr です。
※SysUtilsユニット ShortDateFormat変数の初期値は
  GetLocaleInfo API を使って読み込まれる


サンデープログラマー  2006-05-27 02:14:19  No: 21795

Basser様、ありがとうございます。結果オーライではありますがお時間があれば教えてください。
>>   V:= VarAsType(V, varDate);
>>   が行う処理は日付時刻値への変換迄です。

各種のフォーマットで日付が与えられても変数Vには世界中の(Windows)PCで同じ値が代入されると考えましたが宜しいでしょうか?この値が夫々のPCの設定によりモニターに現れる、と理解しましたが。こう理解するとかなり日付関係の扱いが分かった気になりますが。
------------------------------------------------
気付いたこと  様

Delphiのエディターでの書き方は皆様いろいろの様子で当方もまだ定番は決めていませんがやはりインデントがあると分かりやすいと思います。大文字小文字などはエディターで自動的に変換してくれると間違いがなくなると思いますがこれがないのは残念です。

>>団体職員等で商用/業務だとまずいと思います。
ライセンスの問題でしょうか?  現在実用で使っているのはVBで作ったものですがDolphiでモノになりそうになったらDelphiに切り替えようと思っています。その時は職場にもありますが自分でも買いたいと思います。


識別子  2006-05-27 02:22:46  No: 21796

>大文字小文字などはエディターで自動的に変換してくれると間違いがなくなると思いますがこれがないのは残念です。

Delphi は、識別子の大文字小文字は関係ないですね。Basic と同じ系統。
ゆえに、その機能が付けられる可能性はまずなさそうですね。


Basser  2006-05-27 02:48:38  No: 21797

私も理解していません(;^^)

VarAsType は内部で VariantChangeTypeEx というAPI を呼び出しています。
このAPIは指定された ロケールID で数値や日付を正しく解析すると説明されてます。
下記を参照してみて下さい。

http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/jpdnguion/htm/drgui032999.asp


サンデープログラマー  2006-05-27 21:26:27  No: 21798

Basser様:VarAsTypeというものからVariantChangeEXなるAPIを呼び出しているとのこと、了解しました。これはVCLのソースというものを見ればわかるのでしょうか?  (これがパーソナルとの差でしょうか)理屈はともあれ大変便利な関数が活用できて大変満足しています。

----------------------------------------------------
識別子様:現在Delphiではコメント行の色分け、If Then Else、Begin  End;  String  などが太字で出るようですがDelphiでもVBのようにVarで宣言した変数。予約語などが自動的にクローズアップされて大文字小文字に変わったりすると自信を持って入力できますのでやってもらえるとありがたいと思いました。でもやりそうもないですね?


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加