Объявите TDateTime как Const в Delphi - PullRequest
29 голосов
/ 24 марта 2009

Насколько я знаю, нет способа сделать это, но я собираюсь спросить, на случай, если кто-то еще знает, как это сделать. Как я могу объявить дату как const в Delphi?

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

const
  Expire : TDateTime = 39895; // Is actually 3/23/2009

То, что я хотел бы сделать, это примерно так:

const
  Expire : TDateTime = TDateTime ('3/23/2009');

или

const
  Expire : TDateTime = StrToDate('3/23/2009');

Так что дайте мне знать, если это запрос на функцию или я просто пропустил, как это сделать (да, я знаю, что это странная вещь ...)

Ответы [ 10 ]

21 голосов
/ 15 мая 2009

Хорошо, моя реакция немного запоздала, но вот решение для более новой Delphi.

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

  TDateRec = record
    year,month,day,hour,minute,second,millisecond:word;
    class operator implicit(aDateRec:TDateRec):TDateTime;
    class operator implicit(aDateTime:TDateTime):TDateRec; // not needed
    class operator implicit(aDateRec:TDateRec):String; // not needed
    class operator implicit(aDateRec:String):TDateRec; // not needed
  end;

Реализация:

uses DateUtils;

class operator TDateRec.Implicit(aDateRec:TDateRec):TDateTime;
begin
  with aDateRec do // Yeah that's right you wankers. I like "with" :)
    Result := encodeDateTime(Year,Month,Day,Hour,Minute,Second,Millisecond);
end;

class operator TDateRec.Implicit(aDateTime:TDateTime):TDateRec;
begin
  with Result do
    DecodeDateTime(aDateTime,Year,Month,Day,Hour,Minute,Second,Millisecond);
end;

class operator TDateRec.Implicit(aDateRec:TDateRec):String;
begin
  Result := DateTimeToStr(aDateRec)
end;

class operator TDateRec.Implicit(aDateRec:String):TDateRec;
begin
  Result := StrToDateTime(aDateRec)
end;

Теперь вы можете объявить свои даты следующим образом:

const
  Date1:TDateRec=(Year:2009;month:05;day:11);
  Date2:TDateRec=(Year:2009;month:05;day:11;hour:05);
  Date3:TDateRec=(Year:2009;month:05;day:11;hour:05;minute:00);

Чтобы проверить, работает ли он, выполните следующее:

ShowMessage(Date1); // it can act like a string
ShowMessage(DateToStr(Date1)); // it can act like a date

Если вы действительно хотите заменить все переменные TdateTime этим, вам, вероятно, потребуется перегрузить и некоторые другие операторы (сложение, вычитание, явное и т. Д.).

12 голосов
/ 24 марта 2009

единственный? Возможный путь, но, вероятно, не то, что вы ищете:

const
{$J+}
  Expire: TDateTime = 0;
{$J-}

initialization
  Expire := EncodeDate(2009, 3, 23);
10 голосов
/ 30 июня 2012

Я склонен симулировать const даты с помощью функции. Технически они * немного больше константа , чем присваиваемая "псевдо-константа", набираемая const .

function Expire: TDateTime;
begin
  Result := EncodeDate(2009, 3, 23);
end;

ПРИМЕЧАНИЕ использование EncodeDate вместо StrToDate. StrToDate зависит от региональных настроек, то есть нет гарантии, что строка будет интерпретирована так, как ожидалось.

Например, знаете ли вы, что есть странная группа людей, которые думают, что имеет смысл «перетасовать» части даты в непоследовательный порядок значимости? Они используют среднюю, затем наименьшую, затем наиболее значимую часть (например, «23.03.2009») <нахальная ухмылка> . Логика имеет смысл только тогда, когда вам исполняется 102 года - тогда вы можете утверждать, что ваш возраст равен 021.

Для преждевременных оптимизаторов , если функция вызывается так часто, что наносекунды, необходимые для кодирования даты, становятся проблемой - у вас есть проблема на больше , чем эта незначительная неэффективность имени читаемого, поддерживаемого кода.

8 голосов
/ 24 марта 2009

Нет никакого способа сделать это, потому что интерпретация литеральной даты сама по себе не является детерминированной, она зависит от принятого вами соглашения / языка.
Например, '1/4/2009' не в январе для любого француза, и если компилятор переведет его как 4 января, это сделает его компилятором дурака; -)
Если компилятор не реализует некоторую (хорошо документированную) «волшебную» биективную функцию для сопряжения значения даты и отображаемого представления ... И вообще, половине планеты это не понравится.
Единственный не двусмысленный способ, который я вижу сейчас, - это предоставить значение, даже если это выглядит как боль ... ... мои $ 0,02

6 голосов
/ 24 марта 2009

Нет, Delphi не поддерживает это.

Ваша первая идея - запрос литералов даты и времени, отличных от обычных литералов с плавающей точкой. Я нашел QC 72000 , который показывает отображение значений TDateTime в качестве дат в отладчике, но ничего о вашем конкретном запросе Впрочем, никто не упоминал об этом раньше. Это постоянная тема в группах новостей; Я просто не могу ничего найти в КК по этому поводу.

Ваша вторая идея потребует оценки StrToDate во время компиляции. Я также не вижу записей об этом в QC, но C ++ получает такую ​​возможность для функций, которые, как показано, обладают необходимыми качествами. StrToDate не отвечает этим требованиям, потому что он чувствителен к настройкам даты текущей локали.

4 голосов
/ 25 марта 2009

Одним из решений было бы создание списка констант по годам, другого для смещений по месяцам, а затем создание его на лету. Вы должны были бы заботиться о високосных годах самостоятельно, добавляя 1 к каждой полученной константе. Несколько ниже, чтобы начать ...:)

Const
  Leap_Day = 1;  // use for clarity for leap year dates beyond feb 29.
  Year_2009 = 39812;  // January 1, 2009
  Year_2010 = Year_2009 + 365; // January 1, 2010
  Year_2011 = Year_2010 + 365; // January 1, 2011
  Year_2012 = Year_2011 + 365; // January 1, 2012 (is leap year)
  Year_2013 = Year_2012 + Leap_Day + 365;  // January 1, 2013

Const
  Month_Jan = -1; // because adding the day will make the offset 0. 
  Month_Feb = Month_Jan + 31; // 31 days more for the first day of Feb.
  Month_Mar = Month_Feb + 28; // 28 days more for the first day of Mar.  
  Month_Apr = Month_Mar + 30; // 30 days more for the first day of Apr.

Const
  Expire_Jan1 : tDateTime = Year_2009 + Month_Jan + 1;
  Expire : tDateTime = Year_2009 + Month_Mar + 23;

Если у вас високосный год, вы должны добавить 1 к чему-либо, кроме февраля этого года.

Const
  Expire : tDateTime = Year_2008 + Month_Mar + 23 + Leap_Day;

EDIT

Для ясности добавлено еще несколько лет и добавлена ​​константа Leap_Day.

4 голосов
/ 24 марта 2009

Ответ Роба Кеннеди показывает, что решение StrToDate само по себе исключено, поскольку вы не хотите, чтобы ваш код ломался, если он скомпилирован в Европе!

Я согласен, что должен быть какой-то способ сделать EncodeDate, но это не так.

Насколько мне известно, компилятор должен просто скомпилировать и запустить любой код, который он найдет в постоянном присваивании, и сохранить результат в константе. Я бы оставил это на усмотрение программиста, чтобы гарантировать, что код не чувствителен к его среде.

3 голосов
/ 24 марта 2009

Дельфийская дата - это число дней с 30 декабря 1899 . Таким образом, вы, вероятно, могли бы придумать сложную математическую формулу, чтобы выразить дату как const. Тогда вы можете очень странно отформатировать его, чтобы подчеркнуть читаемые человеком части. Моя лучшая попытка ниже, но она очень неполная; с одной стороны, предполагается, что у всех месяцев есть 30 дней.

Хотя мой пример в основном для развлечения. На практике это довольно смешно.

const
  MyDate = ((
           2009  //YEAR
                                          - 1900) * 365.25) + ((
           3     //MONTH
                                          - 1) * 30) +
           24    //DAY
           ;
1 голос
/ 14 мая 2009

я думаю лучшее доступное решение для вас - объявить:

ArmisticeDay: TDateTime = 6888.0 + (11.0/24.0); //Nov 11, 1918 11 AM

и просто прими это.


Моя попытка Nº1

Expire = EncodeDate(2009, 3, 23);

[Ошибка] Ожидается постоянное выражение

Моя попытка №2

Expire: TDateTime = EncodeDate(2009, 3, 23);

[Ошибка] Ожидается постоянное выражение

Так что, хотя они постоянны и детерминированы (то есть не зависят от какой-либо информации о локали), они все равно не работают.

0 голосов
/ 18 ноября 2018

Тип "TDateTime" = тип "Double".

Алгоритм:

  1. Используйте StrToDateTime ('01 .01.1900 01:01:01 ') (или другим способом) для вычисления потребности в double_value. ('01 .01.1900 01:01:01 '=> 2.04237268518519)

2. Const DTZiro: TDateTime = 2.04237268518519;

...