代码之家  ›  专栏  ›  技术社区  ›  Jim McKeeth

在Delphi中将tdateTime声明为常量

  •  29
  • Jim McKeeth  · 技术社区  · 16 年前

    据我所知,没有办法做到这一点,但我会问,以防万一有人知道如何做到这一点。我如何在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 回复  |  直到 6 年前
        1
  •  21
  •   Wouter van Nifterick Andrey    16 年前

    好吧,我的反应有点晚了,但这里有一个新的德尔菲的解决方案。

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

        2
  •  12
  •   Jim McKeeth    16 年前

    唯一的?可能的方法,但可能不是你要找的:

    const
    {$J+}
      Expire: TDateTime = 0;
    {$J-}
    
    initialization
      Expire := EncodeDate(2009, 3, 23);
    
        3
  •  10
  •   Disillusioned    13 年前

    我倾向于模仿 康斯特 带有函数的日期。从技术上讲,他们有点多 常数 比“伪常量”可赋值类型 康斯特 s。

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

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

    例如,你知道有一个奇怪的群体,他们认为把约会的部分按照不一致的顺序“洗牌”是有意义的吗?它们使用中间部分,然后是最少部分,然后是最重要的部分(例如“3/23/2009”)。 <厚颜无耻的咧嘴笑; .只有当你102岁的时候,逻辑才有意义——然后你可以声称你的年龄是021岁。

    对于 过早乐观主义者 如果函数被频繁调用,那么编码日期所需的纳秒数就成了一个问题,那么 更大的 问题比这个小效率在名称可读,可维护的代码。

        4
  •  8
  •   Francesca    16 年前

    无法做到这一点,因为解释一个日期本身并不具有确定性,它取决于您所遵循的约定/区域设置。
    例如,“1/4/2009”对于任何一个法国人来说都不是在一月份,而让编译器在1月4日进行翻译会使它成为一个愚蠢的编译器;-)
    除非编译器实现了一些(有良好文档记录的)“magic”双目标函数来对日期值和显示表示进行配对…不管怎样,地球上有一半的人不喜欢它。
    我现在看到的唯一不含糊的方法是提供价值,即使它看起来像痛苦… …我的0.02美元

        5
  •  6
  •   Rob Kennedy    16 年前

    不,德尔福不支持。

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

    你的第二个想法需要 StrToDate 在编译时可评估。我在QC也没有看到关于它的任何条目,但是对于它的价值来说,C++获得了那些显示出必要的功能的特征。 斯特罗特 但不满足这些要求,因为它对当前区域设置的日期设置很敏感。

        6
  •  4
  •   Loren Pechtel    16 年前

    RobKennedy的答案表明strtodate解决方案本质上是不可能的,因为如果代码是在欧洲编译的,您不希望代码被破坏!

    我同意应该有一些方法来做编码日期,但没有。

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

        7
  •  4
  •   skamradt    16 年前

    一种解决方案是创建一个多年不变的列表,另一种方法是创建一个月偏移量的列表,然后动态地构建它。您必须自己处理闰年,在每个结果常量中添加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;
    

    编辑

    为了清晰起见,增加了几年,并增加了闰日常数。

        8
  •  3
  •   JosephStyons    16 年前

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

    不过,我的例子主要是为了好玩。实际上,这很荒谬。

    const
      MyDate = ((
               2009  //YEAR
                                              - 1900) * 365.25) + ((
               3     //MONTH
                                              - 1) * 30) +
               24    //DAY
               ;
    
        9
  •  1
  •   Ian Boyd    16 年前

    我想 这个 您可以使用的最佳解决方案是声明:

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

    [错误]应为常量表达式

    因此,即使它们是恒定的和确定性的(即不依赖于任何区域设置信息),它仍然不起作用。

        10
  •  0
  •   jeckp    6 年前

    类型“tdatetime”=类型“double”。

    算法:

    1. 使用 strToDateTime('01.01.1900 01:01:01') (或其他方式) 要计算,需要双倍的_值。('01.01.1900 01:01:01'=>2.04237268518519)

    2。 康斯特 dtziro:tdatetime=2.04237268518519;