首页 > 解决方案 > 为什么 TFDBatchMove 为值为“03/11/2019”的日期字段引发异常 ELocalTimeInvalid?

问题描述

我在 Windows 7 SP1 机器上使用 Delphi 10.3 Rio Update 1。

我的程序的目的是将 aTFDMemtable转换为 JSON 格式。由于我无法理解的原因,当 this 的 date 字段TFDMemTable具有 value'03/11/2019'时,使用 DisplayFormat"day/month/year"会引发异常:

Project ProjMemtabJSON.exe 引发异常类 ELocalTimeInvalid 并显示消息“给定的“03/11/2019”当地时间无效(位于 DST 之前的缺失时段内)。

任何其他日期都可以"Nov, 3rd 2019"正常工作。

我不知道这里发生了什么!

program ProjMemtabJSON;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  System.Classes,
  System.JSON,
  FireDAC.Comp.DataSet,
  FireDAC.Comp.Client,
  FireDAC.Comp.BatchMove,
  FireDAC.Comp.BatchMove.DataSet,
  FireDAC.Comp.BatchMove.JSON,
  Data.DB;

Var
  Fmemtable   : TFDmemtable ;
  FJSONArray  : TJSONArray;
  FDBatchMoveJSONWriter1     : TFDBatchMoveJSONWriter;
  FDBatchMoveDataSetReader1  : TFDBatchMoveDataSetReader;
  FDBatchMove1               : TFDBatchMove;

procedure  CreateMemtable;
begin
  Fmemtable := TFDmemtable.Create(nil);
  FMemTable.FieldDefs.Add('ID', ftInteger, 0, False);
  FMemTable.FieldDefs.Add('Name', ftString, 20, False);
  FMemTable.FieldDefs.Add('Status', ftString, 20, False);
  FMemTable.FieldDefs.Add('Duedate', ftdatetime,0, False);
  FMemTable.CreateDataSet;
end;

procedure FillMemtable;
begin
  FMemtable.Append;
  FMemtable.Fields[0].Value := 10;                           // ID
  FMemtable.Fields[1].Value := 'John';                       // Name
  FMemtable.Fields[2].Value := 'Active';                    // Status
  { ==> HERE IS THE PROBLEM :  change this date to 03/11/2019  i.e.  03/Nov/2019 and an error will raise }
  FMemtable.Fields[3].Value := StrToDate('02/11/2019');     // Due date dd/mm/yyyy
end;

procedure PrintMemtable;
begin
  writeln('ID       : ' ,Fmemtable.Fields[0].AsString);
  writeln('Name     : ' ,Fmemtable.Fields[1].AsString);
  writeln('Status   : ' ,Fmemtable.Fields[2].AsString);
  writeln('Due Date : ' ,Fmemtable.Fields[3].AsString);
end;

function TableToJson : TJSONArray;
begin
  Result := TJSONArray.Create;
  try
    FDBatchMoveDataSetReader1 := TFDBatchMoveDataSetReader.Create(nil);
    FDBatchMoveJSONWriter1    := TFDBatchMoveJSONWriter.Create(nil);
    FDBatchMove1              := TFDBatchMove.Create(nil);

    FDBatchMove1.Reader       := FDBatchMoveDataSetReader1 ;
    FDBatchMove1.Writer       := FDBatchMoveJSONWriter1;

    try
      if not FMemtable.Active then
        FMemtable.Active := True;
      FDBatchMoveDataSetReader1.DataSet := FMemtable;
      FDBatchMoveJSONWriter1.JsonArray  := Result;
      FDBatchMove1.Execute;
    except
      on E: Exception do
        raise Exception.Create('Error Message: ' + E.Message);
    end;
  finally
    FDBatchMoveDataSetReader1.Free;
    FDBatchMoveJSONWriter1.Free;
    FDBatchMove1.Free;
  end;
end;

begin
  try
    { TODO -oUser -cConsole Main : Insert code here }

    Creatememtable;
    FillMemtable;
    PrintMemtable;

    FJSONArray   := TableToJSON;

    readln;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

标签: jsondelphi

解决方案


有一个System.DateUtils例程可以检查无效时间:

TTimeZone.IsInvalidTime(const ADateTime : TDateTime) : Boolean;

如果您添加DateUtils到您的Uses子句,则将您的 FillMemTable 更新为:

procedure FillMemtable;   
var  MyDate : tDateTime;
begin
  FMemtable.Append;
  FMemtable.Fields[0].Value := 10;                           // ID
  FMemtable.Fields[1].Value := 'John';                       // Name
  FMemtable.Fields[2].Value := 'Active';                    // Status
  { ==> HERE IS THE PROBLEM :  change this date to 03/11/2019  i.e.  03/Nov/2019 and     an error will raise }
  MyDate := StrToDate('03/11/2019');
  if TTimeZone.local.IsInvalidTime(MyDate) then MyDate := MyDate + 0.5; //noon won't be invalid
  FMemtable.Fields[3].Value := MyDate;     // Due date dd/mm/yyyy
end;

或者,如评论中所述,如果您不希望 IF 语句的开销,只需强制所有日期为中午。

我从来没有意识到有时区在午夜切换到/从 DST。不幸的是,如何定义日期(没有时间)。


推荐阅读