Confusing of TTimeSpan usage in Delphi 2010 - delphi

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

Related

vala: is this the correct way to get the current time in milliseconds ?

Using this library with Vala :
http://valadoc.org/#!api=glib-2.0/GLib.DateTime
GLib.DateTime now = new GLib.DateTime.now_local();
var sec = now.to_unix()
var msec = (sec * 1000) + now.get_microsecond();
is this the correct way to get the current time in millisecond ?
is there a better way ?
GLib.DateTime is a valid way of doing this, and it's a bit weird that you're requesting a local time then converting it to unix time (which implicitly converts to UTC). The real problem, though, is that you're conflating milliseconds (1/1000th of a second) and microseconds (1/1000000th of a second). So change the last line to
var msec = (sec * 1000) + (now.get_microsecond () / 1000);
Alternatively, an easier way would be to use GLib.get_real_time:
int64 msec = GLib.get_real_time () / 1000;
Depending on your use case you might want to consider using monotonic time instead of real time (see GLib.get_monotonic_time

getTickCount time unit confusion

At the answer to the question on Stack and in the book at here on page 52 I found the normal getTickCount getTickFrequency combination to measure time of execution gives time in milliseconds . However the OpenCV website says its time in seconds. I am confused. Please help...
There is no room for confusion, all the references you have given point to the same thing.
getTickCount gives you the number of clock cycles after a certain event, eg, after machine is switched on.
A = getTickCount() // A = no. of clock cycles from beginning, say 100
process(image) // do whatever process you want
B = getTickCount() // B = no. of clock cycles from beginning, say 150
C = B - A // C = no. of clock cycles for processing, 150-100 = 50,
// it is obvious, right?
Now you want to know how many seconds are these clock cycles. For that, you want to know how many seconds a single clock takes, ie clock_time_period. If you find that, simply multiply by 50 to get total time taken.
For that, OpenCV gives second function, getTickFrequency(). It gives you frequency, ie how many clock cycles per second. You take its reciprocal to get time period of clock.
time_period = 1/frequency.
Now you have time_period of one clock cycle, multiply it with 50 to get total time taken in seconds.
Now read all those references you have given once again, you will get it.
dwStartTimer=GetTickCount();
dwEndTimer=GetTickCount();
while((dwEndTimer-dwStartTimer)<wDelay)//delay is 5000 milli seconds
{
Sleep(200);
dwEndTimer=GetTickCount();
if (PeekMessage (&uMsg, NULL, 0, 0, PM_REMOVE) > 0)
{
TranslateMessage (&uMsg);
DispatchMessage (&uMsg);
}
}

Bad conversion from EndOfTheMonth(date) to Variant value

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.

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

SetRoundMode(rmUp) and rounding "round" values like 10, results in 10,0001 how come?

This code:
SetRoundMode(rmUp);
Memo1.Lines.Add(CurrToStr(SimpleRoundTo(10)));
Results in 10,0001.
I simply don't get it.
I thought that rmUp would do something like, round 10,0001 to 11, but never 10 to 10,0001.
Can anyone explain why this happens?
Thanks.
SimpleRoundTo works like this:
Divide the input value by 10-x, where x is the number of decimal places to preserve in the result.
Add 0.5 to that product.
Truncate the sum.
Multiply by 10-x.
The result is a floating-point value. As with most floating-point values, the result will not be exact, even though in your case you start with an exact value. The number of decimal places specified for SimpleRoundTo is negative, so the divisor in step 1, for your example input, will ideally be 0.01. But that can't be represented exactly as a floating-point number, so when 10 / 0.01 is calculated in step 1, the result is not exactly 1000. The result in step 3 will be exactly 1000, though, so the inexactness of the division isn't important. The inexactness of the multiplication in step 4 is, though. That product won't be exact. It will be slightly higher than 10.
So SimpleRoundTo returns a slightly higher value, and since you've specified that rounding should go up, the conversion of the Extended result of SimpleRoundTo to the Currency input of CurrToStr results in exactly 10.0001.
Currency values are exact; they represent a fixed-point value, an integer scaled by four decimal places.
i'd use the Round( ) function if banker's rounding is ok. it returns an integer.
if you don't like banker's rounding you can use this:
// use this to not get "banker's rounding"
function HumanRound(X: Extended): integer;
// Rounds a number "normally": if the fractional
// part is >= 0.5 the number is rounded up (see RoundUp)
// Otherwise, if the fractional part is < 0.5, the
// number is rounded down
// RoundN(3.5) = 4 RoundN(-3.5) = -4
// RoundN(3.1) = 3 RoundN(-3.1) = -3
begin
// Trunc() does nothing except conv to integer. needed because return type of Int() is Extended
Result := Trunc(Int(X) + Int(Frac(X) * 2));
end;
my posting here is somewhat off-topic but still informative.
i looked into this at length since i needed to not be using banker's rounding. here are my findings. so far as i can see, this still doesn't get rid of banker's rounding
Value Meaning
rmNearest Rounds to the closest value.
rmDown Rounds toward negative infinity.
rmUp Rounds toward positive infinity.
rmTruncate Truncates the value, rounding positive numbers down and negative numbers up.
rmNearest // default
0.500 0
1.500 2
2.450 2
2.500 2
2.550 3
3.450 3
3.500 4
3.550 4
rmDown
0.500 0
1.500 1
2.450 2
2.500 2
2.550 2
3.450 3
3.500 3
3.550 3
rmUp
0.500 1
1.500 2
2.450 3
2.500 3
2.550 3
3.450 4
3.500 4
3.550 4
rmTrunc
0.500 0
1.500 1
2.450 2
2.500 2
2.550 2
3.450 3
3.500 3
3.550 3
uses
math, sysutils, clipbrd;
var
s:string;
procedure trythis(sMode:string);
procedure tryone(d:double);
begin
s:=s+Format('%1.3f %d%s',[d,Round(d),#13+#10]);
end;
begin
s:=s+#13#10+sMode+#13#10;
tryone(0.50);
tryone(1.50);
tryone(2.45);
tryone(2.50);
tryone(2.55);
tryone(3.45);
tryone(3.50);
tryone(3.55);
end;
begin
s:=inttostr(integer(GetRoundMode));
SetRoundMode(rmNearest);
trythis('nearest');
SetRoundMode(rmDown);
trythis('down');
SetRoundMode(rmUp);
trythis('up');
SetRoundMode(rmTruncate);
trythis('trunc');
clipboard.astext:=s;
end.
The return values from calculation SimpleToRound is also a Double and they can never be trusted on rounding. Truncate the value before converting it should do the work!
Memo1.Lines.Add(CurrToStr(Trunc(SimpleRoundTo(10))));
The Ceil() : Integer function should give you the answer you want for values > 0. If < 0 you may need to use floor() instead, depending on desired behaviour.

Resources