I have a stringified date/time in an odd format - yyyymmddhhnnss - and while I know how to convert a TDateTime
to this format with FormatDateTime()
, I have troubles converting it back. I tried using StrToDateTime()
with the TFormatOptions
parameter, but you obviously cannot set it to have no separator (you either give some separator character, or the default system setting is used).
What are some ways to handle this? I know I could parse the string manually, I can do that, but are there some more efficient ways that I'm missing?
I'm using Delphi 11.
Every time you have a particular datetime string format you want to parse, best practice is (still) to write your own parser.
Then you know it will be 100% correct and bug free (yes, a simple task like this is very much possible to get 100% bug free), today and in every future Delphi RTL version, and on every system and user locale.
Best practice also requires you to write not only the MyStringToDateTime
function, but also the TryMyStringToDateTime
and MyStringToDateTimeDef
functions.
Here's how I'd do it (uses Math, DateUtils
):
function TryMyStringToDateTime(const S: string; out ADateTime: TDateTime): Boolean;
begin
if S.Length <> 14 then
Exit(False);
var LYearStr := Copy(S, 1, 4);
var LMonthStr := Copy(S, 5, 2);
var LDayStr := Copy(S, 7, 2);
var LHourStr := Copy(S, 9, 2);
var LMinuteStr := Copy(S, 11, 2);
var LSecondStr := Copy(S, 13, 2);
var LYear, LMonth, LDay, LHour, LMinute, LSecond: Integer;
if
not
(
TryStrToInt(LYearStr, LYear)
and
TryStrToInt(LMonthStr, LMonth)
and
TryStrToInt(LDayStr, LDay)
and
TryStrToInt(LHourStr, LHour)
and
TryStrToInt(LMinuteStr, LMinute)
and
TryStrToInt(LSecondStr, LSecond)
)
then
Exit(False);
if not InRange(LYear, 1, 9999) then
Exit(False);
if not InRange(LMonth, 1, 12) then
Exit(False);
if not InRange(LDay, 1, DaysInAMonth(LYear, LMonth)) then
Exit(False);
if not InRange(LHour, 0, 23) then
Exit(False);
if not InRange(LMinute, 0, 59) then
Exit(False);
if not InRange(LSecond, 0, 59) then
Exit(False);
ADateTime := EncodeDateTime(LYear, LMonth, LDay, LHour, LMinute, LSecond, 0);
Result := True;
end;
function MyStringToDateTime(const S: string): TDateTime;
begin
if not TryMyStringToDateTime(S, Result) then
raise EConvertError.CreateFmt('Invalid datetime string: "%s"', [S]);
end;
function MyStringToDateTimeDef(const S: string; const ADefault: TDateTime): TDateTime;
begin
if not TryMyStringToDateTime(S, Result) then
Result := ADefault;
end;