Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't a Variant contain a TDateTime before 100 CE?

Tags:

delphi

Consider the following code:

procedure Test;
  function d1: Variant;
  var
    DDt: TDateTime;
  begin
    DDt := EncodeDate(100,1,1);
    Result := DDt;
  end;
  function d2: Variant;
  var
    DDt: TDateTime;
  begin
    DDt := EncodeDate(99,12,31);
    Result := DDt;
  end;
  procedure Writedate(V: Variant);
  begin
    Writeln(string(V));
  end;
var
  V: Variant;
begin
  V := d1;
  Writedate(V);
  V := d2;
  Writedate(V);
end;

The first call to Writedate will succeed, and the output will be '01-01-0100'. The second call, however, will fail with an 'invalid argument' failure. Inspecting the code, you can see the Variant of the 99-12-31 date has a EVariantInvalidArgError error.

However, if I call FormatDateTime('c', TDateTime(V)) on either TDateTime, they will both succeed. In fact, at any point when the Variant contains a TDateTime, whose date is before 100 CE, the IDE will display a EVariantInvalidArgError when inspecting its value.

It seems odd that the Variant cannot handle the pre-100 CE date, when TDateTime can. Is this a bug in Delphi? I find it being right between 99 and 100 CE to be a bit suspicious.

like image 653
Svip Avatar asked May 22 '15 08:05

Svip


People also ask

Why does assigning a variant to a tdatetime variable not work?

Assigning a Variant to a TDateTime variable does not work. Because TDateTime is a floating-point type, the assignment would try to convert the Variant to a varDouble, not a varDate.

Why does vartodatetime return a vardouble instead of vardate?

Because TDateTime is a floating-point type, the assignment would try to convert the Variant to a varDouble, not a varDate. VarToDateTime eventually calls the Windows API function VariantChangeTypeEx to parse the string and interpret the date and time. See the Platform SDK documentation for details.

How to check the currently active type in a variant?

You can assess the value by using std::get, std::get_if or by using a form of a visitor. To check the currently active type you can use std::holds_alternative or std::variant::index std::visit is a way to invoke an operation on the currently active type in the variant.

How to create and initialize a variant of a type?

There are several ways you can create and initialize std::variant: Play with the code here @Coliru. if that’s not possible when the type doesn’t have a default constructor, then you’ll get a compiler error you can use std::monostate to pass it as the first type in that case


1 Answers

Variant can contain any date value, as your code demonstrates (assignment V := d2; produces no error).

The error is raised during the conversion to string which the compiler delegates to the OS on Windows platforms. This fails because OLE Automation specifies midnight, 1 January 0100 as the minimum valid OLE Automation date value.

like image 98
Ondrej Kelle Avatar answered Nov 14 '22 21:11

Ondrej Kelle