如何避免TDateTime数据舍入 [英] How to avoid TDateTime Data Rounding
问题描述
TCalendarEdit
和 TTimeEdit
每个单元格中的实例。一切都正常,除了正确处理这些子控件中的更改。 键入
TFMTValue< T> = record
FieldValue:T;
修改:boolean;
附加:boolean;
删除:boolean;
结束
TDateTimeCell = class(TStyledControl)
private
FDate_Time:TFMTValue< TDateTime> ;;
procedure SetDateTime(const Value:TFMTValue< TDateTime>);
函数GetDateTime:TFMTValue< TDateTime> ;;
protected
procedure SetData(const Value:TValue);覆盖
public
属性Date_Time:TFMTValue< TDateTime>读取GetDateTime写入SetDateTime;
...
end;
...
函数TDateTimeCell.GetDateTime:TFMTValue< TDateTime> ;;
begin
FDate_Time.Modified:=(FDate_Time.Modified)或
(FDate_Time.FieldValue> FCalendarEdit.Date +
+ FTimeEdit.Time);
FDate_Time.FieldValue:= FCalendarEdit.Date + FTimeEdit.Time;
结果:= FDate_Time;
结束
程序TDateTimeCell.SetData(const Value:TValue);
begin
Date_Time:= Value.AsType< TFMTValue< TDateTime>> ;;
继承了SetData(TValue.From< TDateTime>(FDate_Time.FieldValue));
ApplyStyling;
结束
procedure TDateTimeCell.SetDateTime(const Value:TFMTValue< TDateTime>);
begin
FDate_Time:= Value;
FCalendarEdit.Date:= DateOf(FDate_Time.FieldValue);
FTimeEdit.Time:= TimeOF(FDate_Time.FieldValue);
FDate_Time.FieldValue:= FCalendarEdit.Date + FTimeEdit.Time; //这行有助于在所有情况下
结束;
想法是数据是通过 TGrid
OnGetValue
事件处理程序。显示日期和时间。用户活动被捕获,修改
标志被设置。问题是即使没有任何用户活动,这个标志也被设置为true。我怀疑是由于TDateTime的时间的四舍五入。没有其他方式可以将值分配给 FCalendarEdit.Date
和 FTimeEdit.Time
。
如何正确比较存储在 FCalendarEdit.Date
和 FTimeEdit.Time中的数据
与存储在 FDate_Time.FieldValue
的
追加
以这种方式设置标志不能解决问题。
FDate_Time.Modified:=(FDate_Time.Modified)或
(DateOf(FDate_Time.FieldValue))FCalendarEdit.Date)或
(TimeOf(FDate_Time.FieldValue))FTimeEdit。时间);
追加2。在@ Ken-White的有价值的建议。
如果我们将比较行替换为
FDate_Time.Modified:=(FDate_Time.Modified)或
(不是SameDateTime(FDate_Time.FieldValue,
FCalendarEdit.Date + FTimeEdit.Time));
它工作正常。因此,TDataTime比较必须由此函数完成。
TDateTime
是类型Double
,这意味着它是一个浮点值,因此在进行相等的比较时会受到二进制表示的常见问题的限制,而不指定可接受的增量(差异)..
对于 TDateTime
值,您可以使用 DateUtils.SameDateTime
将平均值降至小于一毫秒:
FDate_Time.Modified:=(FDate_Time.Modified)或
(不是SameDateTime(FDate_Time.FieldValue,
FCalendarEdit.Date + FTimeEdit.Time));
I am writing column and cell classes for FMX TGrid
that will contain TCalendarEdit
and TTimeEdit
instances in every cell. Everything works fine except the proper processing of changes done in these child controls.
type
TFMTValue<T> = record
FieldValue: T;
Modified: boolean;
Appended: boolean;
Deleted: boolean;
end;
TDateTimeCell = class(TStyledControl)
private
FDate_Time: TFMTValue<TDateTime>;
procedure SetDateTime(const Value: TFMTValue<TDateTime>);
function GetDateTime: TFMTValue<TDateTime>;
protected
procedure SetData(const Value: TValue); override;
public
property Date_Time: TFMTValue<TDateTime> read GetDateTime write SetDateTime;
...
end;
...
function TDateTimeCell.GetDateTime: TFMTValue<TDateTime>;
begin
FDate_Time.Modified := (FDate_Time.Modified) or
(FDate_Time.FieldValue <> FCalendarEdit.Date +
+ FTimeEdit.Time);
FDate_Time.FieldValue := FCalendarEdit.Date + FTimeEdit.Time;
Result := FDate_Time;
end;
procedure TDateTimeCell.SetData(const Value: TValue);
begin
Date_Time := Value.AsType<TFMTValue<TDateTime>>;
inherited SetData(TValue.From<TDateTime>(FDate_Time.FieldValue));
ApplyStyling;
end;
procedure TDateTimeCell.SetDateTime(const Value: TFMTValue<TDateTime>);
begin
FDate_Time := Value;
FCalendarEdit.Date := DateOf(FDate_Time.FieldValue);
FTimeEdit.Time := TimeOF(FDate_Time.FieldValue);
FDate_Time.FieldValue:=FCalendarEdit.Date + FTimeEdit.Time; //this line helps but not in all cases
end;
The idea is that data is assigned via TGrid
OnGetValue
event handler. Both date and time are displayed. The user activity is catched and Modified
flag is set. The problem is that this flag is set to true sometimes even without any user activities. I suspect it is due to the rounding of time part of TDateTime. There are no other ways the code assignes values to FCalendarEdit.Date
and FTimeEdit.Time
.
How can I properly compare the data stored in FCalendarEdit.Date
and FTimeEdit.Time
with that stored in FDate_Time.FieldValue
?
Appended
Setting the flag in this way does not resolve the issue.
FDate_Time.Modified := (FDate_Time.Modified) or
(DateOf(FDate_Time.FieldValue) <> FCalendarEdit.Date) or
(TimeOf(FDate_Time.FieldValue)<> FTimeEdit.Time);
Appended 2. On a valued advice of @Ken-White. If we replace the comparison line by
FDate_Time.Modified := (FDate_Time.Modified) or
(not SameDateTime(FDate_Time.FieldValue,
FCalendarEdit.Date + FTimeEdit.Time));
It works fine. So the TDataTime comparison must be done by this function only.
TDateTime
is of type Double
, which means it's a floating point value, and therefore is subject to the usual issues of binary representation when doing comparisons for equality without specifying an acceptable delta (difference)..
Specifically for TDateTime
values, you can use DateUtils.SameDateTime
to compare equality down to less than one millisecond:
FDate_Time.Modified := (FDate_Time.Modified) or
(not SameDateTime(FDate_Time.FieldValue,
FCalendarEdit.Date + FTimeEdit.Time));
这篇关于如何避免TDateTime数据舍入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!