2017-09-28 4 views
0

私は古いアプリケーションを持っています。データには、ローカライズされた形式の日付が格納されています。この文字列は表示にのみ使用されていたため、ローカライズされた形式で使用できました。 これをTDateTimeとして再利用する必要があります。シンプルなように思えました。DateToStrから文字列を取得したため、StrToDateを使用して文字列を元に戻します。だから私はそれを確認するために、小さなコンソールプログラムを書いた:StrToDateはDateToStrから取得した値を変換できません

program Project1; 

{$APPTYPE CONSOLE} 

{$R *.res} 

uses 
    System.SysUtils; 
var 
    S:String; 
    D: TDateTime; 
begin 
    S := DateToStr(Now); 
    Writeln(S); 
    D := StrToDate(S); //! throws an EConvertError 
    Readln; 
end. 

それはEConvertErrorをスロー: プロジェクトProject1.exeのは'28」というメッセージと例外クラスのEConvertErrorを上げました。 9. 2017年は有効な日付ではありません。 これは間違っていますが、上記の例外的な日付が有効です!ちょうど一瞬前にDateToStrによって生成されました。 これは完全に私には意味をなさない。 これはWindows 10のバグでしょうか?

+2

どのように失敗しますか?それはエラーを投げますか?予期しない出力がありますか? – PrestonM

+0

それは動作します。安心してください。 –

+4

[mcve] please .. –

答えて

4

OSの地域設定で短い日付形式のdd. M.yyyyと入力すると、問題を再現できます。またはdd. M. yyyyに質問で引用した正確なエラーメッセージを表示するには、書式文字列のスペースに注意してください。

理由「StrToDate」が失敗するのは、「sysutils.pas」内の関数が失敗し、Falseを返すためです。理由ScanDateが失敗するのは、デフォルトの書式設定レコードの日付区切りが間違っているためです。

RTLは、LOCALE_SDATELocaleTypeパラメータに渡され、Defaultパラメータに "/"が渡される、以下のコードで日付区切りを取得します。あなたの日付形式の場合は

... 
var 
    Buffer: array[0..1] of Char; 
begin 
    if GetLocaleInfo(Locale, LocaleType, Buffer, 2) > 0 then 
    Result := Buffer[0] else 
    Result := Default; 

は、必要なバッファは、RTLは、APIがERROR_INSUFFICIENT_BUFFERと失敗の理由に関係していない上記の関数、で失敗のみ2つの文字を提供しているので、3つの文字で既定の日付区切り文字を返します「/」のこれはDelphi RTLのエラーです。

奇妙なフォーマット文字列に有効なユースケースがある場合は、フォーマット設定パラメータを受け取るオーバーロードStrToDateを使用します。そうでない場合は、地域設定で日付文字列を修正してください。

残念ながら、最初の選択肢に汎用ソリューションを適用することはできません。

function GetDateSeparator: string; 
var 
    NumChars: Integer; 
begin 
    NumChars := GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDATE, nil, 0); 
    Win32Check(NumChars <> 0); 
    SetLength(Result, NumChars); 
    Win32Check(GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDATE, PChar(Result), NumChars) <> 0); 
    SetLength(Result, Length(Result) - 1); 
end; 

しかし、それはシャアを期待するので、あなたは、TFormatSettingsDateSeparatorに戻る'. 'を割り当てることができません:それは、あなたがこのように、例えば、で正しい日付区切り文字を取得することができます。区切り記号が'.'であり、それを使用していることがわかっていなければなりません。それは、2番目の文字が、ScanDateで取り除かれたスペースであるためにのみ機能します。

+0

私は、この奇妙なRTLの振る舞いを避ける関数を書いた: – Lubos

+0

私のソリューションを貼りたいと思ったが、コメントはおそらくこれを意図したものではないだろうか?このページはスクリーンリーダーには適していません。コメントの編集は複数行であるため、複数行のテキストを書く能力が期待されましたが、Enterを押すとコメントが保存されました。それは役に立たないが、私はそれを削除することはできません、申し訳ありません。 – Lubos

+0

@Lubos - 'VarToDateTime'(バリアント)、または' VarDateFromStr'(varutils)を直接使用してAPIを呼び出して変換を行うこともできます。 –

関連する問題