Delphi XE2 FormatDateTime传递-693594 [英] Delphi XE2 FormatDateTime passing -693594
问题描述
问题是,我们通过我们的应用程序和数据库记录使用值-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屋!