Is possible to convert
'Thu Jul 17 17:20:38 2014'
with this function? Tried my best, but no result. This format uses justin.tv API, for twitch.tv i use code below and it works. Thanks for help.
var
t1, t2: Tdate;
dzien: integer;
begin
t1 := StrToDateTime('"2014-07-21T12:49:08Z"');
t2 := TTimeZone.Local.ToUniversalTime(Now);
dzien := trunc(t2 - t1);
if dzien > 0 then
Result := (Format('%d days, %s', [dzien, FormatDateTime('hh:nn:ss',
Frac(t2 - t1))]))
else
Result := (Format('%s', [FormatDateTime('hh:nn:ss', Frac(t2 - t1))]));
end;
It is easy enough to parse the string yourself. Like this:
uses
Types, SysUtils, DateUtils, StrUtils;
function DecodeJustinTvDateTime(const Value: string): TDateTime;
function MonthNumber(const MonthStr: string): Integer;
var
FormatSettings: TFormatSettings;
begin
FormatSettings := TFormatSettings.Create('en-us');
for Result := low(FormatSettings.ShortMonthNames) to high(FormatSettings.ShortMonthNames) do begin
if SameText(MonthStr, FormatSettings.ShortMonthNames[Result]) then begin
exit;
end;
end;
raise EConvertError.Create('Unrecognised month name');
end;
var
items: TStringDynArray;
Day, Month, Year, Time, Hour, Minute, Second: string;
begin
items := SplitString(Value, ' ');
if Length(items)<>5 then begin
raise EConvertError.Create('Unrecognised date time format');
end;
// items[0] is day of the week which we can ignore
Month := items[1];
Day := items[2];
Time := items[3];
Year := items[4];
items := SplitString(Time, ':');
Assert(Length(items)=3);
if Length(items)<>3 then begin
raise EConvertError.Create('Unrecognised time format');
end;
Hour := items[0];
Minute := items[1];
Second := items[2];
Result := EncodeDateTime(
StrToInt(Year),
MonthNumber(Month),
StrToInt(Day),
StrToInt(Hour),
StrToInt(Minute),
StrToInt(Second),
0
);
end;
The error checking here is a little lame and you might care to improve on it.
procedure TForm6.Button1Click(Sender: TObject);
var
t1: TDateTime;
ts:TFormatSettings;
begin
ts:=TFormatSettings.Create;
ts.ShortDateFormat:='yyyy-MM-dd';
ts.DateSeparator:='-';
ts.TimeSeparator:=':';
t1 := StrToDateTime('2014-07-21T12:49:08Z',ts);
end;
t1 contains date and time from your string.
Related
how does one change the value of the type of currency? I am getting $ for my currency when i need R.
procedure TfrmFinal.addSubtractTotal;
var
total: currency;
begin
total := 0;
frmDataModule.tblpins.First;
while not frmDataModule.tblpins.Eof do
begin
total := total +
frmDataModule.tblpins.FieldByName('qty').AsInteger *
frmDataModule.tblpins.FieldByName('price').AsCurrency;
frmDataModule.tblpins.Next;
end;
totalAmmountLabel.Text := total.ToString;
end;
There are a few ways to solve this. Unfortunately, I don't have the TCurrencyHelper, but here are a few other options:
procedure TForm1.Button1Click(Sender: TObject);
var Total: Currency;
begin
Total := 155;
var FormatSettings := TFormatSettings.Create(7177); //LCID for South Africa, MAY not be necessary if that is the local setting on the machines you are supporting
button1.Caption := FloatToStrF(Total, ffCurrency, 15,2, FormatSettings);
button1.Caption := FormatCurr('', Total, FormatSettings);
button1.Caption := CurrToStr(Total, FormatSettings);
button1.Caption := CurrToStrF(Total,ffCurrency,2,FormatSettings);
end;
All of them are slightly different. My preference would be CurrToStrF (which then calls FloatToStrF), but that is just out of habit.
I'm trying to count down to a time of the day (24-hour clock format). This is my solution so far:
function TimeDiffStr(const s1, s2: string): string;
var
t1, t2: TDateTime;
secs: Int64;
begin
t1 := StrToDateTime(s1);
t2 := StrToDateTime(s2);
secs := SecondsBetween(t1, t2);
Result := Format('%2.2d:%2.2d:%2.2d', [secs div 3600, (secs div 60) mod 60, secs mod 60]);
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var
TargetTime: TTime;
s: string;
begin
s := TimeDiffStr(TimeToStr(Now), TimeToStr(TargetTime));
end;
If Now is, for example, 15:35:02 and the target time is 21:44:59, the output is correct (06:09:57). However, if Now is 15:35:02 and the target time is 01:32:23, instead of counting down from 09:57:21, it will count upwards, because the function does not know that the target time is on a different day.
How can I work out the difference between two times when the times are on different days?
First off, there is no need to pass strings around. If you start with TTime and convert to TTime, then simply pass TTime around.
Second, since you are dealing with just time values, if the target time is meant to be on the next day, you need to add 24 hours so that you have a TDateTime that actually represents the next day.
Try this:
uses
..., DateUtils;
function TimeDiffStr(const t1, t2: TTime): string;
var
d1, d2: TDateTime;
secs: Int64;
begin
d1 := t1;
if t2 < t1 then
d2 := IncDay(t2) // or IncHour(t2, 24)
else
d2 := t2;
secs := SecondsBetween(d1, d2);
Result := Format('%2.2d:%2.2d:%2.2d', [secs div 3600, (secs div 60) mod 60, secs mod 60]);
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var
TargetTime: TTime;
s: string;
begin
TargetTime := ...;
s := TimeDiffStr(Time(), TargetTime);
end;
I have two TDateTime variables, like this:
s := StrToDateTime('03/03/2017 10:10:12');
e := StrToDateTime('04/04/2017 10:10:12');
I need to find out the difference between them, in hh:mm:ss format.
The ...Between() functions are not helping me here.
Use the DateUtils.SecondsBetween function:
Uses
DateUtils,SysUtils;
function TimeDiffStr(const s1,s2: String): String;
var
t1,t2: TDateTime;
secs: Int64;
begin
t1 := StrToDateTime(s1);
t2 := StrToDateTime(s2);
secs := SecondsBetween(t1,t2);
Result := Format('%2.2d:%2.2d:%2.2d',[secs div SecsPerHour,(secs div SecsPerMin) mod SecPerMin,secs mod SecsPerMin]);
end;
begin
WriteLn(TimeDiffStr('03/03/2017 10:10:12','04/04/2017 10:10:12'));
ReadLn;
end.
From the number of seconds, calculate the hours,minutes and remaining seconds.
If you want the difference in minutes, use the DateUtils.MinutesBetween function:
function TimeDiffStr(const s1,s2: String): String;
var
t1,t2: TDateTime;
minutes: Int64;
begin
t1 := StrToDateTime(s1);
t2 := StrToDateTime(s2);
minutes := MinutesBetween(t1,t2);
Result := Format('%2.2d:%2.2d:%2.2d',[minutes div MinsPerHour,minutes mod MinsPerHour,0]);
end;
You can use TTimeSpan (from the System.TimeSpan unit).
program Project1;
{$APPTYPE CONSOLE}
uses
System.SysUtils, System.TimeSpan;
var
StartDate, EndDate: TDateTime;
TS: TTimeSpan;
Temp: string;
begin
StartDate := StrToDateTime('03/03/2017 10:10:12');
EndDate := StrToDateTime('04/04/2017 10:10:12');
TS := TTimeSpan.Subtract(EndDate, StartDate);
Temp := TS;
WriteLn(Temp); // Outputs 32.00:00:00
// The next line outputs the same as the one above
WriteLn(Format('%.2d:%.2d:%.2d:%.2d', [TS.Days, TS.Hours, TS.Minutes, TS.Seconds]));
WriteLn(TS.TotalMinutes); // Outputs 4.60800000000000E+0004
WriteLn(Trunc(TS.TotalMinutes)); // Outputs 46080
// This one will give the output you want (768:00:00)
WriteLn(Format('%.2d:%.2d:%.2d', [TS.Days * 24 + TS.Hours, TS.Minutes, TS.Seconds]));
ReadLn;
end.
First off, don't use hard-coded strings for date/time values. That is subject to localization issues, and it is just wasted overhead anyway. Use the SysUtils.EncodeDate() and SysUtils.EncodeTime() functions, or the DateUtils.EncodeDateTime() function.
Second, the ...Between() functions can indeed be usedneed, in particular SecondsBetween(). You can calculate the individual components from that return value.
Try something like this:
uses
..., SysUtils, DateUtils;
var
s, e: TDateTime;
diff: Int64;
days, hours, mins, secs: Integer;
s: string;
begin
s := EncodeDateTime(2017, 3, 3, 10, 10, 12, 0);
e := EncodeDateTime(2017, 4, 4, 10, 10, 12, 0);
diff := SecondsBetween(e, s);
days := diff div SecsPerDay;
diff := diff mod SecsPerDay;
hours := diff div SecsPerHour;
diff := diff mod SecsPerHour;
mins := diff div SecsPerMin;
diff := diff mod SecsPerMin;
secs := diff;
s := Format('%d:%d:%d:%d', [days, hours, mins, secs]);
end;
I am trying to make a countdown timer, the idea is to set the time in text edit property and after i click set timer(button), that time to be sent to Label, which will then start the countdown to 0. I have gotten to this part, but i cant figure out a way to make seconds countdown, If any of you guys can help I would appreciate it.
I tried this from an example I found online but it didnt work because this is Firemonkey application.
dec(TotalTime); {decrement the total time counter}
// Timer code..
procedure TForm1.ButtonSetTimerClick(Sender: TObject);
var
GetTime : TDateTime;
begin
Timer3.Enabled := True;
Label11.Text := Edit1.Text;
ButtonSetTimer.Enabled := False;
Edit1.Enabled := False;
GetTime := StrToTime(Edit1.Text);
end;
procedure TForm1.ButtonStopTimerClick(Sender: TObject);
begin
Timer3.Enabled := False;
ButtonSetTimer.Enabled := True;
Edit1.Enabled := True;
end;
procedure TForm1.Timer3Timer(Sender: TObject);
var
GetTime : TDateTime;
Hour, Min, Sec, MSec: Word;
begin
DecodeTime(GetTime, Hour, Min, Sec, Msec);
Label11.Text := TimeToStr(GetTime);
Label11.Text := IntToStr(Hour) + ':'+ IntToStr(Min) + ':'+ IntToStr(Sec);
Label11.Text := Format('%2.2u:%2.2u:%2.2u',[Hour,Min,Sec]);
end;
Cheers.
You did not say how (in which format) the time is to be entered in the TEdit, so here are three alternative time entry possibilities. The output is anyway formatted as H:M:S.
I modified the code from yesterday to use TryStrToInt / TryStrToTime to catch errors. Also, a Seconds counter together with OnTimer event as in my previous example has a poor accuracy and can drift several seconds within 5 minutes. Edijs solution to compare Now with a calculated end time is insensitive to the inaccuracy of OnTimer events, so I adopted that too.
var
TimeOut: TDateTime;
function SecsToHmsStr(ASecs: integer):string;
begin
Result := Format('%2d:%2.2d:%2.2d',
[ASecs div 3600, ASecs mod 3600 div 60, ASecs mod 3600 mod 60]);
;end;
procedure TForm6.Timer1Timer(Sender: TObject);
begin
Label1.Caption := SecsToHmsStr(SecondsBetween(Now, TimeOut));
if Now > Timeout then Timer1.Enabled := False;
end;
Time entry alternative one, Timeout after a given number of seconds
// Timeout after a given number of seconds
procedure TForm6.Button1Click(Sender: TObject);
var
Seconds: integer;
begin
if TryStrToInt(Edit1.Text, Seconds) then
begin
TimeOut := IncSecond(Now, Seconds);
Timer1.Enabled := True;
Label1.Caption := SecsToHmsStr(SecondsBetween(Now, TimeOut));
end
else
ShowMessage('Error in number of seconds');
end;
Time entry alternative two, Timeout after a given number of hours, minutes and seconds
// Timeout after a given number of hours, minutes and seconds
procedure TForm6.Button2Click(Sender: TObject);
begin
if TryStrToTime(Edit1.Text, TimeOut) then
begin
TimeOut := Now + TimeOut;
Timer1.Enabled := True;
Label1.Caption := SecsToHmsStr(SecondsBetween(Now, TimeOut));
end
else
ShowMessage('Error in time format');
end;
Time entry alternative three, Timeout at a given time within 24 hours
// Timeout at a given time within 24 hours
procedure TForm6.Button3Click(Sender: TObject);
begin
if TryStrToTime(Edit1.Text, TimeOut) then
begin
if TimeOut <= Time then
TimeOut := Tomorrow + TimeOut
else
TimeOut := Today + TimeOut;
Timer1.Enabled := True;
Label1.Caption := SecsToHmsStr(SecondsBetween(Now, TimeOut));
end
else
ShowMessage('Error in time format');
end;
This should do it:
Uses
System.DateUtils;
type
..
private
FDateTimeTo: TDateTime;
end;
function IntToTimeStr(const ASeconds: Int64): string;
begin
Result := Format('%2d:%2.2d:%2.2d', [ASeconds div 3600, ASeconds mod 3600 div 60,
ASeconds mod 3600 mod 60]);
end;
procedure TForm1.BitBtn1Click(Sender: TObject);
begin
FDateTimeTo := StrToDateTime(FormatDateTime('yyyy' + FormatSettings.DateSeparator + 'mm' +
FormatSettings.DateSeparator + 'dd 00:00:00', Now)) + StrToTime(Edit1.Text);
if CompareDateTime(Now, FDateTimeTo) = 1 then
FDateTimeTo := IncDay(FDateTimeTo);
end;
procedure TfrmMain.Timer1Timer(Sender: TObject);
begin
Label1.Caption := IntToTimeStr(SecondsBetween(Now, FDateTimeTo));
end;
ISO 8601 describes a so called basic date format that does not use the dashes:
20140507 is a valid representation of the more readable 2014-05-07.
Is there a Delphi RTL function that can interpret that basic format and convert it to a TDateTime value?
I tried
function TryIso2Date(const _s: string; out _Date: TDateTime): Boolean;
var
Settings: TFormatSettings;
begin
Settings := GetUserDefaultLocaleSettings;
Settings.DateSeparator := #0;
Settings.ShortDateFormat := 'yyyymmdd';
Result := TryStrToDate(_s, Date, Settings);
end;
TryIso2Date('20140507', dt);
but it did not work because the DateSeparator could not be found in the string.
The only solution I so far came up with (other than writing the parsing code myself) is adding the missing dashes before calling TryStrToDate:
function TryIso2Date(const _s: string; out _Date: TDateTime): Boolean;
var
Settings: TFormatSettings;
s: string;
begin
Settings := GetUserDefaultLocaleSettings;
Settings.DateSeparator := #0;
Settings.ShortDateFormat := 'yyyy-mm-dd';
s := Copy(_s,1,4) + '-' + Copy(_s, 5,2) + '-' + Copy(_s, 7);
Result := TryStrToDate(_s, Date, Settings);
end;
TryIso2Date('20140507', dt);
This works, but it feels rather clumsy.
This is Delphi XE6, so it should have the most recent RTL possible.
You can use Copy to pull out the values as you already do. And then you just need to encode the date:
function TryIso8601BasicToDate(const Str: string; out Date: TDateTime): Boolean;
var
Year, Month, Day: Integer;
begin
Assert(Length(Str)=8);
Result := TryStrToInt(Copy(Str, 1, 4), Year);
if not Result then
exit;
Result := TryStrToInt(Copy(Str, 5, 2), Month);
if not Result then
exit;
Result := TryStrToInt(Copy(Str, 7, 2), Day);
if not Result then
exit;
Result := TryEncodeDate(Year, Month, Day, Date);
end;