29

据我所知,没有办法做到这一点,但我会问以防万一其他人知道如何做到这一点。如何在 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');

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

4

11 回答 11

22

好的,我的反应有点晚了,但这是新德尔福的解决方案。

它使用隐式类重载器,以便可以像使用 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 变量,您可能还需要重载一些其他运算符(加、减、显式......)。

于 2009-05-15T17:03:01.630 回答
12

唯一的?可能的方式,但可能不是您正在寻找的:

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

initialization
  Expire := EncodeDate(2009, 3, 23);
于 2009-03-23T23:26:16.110 回答
11

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

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

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

例如,你知道有一群奇怪的人认为将日期部分“洗牌”成不一致的重要性顺序是有意义的吗?他们使用中间,然后是最小,然后是最重要的部分(例如 '3/23/2009')<cheeky grin>。唯一合理的逻辑是当你 102 岁时——那么你可以声称你的年龄是 021 岁。

对于那些不成熟的优化器,如果函数被如此频繁地调用,以至于编码日期所需的纳秒成为一个问题 - 你遇到的问题远不止是可读、可维护代码的这种轻微的低效率问题。

于 2012-06-30T12:31:17.767 回答
8

没有办法做到这一点,因为解释日期文字本身不是确定性的,它取决于您遵循的约定/语言环境。
例如,对于任何法国人来说,'1/4/2009' 不在 1 月,并且将编译器翻译为 1 月 4 日会使其成为傻瓜编译器;-)
除非编译器为将日期值和显示表示配对...无论如何,地球上的一半人都不喜欢它。
我现在看到的唯一明确的方式是提供价值,即使它看起来很痛苦......我的 0.02 美元

于 2009-03-24T01:30:08.387 回答
6

不,Delphi 不支持。

您的第一个想法是请求与普通浮点文字不同的日期时间文字。我找到了QC 72000,它是关于TDateTime在调试器中将值显示为日期,但与您的特定请求无关。不过,这不像以前没有人提到过。这是新闻组中常年出现的话题;我只是在 QC 中找不到任何关于它的信息。

您的第二个想法需要StrToDate在编译时进行评估。我在 QC 中也没有看到任何关于它的条目,但就其价值而言,C++ 正在为具有必要品质的函数获得这样的特性。StrToDate但是,它不能满足这些要求,因为它对当前语言环境的日期设置很敏感。

于 2009-03-24T01:10:41.053 回答
4

Rob Kennedy 的回答表明 StrToDate 解决方案本质上是不可能的,因为您不希望您的代码在欧洲编译时中断!

我同意应该有某种方法来做 EncodeDate 但没有。

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

于 2009-03-24T01:27:15.413 回答
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 常量。

于 2009-03-25T16:49:38.887 回答
3

Delphi 日期是自 1899 年 12 月 30 日以来的天数。因此,您可能会想出一个复杂的数学公式来将日期表示为 const。然后你可以非常奇怪地格式化它,以强调人类可读的部分。我最好的尝试如下,但它非常不完整;一方面,它假设所有月份都有 30 天。

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

const
  MyDate = ((
           2009  //YEAR
                                          - 1900) * 365.25) + ((
           3     //MONTH
                                          - 1) * 30) +
           24    //DAY
           ;
于 2009-03-24T13:36:04.383 回答
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);

[错误] 应为常量表达式

因此,即使它们是恒定的且具有确定性(即不依赖于任何语言环境信息),它仍然不起作用。

于 2009-05-14T17:09:30.890 回答
1

“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;

于 2018-11-18T08:42:10.100 回答
1

System.DateUtils 具有每个时间部分的常量。

const cDT : TDateTime = (12 * OneHour)   + ( 15 * OneMinute) 
                      + (33 * OneSecond) + (123 * OneMillisecond);
于 2020-09-10T14:04:58.887 回答