Jump to content
Dave Novo

StrToDate cannot handle dd-MMM-yy format

Recommended Posts

Hello Everyone,

I am just wondering if below is simply a bug, or there is some method to the madness.

 

One of the valid windows short date formats is the following

image.png.a10c9f100b3ee94d21b21d78b62142b9.png

 

So, one would think that if you change windows to the short date format above, and wrote the Delphi code

fs:=TFormatSettings.Create;
newDate:=StrToDate('05-Apr-17',fs)

then you would get a valid date.  However, you do not. I checked this on Win7 and Win10, with Delphi Sydney and Seattle.

 

It is hard to believe something this ancient does not work. The fs record has the correct shortMonthNames loaded.

 

There are a few strange issues.

1. The TFormatSettings.ShortDateFormat ends up being dd/MMM/yy because FixDateSeparator replaces the '-' with a '/'. I am not sure this is relevant though, as the TFormatSettings.DateSeparator is still '-'

2. The key thing that fails is TryStrToDate calls ScanDate which exits out because of

 

 if not (ScanNumber(S, Pos, N1, L1) and ScanChar(S, Pos, AFormatSettings.DateSeparator) and
    ScanNumber(S, Pos, N2, L2)) then Exit;

i.e. it is trying to find a number, followed by a separator, followed by a number. Even though the current date format specifies that the month portion should be the short name format.

 

Is there another date method I should be using that works more reliably. Or am I doing something wrong?

Share this post


Link to post

Is there another method of conversion that can handle the entirety of the set of formats that windows supports for the current date format?

Share this post


Link to post

Nothing I am aware of, but it can be achieved easily with a wrapper like this:

  S := '05-Apr-17';
  for I := 1 to 12 do
    S := S.Replace(fs.ShortMonthNames[I], I.ToString);
  newDate := StrToDate(S, fs);

Of course there is some room for improvements, but you get the idea.

Share this post


Link to post

Sure, but then we have to either use a code hook or remember to never use StrToDate and use StrtoDateWrapper (or whatever we call it). It is surprising that these dates formats are not supported. They have been in windows for ages.

  • Sad 1

Share this post


Link to post
21 minutes ago, Dave Novo said:

Sure, but then we have to either use a code hook or remember to never use StrToDate and use StrtoDateWrapper (or whatever we call it).

Or you place a replacement for StrToDate in a separate unit MyDateUtils or so and use that all over the your projects. At least that is less tedious than replacing all StrToDate calls and having to remember a new function name.

24 minutes ago, Dave Novo said:

It is surprising that these dates formats are not supported. They have been in windows for ages.

I suggest filing a feature request in Quality Portal. (didn't check if some already exists)

Share this post


Link to post
1 hour ago, Dave Novo said:

It is surprising that these dates formats are not supported

+1. I was expecting BtoA(AtoB(A)) == A for any A

  • Like 1

Share this post


Link to post

Thanks for looking up the links. I guess if the bug report is >5 years old about this, I will not hold my breath.

Share this post


Link to post
On 9/3/2021 at 5:51 PM, Uwe Raabe said:

Nothing I am aware of

Nothing that allows specifying the format in a template?
 

OK, just looked; dang, the Datetime utilities are even worse than I remembered, and IMHO they're worse than Turbo Pascal's - which could convert a datetime into a record of all of its elements. With Delphi, datetime completely omits any type of dot notation and your datetime code ends up looking rather like LISP with all the parentheses.

 

Whoever designed Delphi's datetime unit must have never seen another language's datetime library and been mad besides. So... many... functions. Except useful ones. The day Delphi gets optional parameters I'm writing an open source datetime unit for it.

 

Even FreePascal can parse an arbitrary datetime string....

 

https://www.freepascal.org/docs-html/rtl/sysutils/formatdatetime.html

 

Share this post


Link to post
41 minutes ago, Dmitry Arefiev said:

StrToDate in v11 supports MMM in date formats.

Confirmed! 👍

  • Thanks 1

Share this post


Link to post

I have to admit that I learned about hh:nn being the correct format quite late in my career. Nevertheless is it correct and logical. Using hh:mm just opens a can of ambiguity, makes the implementation more complex, error prone and slow.

 

Unfortunately MS is not so consistent and also uses hh:mm.

 

Note, that while TFormatSettings.Invariant uses the hh:nn format, TFormatSettings.Create(Locale:TLocalId) still falls back to hh:mm mimicking the MS style:

    if Result.ShortTimeFormat = '' then Result.ShortTimeFormat := TimePrefix + HourFormat + ':mm' + TimePostfix;
    if Result.LongTimeFormat = '' then Result.LongTimeFormat := TimePrefix + HourFormat + ':mm:ss' + TimePostfix;

While we probably cannot drop hh:mm for staying compatible with Windows and older versions, using hh:nn where ever possible for unambiguousness is not that a bad idea.

 

  • Like 1

Share this post


Link to post
2 hours ago, Uwe Raabe said:

... it correct and logical.

 

Unfortunately MS is not so consistent and also uses hh:mm.

Most things seem to use hh:mm. I was just trolling through Google and it looks like Oracle, PostgreSQL, Java all do. Python and C use good old-fashioned case sensitivity, with M for months and m for minutes. This seems to eliminate any ambiguity while still preserving the use of "m" for both months and minutes. Looks like case sensitivity 1, Delphi 0 here. :classic_biggrin:

 

EDIT: Today I learned that if you want to set the time to 00:00:00.00 UTC in PostgreSQL you can use "allballs" as the input string. :classic_biggrin: I may need to file a Delphi feature request immediately....

Edited by Joseph MItzen
  • Haha 1

Share this post


Link to post
On 9/10/2021 at 11:06 PM, Dmitry Arefiev said:

StrToDate in v11 supports MMM in date formats.

Apparently they changed the parser to require date separators in the ShortDateFormat, so now setting ShortDateFormat := 'ddmmyyyy' and DateSeparator := '/' causes StrToDate('01/01/1970') to throw an Exception

Share this post


Link to post

 

37 minutes ago, Richard Wilson said:

ShortDateFormat := 'ddmmyyyy' and DateSeparator := '/' causes StrToDate('01/01/1970') to throw an Exception

 

Nothing was changed 01/01/1970 required date format dd/mm/yyyy. Tested with Delphi XE5:

 

var
  f: TFormatSettings;
begin
  f:=TFormatSettings.Create;
  f.ShortDateFormat:='dd/mm/yyyy';
  f.DateSeparator:='/';
  StrToDate('01011970', f);
end;

The result is as expected

 ---------------------------
Debugger Exception Notification
---------------------------
Project Project1.exe raised exception class EConvertError with message ''01011970' is not a valid date'.
---------------------------
Break   Continue   Help   
---------------------------

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×