Объявите TDateTime как Const в Delphi
Насколько я знаю, нет способа сделать это, но я собираюсь спросить, на случай, если кто-то еще знает, как это сделать. Как я могу объявить дату как 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 ответов
Единственный? Возможный путь, но, вероятно, не то, что вы ищете:
const
{$J+}
Expire: TDateTime = 0;
{$J-}
initialization
Expire := EncodeDate(2009, 3, 23);
Хорошо, моя реакция немного запоздала, но вот решение для новых 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 этим, вам, вероятно, нужно перегрузить и некоторые другие операторы (сложение, вычитание, явное, ...).
Я склонен симулировать константные даты с помощью функции. Технически они немного более постоянны, чем присваиваемые "псевдо-константные" типизированные const.
function Expire: TDateTime;
begin
Result := EncodeDate(2009, 3, 23);
end;
ОТМЕТЬТЕ использование EncodeDate
скорее, чем StrToDate
, StrToDate
зависит от региональных настроек, то есть нет гарантии, что строка будет интерпретирована так, как ожидалось.
Например, знаете ли вы, что есть странная группа людей, которые думают, что имеет смысл "перетасовывать" части даты в непоследовательный порядок значимости? Они используют среднюю, затем наименьшую, затем наиболее значимую часть (например, "23.03.2009") <нахальная ухмылка>. Единственный раз, когда логика имеет смысл - это когда вам исполняется 102 года - тогда вы можете утверждать, что ваш возраст составляет 021 год.
Для недоношенных оптимизаторов, если функция вызывается так часто, что наносекунды, необходимые для кодирования даты, становятся проблемой - у вас гораздо большая проблема, чем эта незначительная неэффективность в названии читаемого, поддерживаемого кода.
Нет никакого способа сделать это, потому что интерпретация даты непосредственно не является детерминированной, она зависит от соглашения / языка, которому вы следуете.
'1/4/2009' не в январе для любого француза, например, и если компилятор переводит как 4 января, это сделает его компилятором дурака;-)
Если компилятор не реализует некоторую (хорошо документированную) "волшебную" биективную функцию для сопряжения значения даты и отображаемого представления... И вообще, половине планеты это не понравится.
Единственный не двусмысленный способ, который я вижу сейчас, это предоставить значение, даже если оно выглядит как боль...... мои $0,02
Нет, Delphi не поддерживает это.
Ваша первая идея - запрос литералов даты и времени, отличных от обычных литералов с плавающей точкой. Я нашел QC 72000, который о отображенииTDateTime
значения как даты в отладчике, но ничего о вашем конкретном запросе. Впрочем, никто не упоминал об этом раньше. Это постоянная тема в группах новостей; Я просто не могу ничего найти в КК по этому поводу.
Ваша вторая идея потребует StrToDate
быть оцененным во время компиляции. Я также не вижу записей об этом в QC, но C++ получает такую возможность для функций, которые, как показано, обладают необходимыми качествами. StrToDate
не будет соответствовать этим требованиям, потому что он чувствителен к настройкам даты текущей локали.
Одним из решений будет создание списка констант по годам, другого для смещений по месяцам, а затем создание его на лету. Вы должны были бы заботиться о високосных годах самостоятельно, добавляя 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;
РЕДАКТИРОВАТЬ
Для ясности добавлено еще несколько лет, и добавлена константа Leap_Day.
Ответ Роба Кеннеди показывает, что решение StrToDate само по себе исключено, поскольку вы не хотите, чтобы ваш код ломался, если он скомпилирован в Европе!
Я согласен, что должен быть какой-то способ сделать EncodeDate, но это не так.
Насколько мне известно, компилятор должен просто скомпилировать и запустить любой код, который он найдет в постоянном присваивании, и сохранить результат в константе. Я бы оставил это на усмотрение программиста, чтобы гарантировать, что код не чувствителен к его среде.
Дата Дельфи - это количество дней с 30 декабря 1899 года. Таким образом, вы, вероятно, могли бы придумать сложную математическую формулу, чтобы выразить дату как const. Тогда вы можете очень странно отформатировать его, чтобы подчеркнуть читаемые человеком части. Моя лучшая попытка ниже, но она очень неполная; с одной стороны, предполагается, что у всех месяцев есть 30 дней.
Мой пример в основном для развлечения. На практике это довольно смешно.
const
MyDate = ((
2009 //YEAR
- 1900) * 365.25) + ((
3 //MONTH
- 1) * 30) +
24 //DAY
;
System.DateUtils имеет константы для каждой части времени.
const cDT : TDateTime = (12 * OneHour) + ( 15 * OneMinute)
+ (33 * OneSecond) + (123 * OneMillisecond);
Я думаю, что лучшее решение, доступное для вас, это объявить:
ArmisticeDay: TDateTime = 6888.0 + (11.0/24.0); //Nov 11, 1918 11 AM
и просто прими это.
Моя попытка № 1
Expire = EncodeDate(2009, 3, 23);
[Ошибка] Ожидается постоянное выражение
Моя попытка № 2
Expire: TDateTime = EncodeDate(2009, 3, 23);
[Ошибка] Ожидается постоянное выражение
Таким образом, несмотря на то, что они постоянны и детерминированы (то есть не зависят от информации о локали), они все равно не работают.
Тип "TDateTime" = тип "Double".
Алгоритм:
- Используйте StrToDateTime ('01.01.1900 01:01:01 ') (или другой способ) для вычисления потребности в double_value. ('01.01.1900 01:01:01 '=> 2.04237268518519)
2.const DTZiro: TDateTime = 2.04237268518519;