Delphi XE2 FormatDateTime传递-693594 [英] Delphi XE2 FormatDateTime passing -693594

查看:281
本文介绍了Delphi XE2 FormatDateTime传递-693594的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们在这里有一个问题。我们从Delphi 2006升级到Delphi XE2,正在转换代码。



问题是,我们通过我们的应用程序和数据库记录使用值-693594代表无日期(零日)。在Delphi 2006中,FormatDateTime函数将正确格式化为00/00/0000(给定日期格式为dd / mm / yyyy)。



但是在Delphi XE2中,在System.SysUtils中的DateTImeToTimeStamp函数中添加了对ValidateTimeStampDate的调用,这引发错误无效浮点运算。传递任何大于-693594的文件,例如-693593,都可以正常工作。



有没有人有这个问题和/或有没有人知道一些工作?

解决方案

如果您真的绝望修复以前的行为,您可以使用以下内容:


$ b单位Unit1; $ b

  

接口

使用
Winapi.Windows,Winapi.Messages,System.SysUtils,System.Variants,System.Classes,Vcl.Graphics,
Vcl.Controls,Vcl.Forms,Vcl.Dialogs,Vcl.StdCtrls;

type
TForm1 = class(TForm)
Button1:TButton;
procedure Button1Click(Sender:TObject);
结束

var
Form1:TForm1;

实现

{$ R * .dfm}

过程PatchCode(地址:指针; const NewCode;大小:整数);
var
OldProtect:DWORD;
begin
如果VirtualProtect(Address,Size,PAGE_EXECUTE_READWRITE,OldProtect)然后
begin
Move(NewCode,Address ^,Size);
FlushInstructionCache(GetCurrentProcess,Address,Size);
VirtualProtect(Address,Size,OldProtect,@OldProtect);
结束
结束

type
PInstruction = ^ TInstruction;
TInstruction =打包记录
操作码:字节;
偏移:整数;
结束

程序RedirectProcedure(OldAddress,NewAddress:Pointer);
var
NewCode:TInstruction;
begin
NewCode.Opcode:= $​​ E9; // jump relative
NewCode.Offset:= NativeInt(NewAddress)-NativeInt(OldAddress)-SizeOf(NewCode);
PatchCode(OldAddress,NewCode,SizeOf(NewCode));
结束

函数DateTimeToTimeStamp(DateTime:TDateTime):TTimeStamp;
const
FMSecsPerDay:Single = MSecsPerDay;
IMSecsPerDay:Integer = MSecsPerDay;
var
LTemp,LTemp2:Int64;
begin
LTemp:= Round(DateTime * FMSecsPerDay);
LTemp2:=(LTemp div IMSecsPerDay);
Result.Date:= DateDelta + LTemp2;
Result.Time:= Abs(LTemp)mod IMSecsPerDay;
结束

procedure TForm1.Button1Click(Sender:TObject);
begin
ShowMessage(FormatDateTime('dd / mm / yyyy',-693594));
结束

初始化
RedirectProcedure(@ System.SysUtils.DateTimeToTimeStamp,@DateTimeToTimeStamp);

结束。

这将适用于32位代码。如果旧功能和新功能都驻留在同一可执行模块中,则它也适用于64位代码。否则跳转距离可能超过32位整数的范围。如果您的RTL驻留在运行时包中,它也不会工作。这些限制都可以很容易的补救。



这段代码是将所有调用重新路由到 SysUtils.DateTimeToTimeStamp 到本单元实施的版本。该单元中的代码只是来自XE2源的 PUREPASCAL 版本。



唯一满足您的意见中列出的需求是修改和重新编译SysUtils单元本身,但我个人避免了这种解决方案。




We have a bit of an issue here. We have upgraded from Delphi 2006 to Delphi XE2 and are in the process of converting our code.

The problem is, we use the value -693594 through our application and database records to represent no date (zero date). In Delphi 2006 the FormatDateTime function would correctly format this as 00/00/0000 (given a date format of dd/mm/yyyy).

However in Delphi XE2 they have added a call to ValidateTimeStampDate in the DateTImeToTimeStamp function in System.SysUtils which raises the error "invalid floating point operation". passing anything greater than -693594, such as -693593, works fine.

Has anyone else had this issue and/or does anyone know a work around?

解决方案

If you are really desperate to patch back to the previous behaviour you could use something like this:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure PatchCode(Address: Pointer; const NewCode; Size: Integer);
var
  OldProtect: DWORD;
begin
  if VirtualProtect(Address, Size, PAGE_EXECUTE_READWRITE, OldProtect) then
  begin
    Move(NewCode, Address^, Size);
    FlushInstructionCache(GetCurrentProcess, Address, Size);
    VirtualProtect(Address, Size, OldProtect, @OldProtect);
  end;
end;

type
  PInstruction = ^TInstruction;
  TInstruction = packed record
    Opcode: Byte;
    Offset: Integer;
  end;

procedure RedirectProcedure(OldAddress, NewAddress: Pointer);
var
  NewCode: TInstruction;
begin
  NewCode.Opcode := $E9;//jump relative
  NewCode.Offset := NativeInt(NewAddress)-NativeInt(OldAddress)-SizeOf(NewCode);
  PatchCode(OldAddress, NewCode, SizeOf(NewCode));
end;

function DateTimeToTimeStamp(DateTime: TDateTime): TTimeStamp;
const
  FMSecsPerDay: Single = MSecsPerDay;
  IMSecsPerDay: Integer = MSecsPerDay;
var
  LTemp, LTemp2: Int64;
begin
  LTemp := Round(DateTime * FMSecsPerDay);
  LTemp2 := (LTemp div IMSecsPerDay);
  Result.Date := DateDelta + LTemp2;
  Result.Time := Abs(LTemp) mod IMSecsPerDay;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage(FormatDateTime('dd/mm/yyyy', -693594));
end;

initialization
  RedirectProcedure(@System.SysUtils.DateTimeToTimeStamp, @DateTimeToTimeStamp);

end.

This will work for 32 bit code. It will also work for 64 bit code provided that both the old and new functions reside in the same executable module. Otherwise the jump distance may exceed the range of a 32 bit integer. It will also not work if your RTL resides in a runtime package. Both of these limitations can be readily remedied.

What this code does is re-route all calls to SysUtils.DateTimeToTimeStamp to the version implemented in this unit. The code in this unit is just the PUREPASCAL version from the XE2 source.

The only other approach that meets the needs outlined in your comments is to modify and re-compile the SysUtils unit itself, but I personally avoid that sort of solution.

这篇关于Delphi XE2 FormatDateTime传递-693594的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆