5

I need know type variable TDateTime, TDate and TTime.

Anyone have any idea how to do this?

I used the code below, the result is "Is NOT TDateTime", "Is NOT TDate", "Is NOT Ttime"


program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.Rtti,
  System.SysUtils;

var
  DateTime, Date,Time: TValue;

begin

  DateTime:= StrToDateTime( '01/01/2013 01:05:09' );
  if ( DateTime.TypeInfo = System.TypeInfo(TDateTime) ) then
    Writeln( 'Is TDateTime' )
  else
    Writeln( 'Is NOT TDateTime' );

  Date:=  StrToDate( '01/01/2015' );
  if ( Date.TypeInfo = System.TypeInfo(TDate) ) then
    Writeln( 'Is TDate' )
  else
    Writeln( 'Is NOT TDate' );

 Time:=  StrToTime( '01:01:02' );
  if ( Date.TypeInfo = System.TypeInfo(TTime) ) then
    Writeln( 'Is TTime' )
  else
    Writeln( 'Is NOT TTime' );

 Readln;

end.

Thanks

  • 3
    Maybe you can try to follow the answer [`from here`](http://stackoverflow.com/q/7836880/960757). – TLama Oct 03 '13 at 17:09
  • 3
    Welcome to Stack Overflow. It's very good that you included what results you *expected* to get, but it's also helpful to report what results you got *instead*. You know you didn't get a TDateTime, so investigate a little further and find out what type you got instead. Also note that StrToDateTime, StrToDate, and StrToTime *all* return TDateTime, so don't get your hopes up about distinguishing them. – Rob Kennedy Oct 03 '13 at 17:34
  • Type is `TDateTime`, always. – Free Consulting Oct 03 '13 at 21:19
  • No, the type is `Extended` always - see my answer below. – Stefan Glienke Oct 04 '13 at 06:18

3 Answers3

5

The Implicit operator overloads of TValue got you.

When you assign the result of StrToDateTime, StrToDate and StrToTime to a TValue it uses the most matching Implicit operator overload from TValue which is Extended.

Also keep in mind that all three functions return TDateTime so even if there were operator overloads for TDateTime, TDate and TTime it would not work as expected.

To get the correct results you would have to explicitly specify the type when assigning your values to the TValue variables:

DateTime := TValue.From<TDateTime>(StrToDateTime( '01.01.2013 01:05:09' ));

Date:= TValue.From<TDate>(StrToDate( '01.01.2015' ));

Time:= TValue.From<TTime>(StrToTime( '01:01:02' ));
Stefan Glienke
  • 20,860
  • 2
  • 48
  • 102
  • Wow, `Extended`! I cannot get over the fact that new Emba RTL code still uses `Extended`. Putting a date time into an `Extended` is just bonkers. Bad enough storing them in binary floating point (!!). Pah! – David Heffernan Oct 04 '13 at 12:33
  • The "problem" is that the only matching Implicit operator overload of TValue for float numbers *is* Extended which breaks TDateTime/TTime/TDate/any other float type compatibility (i.e. being able to determine the type afterwards). While it manifests mostly with these types it is also the case for any other type that does not have a specific Implicit operator overload in TValue but is assignment compatible to any that has an overload. – Stefan Glienke Oct 04 '13 at 12:42
  • 1
    I just like any opportunity to whine about `Extended` which should never have existed, and `TDateTime` being floating point. An opportunity have both whines at the same time was too enticing to pass up! ;-) – David Heffernan Oct 04 '13 at 13:25
2

Just in case you were trying to determine the result type of StrToDateTime:

type
  TDateType = (dtDate, dtDateTime, dtTime);

function getDateType(date: TDateTime): TDateType;
begin
  if Trunc(date) = date then // Or DateOf(date), if available
  begin
    Result := dtDate;
  end
  else
  begin
    if Trunc(date) = 0 then // Or DateOf(date), if avaialble
    begin
      Result := dtTime
    end
    else
    begin
      Result := dtDateTime;
    end;
  end;
end;

// Sample
var
  result: TDateType;
begin
  result := getDateType(StrToDateTime('01/01/2013 01:05:09')); // dtDateTime
  result := getDateType(StrToDateTime('01/01/2015')); // dtDate
  result := getDateType(StrToDateTime('01:01:02')); // dtTime
  // One caveat
  result := getDateType(StrToDateTime('01/01/2013 00:00:00')); // dtDate
end;

Alternatively, you could use the TryStrToDate, TryStrToTime, and TryStrToDateTime functions.

Marcus Adams
  • 53,009
  • 9
  • 91
  • 143
2

In case you're curious, the TDateTime is encoded as floating point Double internally.

TDateTime internals
The fractional part denotes the time, the integer part denotes the date.
Knowing this the following tests will evaluate to true.

dtTime: ABS(Double(DateTime1)) < 1.0 
dtDate: Trunc(Double(DateTime1)) = Double(DateTime1)
dtDateTime:  (     (ABS(Double(DateTime1)) > 1.0) 
         and (Trunc(Double(DateTime1)) <> Double(DateTime1)) )

Obviously that's a very roundabout way of testing, but sometimes it helps to know how a TDateTime is shaped internally.

DateUtils
The sane versions of these tests would be:

uses DateUtils;

dtDate: DateTime1 = DateOf(DateTime1)
dtTime: DateTime1 = TimeOf(DateTime1)
dtDateTime:(DateTime1 <> DateOf(DateTime1)) and (DateTime1 <> TimeOf(DateTime1))

TDateTime is compatible with Excel
The value 0 links to the epoch in Microsoft's Excel: 30 December 1899; 12:00 A.M.
(It should have been 1-1-1900, but they changed it to compensate for an error in Lotus' 123 date algorithm)
This is great, because Delphi's TDateTime is fully compatible with Excel's DateTime.

Here's the official doc: http://docwiki.embarcadero.com/Libraries/XE5//en/System.TDateTime

Johan
  • 74,508
  • 24
  • 191
  • 319
  • 2
    "There are no negative dates!" Obviously we don't have the same dating experience. ;-) – alcalde Oct 04 '13 at 01:31
  • You don't really get a choice of whether to use -ve dates or not - you either need to represent a pre-1900 date or you don't. I can see how the time segment could be confusing, though. – Matt Allwood Oct 04 '13 at 08:13
  • @MattAllwood Sure you can roll your own, but don't expect RTL support (DateToStr) etc. Oh and pre 1900 dates are complicated. See wikipedia. – Johan Oct 04 '13 at 09:39
  • -1 for stating there are no negative dates. There are and they function perfectly fine. The documentation you linked even explicitely states that `-1.25` is December 29, 1899; 6:00 A.M. Now what should -1.25 + 0.25 add up to? ... Well, -1 of course. And yest that is exactly 6 hours ahead: December 30 1989 at midnight. Nothing complicated about it. Completely and utterly normal. Which is only to be expected as we would otherwise never be able to do anything with dates prior to December 30 1989 and genealogy programs would have no business being programmed in Delphi – Marjan Venema Oct 04 '13 at 17:42
  • Correction. I'll admit to a bit of complication when doing calculations with time fractions. Time increases away from zero on both sides of zero and that seems "off" because you would expect time fractions to move from left to right just like dates do even below zero. That fact time fractions sort of increase "contrary" to the dates is actually to make calculations work correctly. – Marjan Venema Oct 04 '13 at 17:50
  • @MarjanVenema, Yes, you are correct, I misread. Corrected now. – Johan Oct 04 '13 at 17:52
  • Downvote converted to upvote. I already liked the rest of your post! – Marjan Venema Oct 04 '13 at 17:53