Round TTime to nearest 15 minutes - delphi

I have the following function which I'm led to believe should round time to nearest 15 minutes.
function TdmData.RoundTime(T: TTime): TTime;
var h, m, s, ms : Word;
begin
DecodeTime(T, h, m, s, ms);
m := (m div 15) * 15;
s := 0;
Result := EncodeTime(h, m, s, ms);
end;
To test the function I have put a tbutton and a tedit on a form and at the click of the button I do:
begin
Edit1.Text := RoundTime('12:08:27');
end;
I get an error when compiling : 'Incompatible types TTime and string'
Any help with this would be great.
Thanks,

The error which causes the compilation failure is that you are passing a string to a function which needs a TTime as a parameter.
Once this is fixed, Edit1.Text needs a string type but your function returns TTime.
Using StrToTime and TimeToStr you can obtain the desired conversion from and to a string type.
Your function can be called like this:
begin
Edit1.Text := TimeToStr(RoundTime(StrToTime('12:08:27'));
end;
Stealing the gabr user's answer - In Delphi: How do I round a TDateTime to closest second, minute, five-minute etc? - you can obtain a date rounded to an arbitrary nearest value assigned to the interval parameter:
function RoundToNearest(time, interval: TDateTime): TDateTime;
var
time_sec, int_sec, rounded_sec: int64;
begin
time_sec := Round(time * SecsPerDay);
int_sec := Round(interval * SecsPerDay);
rounded_sec := (time_sec div int_sec) * int_sec;
if ((rounded_sec + int_sec - time_sec) - (time_sec - rounded_sec)) > 0 then
rounded_sec := rounded_sec + time_sec + int_sec;
Result := rounded_sec / SecsPerDay;
end;
begin
Edit1.Text := TimeToStr(RoundToNearest(StrToTime('12:08:27'), StrToTime('0:0:15')));
end;

Related

Logarithmic-linear value conversion

The code below draws a logarithmic grid with DrawGrid(). It seems the vertical lines are ok.
When I use the function SetPositionHzValue() the resulting position seems ok (it uses the same logic as the DrawGrid() and seems to match the grid).
But how to convert this 0 - 1.0 normalized value, that uses the display width linearly, to an actual Hz value? Why is the function GetPositionsHzValue() wrong?
To complicate things, the display has a start frequency (20 Hz in this case) and an end frequency (44100 Hz in this case).
procedure TAudioBezierCurves.DrawGrid(Bitmap32: TBitmap32);
var
GridPosition: Integer;
GridPositionF: Double;
i: Integer;
Base: Double;
LogOffsetValue: Double;
LogMaxValue: Double;
begin
GridPosition := 0;
Base := 1;
if GridFrequencyMin = 0 then begin
LogOffsetValue := 0;
end else begin
LogOffsetValue := Log10(GridFrequencyMin);
end;
LogMaxValue := Log10(GridFrequencyMax) - LogOffsetValue;
repeat
for i := 2 to 10 do begin
if Base * i < GridFrequencyMin then begin
Continue;
end;
//* This gives the % value relative to the total scale
GridPositionF := (Log10(Base * i) - LogOffsetValue) / LogMaxValue;
GridPositionF := GridPositionF * Bitmap32.Width;
GridPosition := Trunc(GridPositionF);
Bitmap32.VertLineS(GridPosition, 0, Bitmap32.Height - 1, GridColor);
end;
Base := Base * 10;
until GridPosition > Bitmap32.Width;
end;
procedure TAudioBezierCurve.SetPositionHzValue(AValue: Double);
var
LogOffsetValue: Double;
LogMaxValue: Double;
begin
if AValue = 0 then begin
Self.Position := 0;
end else begin
if Parent.GridFrequencyMin = 0 then begin
LogOffsetValue := 0;
end else begin
LogOffsetValue := Log10(Parent.GridFrequencyMin);
end;
LogMaxValue := Log10(Parent.GridFrequencyMax) - LogOffsetValue;
//* This gives the % value relative to the total scale
AValue := (Log10(AValue) - LogOffsetValue) / LogMaxValue;
Self.Position := AValue;
end;
end;
function TAudioBezierCurve.GetPositionsHzValue: Double;
var
AValue: Double;
begin
AValue := Self.Position;
AValue := Power(AValue, 2);
Result := AValue * (Parent.GridFrequencyMax);
Result := Result - (AValue * Parent.GridFrequencyMin) + Parent.GridFrequencyMin;
end;
EDIT: Ok, almost ok now. So it seems the correct function is:
AValue := Power(AValue, 10);
But still not perfect. Changing the display range to min. 0 to 44100, for simplicity, results that setting to the upper value 44100 is ok, the function GetPositionsHzValue() report 41100. But calling setting the position value to 20, GetPositionsHzValue() reports 0.
Trying to decrement the position all is fine until 44085, but 44084 value is reported as 44085 and this difference increases with smaller values. Going from lower values, it's 0 until 39, 40 results 1.
In function GetPositionsHzValue, line "AValue := Power(AValue, 2);" where does the value of "AValue" come from?
Maybe you should do something like you did in "SetPositionHzValue(AValue: Double);". AValue should be a parameter, not a local variable.
Found the solution, it should be:
function TAudioBezierCurve.GetPositionsHzValue: Double;
var
AValue: Double;
begin
AValue := Self.Position;
AValue := AValue * Log10(Parent.GridFrequencyMax) + (Log10(Parent.GridFrequencyMin) * (1 - AValue)); //* Results "min." at 0
Result := Power(10, AValue);
end;

Delphi How To Convert String To Binary Using Only Pascal [duplicate]

This question already has answers here:
Converting decimal/integer to binary - how and why it works the way it does?
(6 answers)
Closed 4 years ago.
I have done some Example to convert a string to binary but i couldn't find a way to walk on each character in the string and complete the whole calculations process and then step to the next character in the string, Here is my code:
var i,j, rest, results :integer;
restResult : string;
begin
results := 1;
for i := 1 to length(stringValue) do
begin
while (results > 0) do
begin
results := ord(stringValue[i]) div 2;
rest := ord(stringValue[i]) mod 2;
restResult := restResult + inttostr(rest);
end;
end;
// Get The Rests Backwards
for i := length(restResult) downto 1 do
begin
result := result + restResult[i];
end;
The application always get into infinite loop, any suggestions?
Your results := ord(stringValue[i]) div 2; remains the same, because stringValue[i] does not change, so while loop is infinite.
To solve this mistake:
for i := 1 to length(stringValue) do
begin
t := ord(stringValue[i]);
repeat
restResult := restResult + inttostr(t mod 2);
t := t div 2;
until t = 0;
end;
But note that you cannot divide resulting string into pieces for distinct chars, because length of binary representation will vary depending on char itself.
This is example of code with fixed length for representation of char (here AnsiChar):
function AnsiStringToBinaryString(const s: AnsiString): String;
const
SBits: array[0..1] of string = ('0', '1');
var
i, k, t: Integer;
schar: string;
begin
Result := '';
for i := 1 to Length(s) do begin
t := Ord(s[i]);
schar := '';
for k := 1 to 8 * SizeOf(AnsiChar) do begin
schar := SBits[t mod 2] + schar;
t := t div 2
end;
Result := Result + schar;
end;
end;
'#A z': (division bars are mine)
01000000|01000001|00100000|01111010
# A space z

Pascal, how to mark an integer into money value

How can I mark an integer into thousands and hundreds?
Just say I have an integer 12345678910, then I want to change it into a money value like 12.345.678.910.
I try the following code but it is not working.
procedure TForm1.Button1Click(Sender: TObject);
var
j,iPos,i, x, y : integer;
sTemp, original, hasil, data : string;
begin
original := edit1.Text;
sTemp := '';
j := length(edit1.Text);
i := 3;
while i < j do
begin
insert('.',original, (j-i));
edit1.Text := original;
j := length(edit1.Text);
for x := 1 to y do
begin
i := i + ( i + x );
end;
end;
edit2.Text := original;
There is System.SysUtils.Format call in Delphi http://docwiki.embarcadero.com/Libraries/Tokyo/en/System.SysUtils.Format.
This call understand 'm' character as money specific formatter.
Try code like this:
Value := 12345678910;
FormattedStr := Format('Money = %m', [Value])
By default Format will use systemwide format settings, if you have to override default system settings, see official docs:
The conversion is controlled by the CurrencyString, CurrencyFormat,
NegCurrFormat, ThousandSeparator, DecimalSeparator, and
CurrencyDecimals global variables or their equivalent in a
TFormatSettings data structure. If the format string contains a
precision specifier, it overrides the value given by the
CurrencyDecimals global variable or its TFormatSettings equivalent.
This function does what you specify:
function FormatThousandsSeparators(Value: Int64): string;
var
Index: Integer;
begin
Result := IntToStr(Value);
Index := Length(Result) - 3;
while Index > 0 do
begin
Insert('.', Result, Index + 1);
Dec(Index, 3);
end;
end;
Note that your example 12345678910 does not fit into a 32 bit signed integer value which is why I used Int64.
This function does not handle negative values correctly. For instance, it returns '-.999' when passed -999. That can be dealt with like so:
function FormatThousandsSeparators(Value: Int64): string;
var
Index: Integer;
Negative: Boolean;
begin
Negative := Value < 0;
Result := IntToStr(Abs(Value));
Index := Length(Result) - 3;
while Index > 0 do
begin
Insert('.', Result, Index + 1);
Dec(Index, 3);
end;
if Negative then
Result := '-' + Result;
end;
i know now, its so simple. just use
showMessage(formatFloat('#.###.00', strToFloat(original)));
but thanks Remy, you opened my mind.

Which number is closer

How can i find out which number is closer? say my value is "1" and i have two var, A:= 1.6 and b:=1.001
currently looking at a few numbers and taking a 0.1% +/- difference and a +/- 0.6 difference.. i just need to see which answer is closer to the starting value.. code so far..
Also nothing to big, the code is just to stop me from doing them all manually :D
procedure TForm1.Button1Click(Sender: TObject);
var
winlimit,test6high,test6low,test6,test1high,test1low,test1,value: double;
begin
value := 1.0;
while value < 1048567 do
begin
test6high := value + 0.6 ;
test6low := value - 0.6 ;
test1high := (-0.1 * value)/100;
test1high := value - test1high;
test1low := (0.1 * value)/100;
test1low := value - test1low;
memo1.Lines.Add('value is '+floattostr(value)+': 1% High:'+floattostr(Test1high)+' 1% Low:'+floattostr(Test1low));
memo1.Lines.Add('value is '+floattostr(value)+': 0.6 +/- '+floattostr(Test6high)+' 0.6 Low:'+floattostr(Test6low));
memo1.Lines.Add(' ');
value := value*2;
end
end;
I think you mean a function like this:
function ClosestTo(const Target, Value1, Value2: Double): Double;
begin
if abs(Target-Value1)<abs(Target-Value2) then
Result := Value1
else
Result := Value2;
end;
If you use IfThen from the Math unit you can write it more concisely:
function ClosestTo(const Target, Value1, Value2: Double): Double;
begin
Result := IfThen(abs(Target-Value1)<abs(Target-Value2), Value1, Value2);
end;

How to calculate min, max and average values of selected cells in a string grid?

I'm using Delphi XE3 and I'm developing an application to read numerical type cells from Excel. I'm using TStringGrid for this import.
I already know, how to get them to the string grid, but can't manage to do any mathmatical functions like in Excel. How do I calculate min, max and average values for selected cell values of my string grid ?
You can try the following function. It returns the count of numeric values found in the current string grid's selection. To declared parameters passed to it returns minimum, maximum and average values from the current selection's numeric values (if there are some):
uses
Math;
function CalcStats(AStringGrid: TStringGrid; var AMinValue, AMaxValue,
AAvgValue: Double): Integer;
var
Col, Row, Count: Integer;
Value, MinValue, MaxValue, AvgValue: Double;
begin
Count := 0;
MinValue := MaxDouble;
MaxValue := MinDouble;
AvgValue := 0;
for Col := AStringGrid.Selection.Left to AStringGrid.Selection.Right do
for Row := AStringGrid.Selection.Top to AStringGrid.Selection.Bottom do
begin
if TryStrToFloat(AStringGrid.Cells[Col, Row], Value) then
begin
Inc(Count);
if Value < MinValue then
MinValue := Value;
if Value > MaxValue then
MaxValue := Value;
AvgValue := AvgValue + Value;
end;
end;
Result := Count;
if Count > 0 then
begin
AMinValue := MinValue;
AMaxValue := MaxValue;
AAvgValue := AvgValue / Count;
end;
end;
Here's a sample usage:
procedure TForm1.Button1Click(Sender: TObject);
var
MinValue, MaxValue, AvgValue: Double;
begin
if CalcStats(StringGrid1, MinValue, MaxValue, AvgValue) > 0 then
Label1.Caption :=
'Min. value: ' + FloatToStr(MinValue) + sLineBreak +
'Max. value: ' + FloatToStr(MaxValue) + sLineBreak +
'Avg. value: ' + FloatToStr(AvgValue)
else
Label1.Caption := 'There is no numeric value in current selection...';
end;
Another chapter is how to get notification when the selection of a string grid changes. There's no event nor virtual method for implementing event like OnSelectionChange. But that would be topic for another question.

Resources