Reputation: 38703
As far as I know there is no way to do this, but I am going to ask just in case someone else knows how to do this. How can I declare a date as a const in Delphi?
The only solution I have found is to use the numeric equivalent, which is kind of a pain to maintain because it is not human readable.
const
Expire : TDateTime = 39895; // Is actually 3/23/2009
What I would like to be able to do is something like this:
const
Expire : TDateTime = TDateTime ('3/23/2009');
or
const
Expire : TDateTime = StrToDate('3/23/2009');
So let me know if this is a feature request or if I just missed how to do this (yeah, I know it seems like an odd thing to want . . . .)
Upvotes: 31
Views: 13525
Reputation: 11
System.DateUtils has constants for each part of time.
const cDT : TDateTime = (12 * OneHour) + ( 15 * OneMinute)
+ (33 * OneSecond) + (123 * OneMillisecond);
Upvotes: 1
Reputation: 21
The type "TDateTime" = type "Double".
Algorithm:
2.const DTZiro: TDateTime = 2.04237268518519;
Upvotes: 1
Reputation: 14832
I tend to simulate const dates with a function. Technically they're a little more constant than the "pseudo-constant" assignable typed const's.
function Expire: TDateTime;
begin
Result := EncodeDate(2009, 3, 23);
end;
NOTE the use of EncodeDate
rather than StrToDate
. StrToDate
is affected by regional settings meaning there's no guarantee a string will be interpreted as would be expected.
For example, did you know that there's a strange a group of people who think it makes sense to "shuffle" date parts into an inconsistent order of significance? They use middle, then least, then most significant part (e.g. '3/23/2009') <cheeky grin>. The only time that logic makes sense is when you turn 102 years old - then you can claim your age is 021.
For the premature optimisers out there, if the function is called so frequently that the nano seconds required to encode a date becomes an issue - you have a far bigger problem than this minor inefficiency in the name of readable, maintainable code.
Upvotes: 11
Reputation: 256671
i think the best solution available to you is to declare:
ArmisticeDay: TDateTime = 6888.0 + (11.0/24.0); //Nov 11, 1918 11 AM
and just accept it.
My attempt Nº1
Expire = EncodeDate(2009, 3, 23);
[Error] Constant expression expected
My attempt Nº2
Expire: TDateTime = EncodeDate(2009, 3, 23);
[Error] Constant expression expected
So even though they're constant, and deterministic (i.e. do not depend on any locale information), it still doesn't work.
Upvotes: 1
Reputation: 24086
Ok, my reaction is a bit late, but here's a solution for the newer Delphi's.
It uses implicit class overloaders so that records of this type can be used as if they are TDateTime variables.
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;
Implementation:
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;
Now you can declare your dates like this:
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);
To see if it works, execute the following:
ShowMessage(Date1); // it can act like a string
ShowMessage(DateToStr(Date1)); // it can act like a date
If you really want to replace all your TdateTime variables with this, you probably need to overload some other operators too (Add, subtract, explicit, ...).
Upvotes: 23
Reputation: 15538
One solution would be to create a list of constants for years, another for month offsets and then build it on the fly. You would have to take care of leap years yourself by adding 1 to each resulting constant. Just a few below to get you started... :)
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;
If you have a leap year then you have to add 1 to anything beyond february of that year.
Const
Expire : tDateTime = Year_2008 + Month_Mar + 23 + Leap_Day;
EDIT
Added a few more years for clarity, and added a Leap_Day constant.
Upvotes: 4
Reputation: 7062
The only? possible way, but probably not what you are looking for:
const
{$J+}
Expire: TDateTime = 0;
{$J-}
initialization
Expire := EncodeDate(2009, 3, 23);
Upvotes: 12
Reputation: 58685
A Delphi date is the # of days since Dec 30, 1899. So you could probably come up with an elaborate mathematical formula to express a date as a const. Then you could format it very oddly, to emphasize the human-readable parts. My best attempt is below, but it is very much incomplete; for one thing, it assumes that all months have 30 days.
My example is mostly for fun though. In practice, this is pretty ridiculous.
const
MyDate = ((
2009 //YEAR
- 1900) * 365.25) + ((
3 //MONTH
- 1) * 30) +
24 //DAY
;
Upvotes: 3
Reputation: 21640
There is no way to do this because interpreting a date litteral in itself is not deterministic, it depends on the convention/locale you follow.
'1/4/2009' is not in January for any French person for instance, and having the compiler translating as January 4th would make it a fool's compiler ;-)
Unless the compiler implements some (well documented) "magic" bijective function for pairing a date value and a display representation... And anyway, half of the planet would not like it.
The only non ambiguous way I see now is to provide the value even if it looks like a pain...
... my $0.02
Upvotes: 8
Reputation: 9093
Rob Kennedy's answer shows that the StrToDate solution is inherently out of the question as you don't want your code to break if it's compiled in Europe!
I do agree there should be some way to do EncodeDate but there isn't.
As far as I'm concerned the compiler should simply compile and run any code it finds in a constant assignment and store the result into the constant. I'd leave it up to the programmer to ensure the code isn't sensitive to it's environment.
Upvotes: 4
Reputation: 163277
No, Delphi doesn't support that.
Your first idea would be a request for date-time literals distinct from ordinary floating-point literals. I found QC 72000, which is about displayingTDateTime
values as dates in the debugger, but nothing about your particular request. It's not like nobody's ever mentioned it before, though. It's a perennial topic on the newsgroups; I just can't find anything in QC about it.
Your second idea would require StrToDate
to be evaluable at compile time. I don't see any entries in QC about it either, but for what it's worth, C++ is getting such a feature for functions that are shown to have the necessary qualities. StrToDate
wouldn't meet those requirements, though, because it's sensitive to the current locale's date settings.
Upvotes: 6