如何避免TDateTime数据舍入 [英] How to avoid TDateTime Data Rounding

查看:113
本文介绍了如何避免TDateTime数据舍入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为FMX c> TGrid 编写列和单元格类,其中包含 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屋!

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