Как узнать переменную типа TDateTime, TDate и TTime в Delphi

Мне нужно знать переменные типа TDateTime, TDate и TTime.

Кто-нибудь знает, как это сделать?

Я использовал приведенный ниже код, результат «НЕ TDateTime», «НЕ TDate», «НЕ 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.

Спасибо


person Johni Douglas Marangon    schedule 03.10.2013    source источник
comment
Возможно, вы можете попытаться выполнить ответ from here.   -  person TLama    schedule 03.10.2013
comment
Добро пожаловать в Stack Overflow. Очень хорошо, что вы указали, какие результаты вы ожидали получить, но также полезно сообщать, какие результаты вы получили вместо этого. Вы знаете, что не получили TDateTime, так что исследуйте немного дальше и выясните, какой тип вы получили вместо этого. Также обратите внимание, что StrToDateTime, StrToDate и StrToTime все возвращают TDateTime, так что не надейтесь на их различение.   -  person Rob Kennedy    schedule 03.10.2013
comment
Тип TDateTime, всегда.   -  person Free Consulting    schedule 04.10.2013
comment
Нет, тип всегда Extended - см. мой ответ ниже.   -  person Stefan Glienke    schedule 04.10.2013


Ответы (3)


Перегрузки оператора Implicit для TValue достали вас.

Когда вы присваиваете результат StrToDateTime, StrToDate и StrToTime TValue, он использует наиболее подходящую перегрузку оператора Implicit из TValue, то есть Extended.

Также имейте в виду, что все три функции возвращают TDateTime, поэтому даже если бы были перегружены операторы для TDateTime, TDate и TTime, это не сработало бы должным образом.

Чтобы получить правильные результаты, вам нужно будет явно указать тип при присвоении ваших значений переменным TValue:

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' ));
person Stefan Glienke    schedule 04.10.2013
comment
Вау, Extended! Я не могу свыкнуться с тем фактом, что новый код Emba RTL по-прежнему использует Extended. Вставлять дату и время в Extended просто безумие. Достаточно плохо хранить их в двоичном формате с плавающей запятой (!!). Па! - person David Heffernan; 04.10.2013
comment
Проблема в том, что единственная подходящая неявная перегрузка оператора TValue для чисел с плавающей запятой является Extended, которая нарушает совместимость TDateTime/TTime/TDate/любого другого типа с плавающей запятой (т. е. возможность впоследствии определить тип). Хотя это проявляется в основном с этими типами, это также имеет место для любого другого типа, который не имеет конкретной перегрузки неявного оператора в TValue, но совместим по присваиванию с любым, имеющим перегрузку. - person Stefan Glienke; 04.10.2013
comment
Мне просто нравится любая возможность поныть о Extended, которого никогда не должно было существовать, и TDateTime с плавающей запятой. Возможность получить оба нытья одновременно была слишком заманчивой, чтобы упустить ее! ;-) - person David Heffernan; 04.10.2013

На всякий случай, если вы пытались определить тип результата 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;

В качестве альтернативы вы можете использовать функции TryStrToDate, TryStrToTime и TryStrToDateTime.

person Marcus Adams    schedule 03.10.2013
comment
Более наглядно использовать DateOf. - person David Heffernan; 03.10.2013
comment
@DavidHeffernan, я согласен, где это возможно. - person Marcus Adams; 04.10.2013

Если вам интересно, TDateTime внутренне закодирован как число с плавающей запятой Double.

Внутреннее устройство TDateTime
Дробная часть обозначает время, целая часть обозначает дату.
Зная это, следующие тесты дадут 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)) )

Очевидно, что это очень окольный способ тестирования, но иногда полезно знать, как TDateTime формируется внутри.

DateUtils
Разумными версиями этих тестов будут:

uses DateUtils;

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

TDateTime совместим с Excel
Значение 0 указывает на эпоху в Microsoft Excel: 30 декабря 1899 года; 00:00
(Должно быть 1-1-19:00, но они изменили его, чтобы компенсировать ошибку в алгоритме дат Lotus 123)
Это здорово, потому что TDateTime в Delphi полностью совместима с DateTime в Excel.

Вот официальный документ: http://docwiki.embarcadero.com/Libraries/XE5//en/System.TDateTime

person Johan    schedule 04.10.2013
comment
Отрицательных дат не бывает! Очевидно, у нас не одинаковый опыт свиданий. ;-) - person alcalde; 04.10.2013
comment
На самом деле у вас нет выбора, использовать ли даты -ve или нет - вам либо нужно представлять дату до 1900 года, либо нет. Однако я вижу, как временной отрезок может сбивать с толку. - person Matt Allwood; 04.10.2013
comment
@MattAllwood Конечно, вы можете создать свой собственный, но не ожидайте поддержки RTL (DateToStr) и т. Д. Да, и даты до 1900 года сложны. См. википедию. - person Johan; 04.10.2013
comment
-1 за то, что нет отрицательных дат. Есть и работают отлично. В документации, на которую вы ссылаетесь, даже прямо указано, что -1.25 - это 29 декабря 1899 года; 6:00 УТРА. Теперь, что должно составить -1,25 + 0,25? ... Ну -1 конечно. А впереди ровно 6 часов: 30 декабря 1989 года, полночь. Ничего сложного в этом нет. Совершенно и совершенно нормально. Чего и следовало ожидать, поскольку в противном случае мы бы никогда не смогли ничего сделать с датами до 30 декабря 1989 года, а генеалогические программы не имели бы смысла программироваться в Delphi. - person Marjan Venema; 04.10.2013
comment
Коррекция. Я признаю некоторую сложность при выполнении расчетов с долями времени. Время увеличивается от нуля по обе стороны от нуля, и это кажется неправильным, потому что вы ожидаете, что доли времени будут двигаться слева направо, как даты, даже ниже нуля. Тот факт, что доли времени как бы увеличиваются по сравнению с датами, на самом деле нужен для того, чтобы расчеты работали правильно. - person Marjan Venema; 04.10.2013
comment
@MarjanVenema, да, вы правы, я неправильно понял. Исправлено сейчас. - person Johan; 04.10.2013
comment
Голос против был преобразован в голос за. Мне уже понравилась остальная часть вашего поста! - person Marjan Venema; 04.10.2013