在Delphi中将TDateTime声明为Const

时间:2009-03-23 23:00:10

标签: delphi date operator-overloading const tdatetime

据我所知,没有办法做到这一点,但我会问以防其他人知道如何做到这一点。如何在Delphi中将日期声明为const?

我找到的唯一解决方案是使用数字等价物,这是一种痛苦来维护,因为它不是人类可读的。

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

我希望能做的是这样的事情:

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

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

所以让我知道这是一个功能请求还是我错过了如何做到这一点(是的,我知道这似乎是一件奇怪的事情......)。

11 个答案:

答案 0 :(得分:21)

好的,我的反应有点晚了,但这是新款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变量,你可能还需要重载其他一些运算符(加,减,显式,......)。

答案 1 :(得分:12)

唯一的?可能的方式,但可能不是你想要的:

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

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

答案 2 :(得分:10)

我倾向于使用函数模拟 const 日期。从技术上讲,它们比“伪常量”可分配类型的 const 更加常量

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

注意使用EncodeDate而不是StrToDateStrToDate受区域设置的影响,这意味着无法保证将字符串解释为预期的字符串。

例如,您是否知道有一群人认为将日期部分“混乱”为不一致的重要顺序是有意义的?他们使用中间,然后最少,然后最重要的部分(例如'3/23/2009')< cheeky grin> 。逻辑有意义的唯一时间是当你年满102岁时 - 那么你可以宣称你的年龄是021岁。

  

对于那些过早优化器,如果频繁调用该函数使得编码日期所需的纳秒时间成为一个问题 - 那么你有一个远远更大的问题可读,可维护的代码名称中的这种轻微的低效率。

答案 3 :(得分:8)

没有办法做到这一点,因为解释日期本身不是确定性的,它取决于您遵循的约定/区域。
例如,对于任何一个法国人来说,'1 / 4/2009'不是1月份,并且将编译器翻译为1月4日会使它成为傻瓜的编译器;-)
除非编译器实现一些(记录良好的)“魔术”双射函数来配对日期值和显示表示......无论如何,一半的星球都不喜欢它。
我现在看到的唯一不模糊的方式是提供价值,即使它看起来像一个痛苦...... ......我的0.02美元

答案 4 :(得分:6)

不,Delphi不支持。

您的第一个想法是请求日期时间文字与普通浮点文字不同。我找到了QC 72000,它是关于在调试器中显示TDateTime值作为日期,但没有关于您的特定请求。但是,这并不像之前没有人提到的那样。这是新闻组的一个长期主题;我在QC中找不到任何关于它的信息。

您的第二个想法是要求StrToDate在编译时可评估。我没有在QC中看到任何有关它的条目,但是对于它的价值,C ++正在为显示具有必要品质的功能获得这样的功能。但是,StrToDate不符合这些要求,因为它对当前区域设置的日期设置很敏感。

答案 5 :(得分:4)

Rob Kennedy的回答表明StrToDate解决方案本质上是不可能的,因为如果它在欧洲编译,你不希望你的代码破坏!

我同意应该有一些方法来做EncodeDate,但没有。

就我而言,编译器应该简单地编译并运行它在常量赋值中找到的任何代码并将结果存储到常量中。我将它留给程序员来确保代码对它的环境不敏感。

答案 6 :(得分:4)

一种解决方案是创建一个常量列表多年,另一个用于月份偏移,然后在运行中构建它。你必须通过在每个结果常量中加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;

如果你有一个闰年,那么你必须在那年的2月之后加上1。

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

修改

为了清晰起见,又增加了几年,并添加了Leap_Day常量。

答案 7 :(得分:3)

Delphi日期是days since Dec 30, 1899的#。所以你可能想出一个精心设计的数学公式来表示一个日期作为const。然后你可以非常奇怪地格式化它,以强调人类可读的部分。我最好的尝试是在下面,但它是非常不完整的;首先,它假定所有月份都有30天。

我的例子主要是为了好玩。在实践中,这非常荒谬。

const
  MyDate = ((
           2009  //YEAR
                                          - 1900) * 365.25) + ((
           3     //MONTH
                                          - 1) * 30) +
           24    //DAY
           ;

答案 8 :(得分:1)

我认为 可用的最佳解决方案是声明:

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

然后接受它。


我的尝试Nº1

Expire = EncodeDate(2009, 3, 23);
  

[错误]预期的常量表达式

我的尝试N°2

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

[错误]预期的常量表达式

因此即使它们是常数和确定性的(即不依赖于任何语言环境信息),它仍然无效。

答案 9 :(得分:1)

System.DateUtils在每个时间段都有常量。

const cDT : TDateTime = (12 * OneHour)   + ( 15 * OneMinute) 
                      + (33 * OneSecond) + (123 * OneMillisecond);

答案 10 :(得分:0)

类型“ TDateTime” =类型“ Double”。

算法:

  1. 使用 StrToDateTime('01 .01.1900 01:01:01') (或其他方式)来计算需要的double_value。 ('01 .01.1900 01:01:01'=> 2.04237268518519)

2. 常量 DTZiro:TDateTime = 2.04237268518519;