我正在编写FMX def reverse(stack):
tmp1 = Stack()
while not stack.is_empty():
tmp1.push(stack.pop())
tmp2 = Stack()
while not tmp1.is_empty():
tmp2.push(tmp1.pop())
while not tmp2.is_empty():
stack.push(tmp2.pop())
的列和单元格类,每个单元格中都包含TGrid
和TCalendarEdit
个实例。除了正确处理这些子控件中所做的更改外,一切正常。
TTimeEdit
我们的想法是通过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;
TGrid
事件处理程序分配数据。显示日期和时间。捕获用户活动并设置OnGetValue
标志。问题是即使没有任何用户活动,有时也会将此标志设置为true。我怀疑这是由于TDateTime的时间部分的缩小。代码没有其他方式为Modified
和FCalendarEdit.Date
分配值。
如何正确比较FTimeEdit.Time
和FCalendarEdit.Date
中存储的数据与FTimeEdit.Time
中存储的数据?
追加
以这种方式设置标志不能解决问题。
FDate_Time.FieldValue
附加2。关于@Ken-White的重要建议。 如果我们用
替换比较线 FDate_Time.Modified := (FDate_Time.Modified) or
(DateOf(FDate_Time.FieldValue) <> FCalendarEdit.Date) or
(TimeOf(FDate_Time.FieldValue)<> FTimeEdit.Time);
工作正常。因此,TDataTime比较必须仅由此函数完成。
答案 0 :(得分:5)
TDateTime
属于type Double
,这意味着它是一个浮点值,因此在进行相等比较而不指定可接受的delta(差异)时,会遇到二进制表示的常见问题。
特别是对于TDateTime
值,您可以使用DateUtils.SameDateTime
将等式比较到不到一毫秒:
FDate_Time.Modified := (FDate_Time.Modified) or
(not SameDateTime(FDate_Time.FieldValue,
FCalendarEdit.Date + FTimeEdit.Time));
答案 1 :(得分:3)
TCalendarEdit (实际上是一些)中存在一个错误,这是导致问题的根本原因,但您只需对代码进行少量更改即可解决此问题。
TCalendarEdit 在应用新的日期值时会产生许多重大错误。
TDate 类型实际上只是普通的 TDateTime ,您应该忽略该时间部分。同样, TTime 是 TDateTime ,您应该忽略日期部分。
但是你必须在你的代码中正确使用这些类型 - 没有什么可以让 TTime 忽略日期或 TDate 忽略时间。
例如,如果检查TCalendarEdit的构造函数,您将看到它使用Now将内部日期/时间初始化为当前系统日期和时间,但是将其截断以消除时间元素:
Date := Trunc(Now);
到目前为止一切顺利。
但是当您通过日期属性应用新值时,它会执行以下(简化):
if Date <> Value then
FDateTime := Value + Time;
这些代码行中的两个都包含严重的错误:
它将日期(返回控件的日期值的属性)与分配的值进行比较 - 包括该日期的任何时间值/时间。它应该只比较值的 date 部分。
将新值分配到内部日期/时间时,会将时间添加到您指定的值。
第一个错误会导致内部属性发生不必要的更改,但相对来说无关紧要。然而,第二个错误要严重得多,这也是造成问题的原因。
我认为控制作者的意图是保持内部日期/时间值的时间部分不变。但是,值不会被截断,因此它会保留在属性赋值中指定的时间值。更糟糕的是,此控件上没有 Time 属性,因此实际上将当前系统时间添加到值中指定的任何时间。
由于您的测试用例涉及中午时间--12小时 - 结果是当您在下午运行此代码时, TCalendarEdit 的日期实际上是设置为2015年9月25日+ 12小时+ 控件初始化时的时间。
如果您在早上运行代码,它似乎有效,因为添加的时间会产生一个仍然在9月25日的值。
但是当你在下午运行代码时,12小时会被添加到当前时间,所以日期会滚动到到第二天!
使用更有用的诊断错误消息,或者如果您通过调试器检查了代码中的属性,您会看到这种情况发生。
DT := EncodeDate(2015, 9, 25) + EncodeTime(12, 0, 0, 0);
CalendarEdit1.Date := DT;
ShowMessage(DateTimeToString(CalendarEdit1.Date));
// When executed at e.g. 9am, displays: 25 Sep 2015
// When executed at e.g. 1pm, displays: 26 Sep 2015
因此,您的比较失败的原因是日期实际上完全不同!
如果你曾尝试过简单地使用 SameDateTime()进行比较,那么如果你在早上上测试它可能已经有效了,但你的问题会在下午!!
您可以通过确保自己尊重属性值的预期用途,仅分配 DT 日期/时间值的那些部分,来解决 TCalendarEdit 中的这些错误适用于每种情况:
TimeEdit1.Time := TimeOf(DT);
CalendarEdit1.Date := DateOf(DT);
虽然在 TTimeEdit 的情况下并非绝对必要,但这会阻止 TCalendarEdit 中的这些错误导致这些问题,并在您的代码中明确表示您已了解需要什么(如果你愿意,可以考虑自己记录代码)。 :)
如果您的Delphi版本中没有 TimeOf()和 DateOf()函数,则以下内容是等效的:
TimeEdit1.Time := DT - Trunc(DT);
CalendarEdit1.Date := Trunc(DT);
您当然可以根据此编写自己的 TimeOf()和 DateOf()版本,以使意图更加清晰。
由于Delphi中日期/时间值的浮点性质而导致 精确复杂化,这可能导致与某些特定日期和时间值的直接比较出现问题,因此强烈建议您使用 SameDateTime()函数执行此类比较。
但在这种情况下,这绝对是不问题的原因, SameDateTime() 不解决您的问题。
SameDateTime()消除了因日期/时间值差异小于1毫秒而产生的问题。这种情况的区别是24小时!
值得注意的是, TCalendarEdit 控件在XE7中已弃用,并已完全从XE8中删除。