Bad conversion from EndOfTheMonth(date) to Variant value - delphi

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.

Related

How to extract(parse) integers from a continuous string in Go Lang

I have very large(potentially endless) stream of integers similar to input below.
I intend to randomly access this slice and read from string one character at a time, and would like to access the integer represented by the character.
For the code below I was expecting intVal to be an integer value of 3. number[1] gives me the ASCII code for 3 which is 51.
input := "2345892345234502349502345234534234572304520345902384523045"
intVal,_ := strconv.Atoi(input[1])
Essentially, What is the proper way of reading integers from strings in Go ?
Use the following code to get the numeric value of the decimal number at input[i]:
b := input[i]
if b < '0' || b > '9' {
// not a decimal number
... handle error here
}
n := int(b) - '0'
You can read one rune at a time and convert to string:
for _,r:=range input {
str:=string(r)
}
Or access randomly:
str:=input[n:n+1]

Access 2016 formula

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

VB6 SCGrid Textbox

Within a VB6 form, I'm using an SCGrid object were the cells are editable by means of a textbox.
I suppose the grid control creates a TextBox object as soon as the user clicks a cell.
I need a reference to this TextBox.
In particular, when the user presses the [Left] or [Right] key, I need the current position of the cursor within the textbox. I can then simply call TextBox.SelStart.
Does anybody know how to get the control used when editing a cell?
I figured it out myself:
' Declaration needed for getting the current position of the cursor
Private Type Point
x As Long
y As Long
End Type
Private Declare Function GetCaretPos Lib "user32" (ByRef lpPoint As Point) As Long
' This function returns the position of the cursor within the cell currently being edited as a TextBox
' The value is expressed as the number of characters preceeding the position
Private Function GetCaretPosition() As Integer
' Variables
Dim position As Point
Dim result As Long
Dim contents As String
' Get position
result = GetCaretPos(position)
' Convert it into number of characters
' I figured out the factor 15 by trial and error
' Don't know where it comes from but it seems independent of the font size
contents = myGrid.Text(row_gvar, column_gvar)
result = 0
While ((result < Len(contents)) And _
(position.x > (grid_gvar.Parent.TextWidth(Left(contents, result)) / 15)))
result = result + 1
Wend
' Done
GetCaretPosition = result
End Function

Confusing of TTimeSpan usage in Delphi 2010

I tried the new Record type TTimeSpan in Delphi 2010. But I encourage a very strange problem.
assert(TTimeSpan.FromMilliseconds(5000).Milliseconds = 5000);
This assertion does not pass. The value of 'TTimeSpan.FromMilliseconds(5000).Milliseconds' is expected to be 5000, but it was 0.
I dig deeper:
function TTimeSpan.GetMilliseconds: Integer;
begin
Result := Integer((FTicks div TicksPerMillisecond) mod 1000);
end;
FTicks = 50000000
TicksPerMillisecond = 10000
FTick div TicksPerMillisecond = 50000000 div 10000 = 5000
(FTick div TicksPerMillisecond) mod 1000 = 5000 mod 1000 = 0 // I do not understand, why mod 1000
Integer((FTick div TicksPerMillisecond) mod 1000) = Integer(0) = 0
My code interpretation is correct, isn't it?
UPDATE: The method GetTotalMilliseconds (double precision) is implemented correctly.
You are confusing the properties giving the total amount expressed in a given unit with the properties giving the portion of a value when you break it up into its components (days, hours, minutes, seconds, milliseconds, ticks).
With those, you get the integer remainder for each category. So, Milliseconds will always be between 0 and 999 (Number Of Milliseconds Per Second - 1).
Or, another example, if you have 72 minutes, TotalMinutes is 72, but Minutes is 12.
It is very much similar to the DecodeDateTime function to break up a TDateTime.
And for what you want to achieve, you definitely need to use the TotalMilliseconds property, as TridenT pointed out, but the code for GetMilliseconds is indeed correct in TimeSpan.
You must use TotalMilliseconds instead of Milliseconds property.
It works better !
assert(TTimeSpan.FromMilliseconds(5000).TotalMilliseconds = 5000);
From documentation:
TotalMilliseconds Double
Timespan expressed as milliseconds and
part milliseconds

Declare a TDateTime as a Const in Delphi

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

Resources