Was playing with dateutils and did some experimenting.
procedure TForm1.Button1Click(Sender: TObject);
var
fromDate, toDate : TDateTime;
begin
fromDate := cxDateEdit1.Date ;
toDate := cxDateEdit2.Date ;
Label1.Caption := 'Hour difference '+IntToStr(HoursBetween(toDate, fromDate))+' hours';
Label2.Caption := 'Minute difference '+IntToStr(MinutesBetween(toDate, fromDate))+' minutes';
end;
How can I get a time difference result in a label caption like hh/mm (example 01:05) ???
A TDateTime is intended to be used with absolute dates and times. Instead you might consider TTimeSpan from the System.TimeSpan unit.
uses
System.TimeSpan;
....
var
d1, d2: TDateTime;
Span: TTimeSpan;
str: string;
....
d1 := ...;
d2 := ...;
Span := TTimeSpan.Subtract(d2, d1);
str := Format('%.2d:%.2d', [Span.Hours, Span.Minutes]));
This assumes that the span is less than a day. But then the format of your output seems to build in that very assumption.
Whether or not this is really any better than simply subtracting two date time values I am not so sure.
SysUtils.FormatDateTime has many useful TDateTime to string conversions:
Label3.Caption := 'Time difference [hh:mm] '+FormatDateTime('hh:nn',toDate-fromDate);
As an alternative, use the result from MinutesBetween:
var
minutes: Integer;
...
minutes := MinutesBetween(toDate,FromDate);
Label3.Caption :=
'Time difference [hh:mm] '+Format('%.2d:%.2d',[minutes div 60,minutes mod 60]);
Related
I'm using Delphi7.
I have date format set to yyyymmdd (can take any date format without separator). When I'm trying StrToDate('20170901') it is throwing error.
I want to support all the valid date formats (can be used by different clients in different zones.)
I have tried with VarToDateTime but it is also not working.
If same issue will be there for DateToStr() also, please guide me through that too.
You are getting an error because your input string does not match your machine's regional settings for date/time strings.
Normally, I would suggest using the StrToDate() function in the SysUtils unit, setting its global ShortDateFormat and DateSeparator variables beforehand, and then restore them afterwards (Delphi 7 predates the introduction of the TFormatSettings record), eg:
uses
..., SysUtils;
var
OldShortDateFormat: string;
OldDateSeparator: Char;
input: string;
dt: TDateTime;
begin
input := ...;
OldShortDateFormat := ShortDateFormat;
OldDateSeparator := DateSeparator;
ShortDateFormat := 'yyyymmdd'; // or whatever format you need...
DateSeparator := '/'; // or whatever you need
try
dt := StrToDate(input);
finally
ShortDateFormat := OldShortDateFormat;
DateSeparator := OldDateSeparator;
end;
// use dt as needed...
end;
Unfortunately, StrToDate() requires the input string to have a separator between the date components (ie 2017/09/01), but your input string does not (20170901). StrToDate() does not allow DateSeparator to be set to #0 when parsing a string, even if the ShortDateFormat does not specify any separators are in the format.
So that leaves only one option - parse the string manually to extract the individual components, and then use the EncodeDate() function in the SysUtils unit, eg:
uses
..., SysUtils;
var
wYear, wMonth, wDay: Word;
input: string;
dt: TDateTime;
begin
input := ...;
wYear := StrToInt(Copy(input, 1, 4));
wMonth := StrToInt(Copy(input, 5, 2));
wDay := StrToInt(Copy(input, 7, 2));
// or in whatever order you need...
dt := EncodeDate(wYear, wMonth, wDay);
// use dt as needed...
end;
The DateToStr() function is also subject to regional settings. However, it does allow the DateSeparator to be omitted in the output. So, you can either:
use DateToStr(), setting the global ShortDateFormat variable to the desired format:
uses
..., SysUtils;
var
OldShortDateFormat: string;
dt: TDateTime;
output: string;
begin
dt := ...;
OldShortDateFormat := ShortDateFormat;
ShortDateFormat := 'yyyymmdd'; // or whatever format you need...
try
output := DateToStr(dt);
finally
ShortDateFormat := OldShortDateFormat;
end;
// use output as needed...
end;
extract the individual date components from the TDateTime using the DecodeDate() function in the SysUtils unit, and then format your own string with the year/month/day values however you want:
uses
..., SysUtils;
var
wYear, wMonth, wDay: Word;
dt: TDateTime;
output: string;
begin
dt := ...;
DecodeDate(dt, wYear, wMonth, wDay);
output := Format('%.4d%.2d%.2d', [wYear, wMonth, wDay]);
// use output as needed...
end;
To convert that string into a TDateTime, split the string into its year, month and day components and pass them to the EncodeDate() function.
var
myStr: string;
myDate: TDate;
begin
myStr := '20170901';
myDate := EncodeDate(
StrToInt(Copy(MyStr, 1, 4)),
StrToInt(Copy(MyStr, 5, 2)),
StrToInt(Copy(MyStr, 7, 2))
);
...
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;
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.
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;
I am looking for a function to reverse any string (YYYYMDD,YY/MM/DD,YYMMDD,...) created by the function FormatDateTime to datetime.
example
I have a string-date in format YYYYMMDDcreated by FormatDateTime
mydatestr:=FormatDateTime('YYYYMMDD',Mydate);
now how I can convert mydatestr to DateTime again?
UPDATE
these functions
function StrToDate(const S: string): TDateTime; overload;
function StrToDate(const S: string;
const FormatSettings: TFormatSettings): TDateTime; overload;
function StrToDateTime(const S: string): TDateTime; overload;
function StrToDateTime(const S: string;
const FormatSettings: TFormatSettings): TDateTime; overload;
do not support passing a string with the format to convert.
I am looking something like this
Mydatetime:=InvFormatDatetime('20091225','yyyymmdd');
or
Mydatetime:=InvFormatDatetime('20090108','yyyyddmm');
It is quite easy with existing solution, StrToDateFmt function in rxDateutil.pas unit from RX package, which can be downloaded here: http://sourceforge.net/projects/rxlib/
EDIT:
Mentioned above function and StrToDateFmt from rxDateutil.pas are doing exactly what you expect, converting string to datetime using specified string mask, the code is too large to be included as this unit contains also other date functions, some of them required for converting string to date.
Example of use:
Result := StrToDateFmtDef('MM/DD/YYYY', '11/11/2011', Now);
Note: Unfortunately, as pointed out by Martien in this answer's comments, this solution will not work for cases where the date includes no date separator. However, I'm going to leave the answer up for anyone that may find it useful regardless.
I liked Tuncay's answer but there were a couple of problems with it. I'd have left a comment but I don't have enough reputation points.
So, here's the corrected version of Tuncay's answer (amending "TFormatSetting" missing an "s" and specified the format settings date separator):
function AnyStringToDate(fmt, dt: String) : TDateTime;
var
fs : TFormatSettings;
Begin
fs := TFormatSettings.Create;
fs.DateSeparator := '-';
fs.ShortDateFormat := fmt;
result := StrToDateDef(dt, 0, fs);
End;
Identical to Tuncay's answer, AnyStringToDate can be used as follows:
mydate := AnyStringToDate('YYYY-MM-DD', '2015-01-20');
Without using any external library, you can do something like:
function AnyStringToDate(fmt, dt: String) : TDateTime;
var
fs : TFormatSettings;
Begin
fs := TFormatSettings.Create;
fs.ShortDateFormat := fmt;
result := StrToDateDef(dt, 0, fs);
End;
and then use it like:
mydate := AnyStringToDate('YYYY-MM-DD', '2015-01-20');
I havent compiled this, but the idea simple.
You could use StrToDateFmt function of JvJCLUtils unit belonging to JEDI Code Library
in your case :
Function InvFormatDatetime ( dateString :String; dateFormat :String ) : TDateTime;
begin
Result := JvJCLUtils.StrToDateFmt ( dateFormat, dateString );
end;
Did you check StrToDate and StrToDateTime ?
I know its too late but just for interest sake, with Delphi XE6 onwards you can now do the following
uses
System.DateUtils;
var
dt: TDateTime;
begin
dt := ISO8601ToDate('20190408');
end.
dt will now be 2019/04/08
Function InvFormatDatetime (Cadena:String; Formato:String) : TDateTime;
Var
PosD, PosM, PosY : Integer;
sD, sM, sY : String;
begin
sd := '0';
sm := '0';
sy := '0';
If Length(Cadena) = Length(Formato) Then
Begin
Formato := UpperCase(Formato);
PosD := Pos('D',Formato);
PosM := Pos('M',Formato);
PosY := Pos('Y',Formato);
sd := Copy(Cadena,PosD,2);
sm := Copy(Cadena,PosM,2);
if Length(Cadena) = 6 then
begin
sy := Copy(Cadena,PosY,2);
if StrToInt(sy) > 50 then
sy := '19'+sy
else
sy := '20'+sy;
end
else
sy := Copy(Cadena,Posy,4);
End;
Result := EncodeDate(StrToInt(sY),
StrToInt(sM),
StrToInt(sD));
End;
greetings