Let's say I have the following SQL statement:
SELECT 1 + myField + 2
If we want to reduce the expression at the parsing phase before sending it to SQL, we could turn it into:
SELECT 3 + myField
What is the name of the rule that allows this? Another example being:
SELECT myField * (1 + myField * 2 + 3)
Would turn into:
SELECT myField * (4 + (myField * 2) )
That's usually called "constant folding" (which should be a good search term) and it's easier to do as a transformation on the AST than trying to do it while you parse, precisely because of the reordering which is evident in your examples.
sometimes toString(datetime()) return the milliseconds without the leading zeros to reach the length of 3 (yyyy-MM-dd'T'HH:mm:ss.SSSXXX). Is it a bug or normal behavior?
For example:
2019-11-21T15:59:22.53Z -> it should be 2019-11-21T15:59:22.053Z
2019-11-21T15:59:21.216Z -> OK
2019-11-21T15:30:09.042Z -> OK
This behavior causes an issue when I try to convert the string into a date.
Thank you
Try using the apoc.temporal.format function, specifying the iso_instant type conversion.
For example:
RETURN apoc.temporal.format(datetime("2019-11-21T22:04:19.13Z"), 'iso_instant');
will return:
"2019-11-21T22:04:19.130Z"
[UPDATE]
Since the TOSTRING() function is not documented to return any particular ISO 8601 string format for a datetime, one should not depend on it returning a specific format -- or even returning the same string for the same datetime across versions.
However, if you want a non-APOC approach that works with recent versions of neo4j (like, 3.5.12, on which this was tested), here is an example of one way to modify the current TOSTRING() output string to always have a 3-digit millisecond value:
// Generate a string.
// You can play with the number of digits after ".", and
// even eliminate the "." and any following digits.
WITH TOSTRING(datetime("2019-11-21T22:04:10.1Z")) AS d
// Always return a 3-digit millisecond time in result
WITH d, LENGTH(d) AS lth
RETURN d, CASE WHEN lth < 24
THEN SUBSTRING(d, 0, lth-1) + SUBSTRING('.000Z', lth - 20)
ELSE d END AS result
Learning Access recently but find myself suck on a particular formula.
I've been trying to find a way to calculate the number of years since a employee's hire date and a specific date in place of today.
I searched and tried a few Datediff and DATEDIF with no luck just get negative results if any. Any help is greatly appreciated.
That's because it isn't that easy and there are some traps, indeed if you wish to count correctly taking leap years into account.
The trick is to always use DateAdd as in this function:
Public Function Years( _
ByVal datDate1 As Date, _
ByVal datDate2 As Date, _
Optional ByVal booLinear As Boolean) _
As Integer
' Returns the difference in full years between datDate1 and datDate2.
'
' Calculates correctly for:
' negative differences
' leap years
' dates of 29. February
' date/time values with embedded time values
' negative date/time values (prior to 1899-12-29)
'
' Optionally returns negative counts rounded down to provide a
' linear sequence of year counts.
' For a given datDate1, if datDate2 is decreased step wise one year from
' returning a positive count to returning a negative count, one or two
' occurrences of count zero will be returned.
' If booLinear is False, the sequence will be:
' 3, 2, 1, 0, 0, -1, -2
' If booLinear is True, the sequence will be:
' 3, 2, 1, 0, -1, -2, -3
'
' If booLinear is False, reversing datDate1 and datDate2 will return
' results of same absolute Value, only the sign will change.
' This behaviour mimics that of Fix().
' If booLinear is True, reversing datDate1 and datDate2 will return
' results where the negative count is offset by -1.
' This behaviour mimics that of Int().
' DateAdd() is used for check for month end of February as it correctly
' returns Feb. 28. when adding a count of years to dates of Feb. 29.
' when the resulting year is a common year.
'
' 2007-06-22. Gustav Brock, Cactus Data, CPH.
Dim intDiff As Integer
Dim intSign As Integer
Dim intYears As Integer
' Find difference in calendar years.
intYears = DateDiff("yyyy", datDate1, datDate2)
' For positive resp. negative intervals, check if the second date
' falls before, on, or after the crossing date for a full 12 months period
' while at the same time correcting for February 29. of leap years.
If DateDiff("d", datDate1, datDate2) > 0 Then
intSign = Sgn(DateDiff("d", DateAdd("yyyy", intYears, datDate1), datDate2))
intDiff = Abs(intSign < 0)
Else
intSign = Sgn(DateDiff("d", DateAdd("yyyy", -intYears, datDate2), datDate1))
If intSign <> 0 Then
' Offset negative count of years to continuous sequence if requested.
intDiff = Abs(booLinear)
End If
intDiff = intDiff - Abs(intSign < 0)
End If
' Return count of years as count of full 12 months periods.
Years = intYears - intDiff
End Function
Typical usage:
HiredYears = Years([HireDate], #12/31/2017#)
Note, that for someone hired at the 1st of a month, a full year of employment will be counted at the next 1st of that month, so the expression may rather be:
HiredYears = Years([HireDate], #1/1/2018#)
I have a TDateTime value (that I get as result from EndOfTheMonth(date)) to a variant type. The result is wrongly rounded. Let's have a look at example:
data := EndOfTheMonth(date);
V := data;
ShowMessage(DateTimeToStr(data) + ' vs ' + VarToStr(V));
// output is
// data = 2012-01-31 23:59:59
// v = 2012-02-01 // why next day?
Is it designed behaviour?
How to work around this?
ShowMessage(DateTimeToStr(data) + ' vs ' + DateTimeToStr(VarToDateTime(V)));
Update: I would guess the problem is that the last millisecond of the month is very close to 0:00:00 the next day, that is, the TDateTime value (which is basically a double) is very close to an integer (e.g. 41029.9999999884 is very close to 41029) and so the VarToStr function assumes the decimals to be numerical fuzz.
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 . . . .)
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, ...).
The only? possible way, but probably not what you are looking for:
const
{$J+}
Expire: TDateTime = 0;
{$J-}
initialization
Expire := EncodeDate(2009, 3, 23);
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.
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
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.
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.
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.
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
;
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.
The type "TDateTime" = type "Double".
Algorithm:
Use StrToDateTime('01.01.1900 01:01:01') (or other way) to calculate need double_value. ('01.01.1900 01:01:01' => 2.04237268518519)
2.const
DTZiro: TDateTime = 2.04237268518519;
System.DateUtils has constants for each part of time.
const cDT : TDateTime = (12 * OneHour) + ( 15 * OneMinute)
+ (33 * OneSecond) + (123 * OneMillisecond);