Converting from SQL Date to DateTime in Delphi XE
Solution 1
I could reproduce this behavior (SQL Server 2008 R2).
SQL-Server data type date
(2008+) maps to TWideStringField
(ftWideString
) with ADO provider SQLOLEDB.1
.
Accessing this field (TWideStringField
) with .AsDateTime
will raise an exception as described in the quesion:
'2014-06-15' is not a valid date and time
.
Here is a related (or duplicate?) question: Delphi 6, ADO, MS database “Date” field is same as ftWideString
Possible solutions:
- use the SQL-Server native client e.g.
Provider=SQLNCLI10.1;
->date
is mapped toTDateField
-
SELECT
viaCAST(ActiveDate AS datetime)
and then.AsDateTime
works as expected. - use
datetime
data type on SQL-Server instead ofdate
- access the
date
field via solution provided by @Chris Thornton
Solution 2
Here's a function that should do the trick, thanks to feedback from David and Remy:
function AnsiDateStrToDate(AnsiDate : string) : TDate;
// Convert data in YYYY-MM-DD to TDate
var
Fmt : TFormatSettings; // Does not need to be freed
begin
Fmt := TFormatSettings.Create;
Fmt.ShortDateFormat := 'YYYY-MM-DD';
Fmt.DateSeparator := '-';
result := StrToDate(AnsiDate,Fmt);
end;
Usage:
if AnsiDateStrToDate(myQuery.FieldByName('ActiveDate').AsString) = Date Then
writeln('Today!')
Else
writeln('Not Today!);
mvanella
Updated on June 19, 2022Comments
-
mvanella almost 2 years
I've searched google and SO with no usable fixes for this. I am retrieving a
date
from a table in SQL Server. I need to convert this to aDateTime
object in Delphi. The problem seems to lie in the value coming in from SQL. The version of SQL Server on which I am testing this is SQL Server 2012 (not R2).If I display the value retrieved from a query as a string I get:
myQuery.FieldByName('ActiveDate').AsString;
I get the value
2014-06-15
myQuery
is a TADOQuery type.DateTime doesn't seem to like this format since all of these fail:
myQuery.FieldByName('ActiveDate').AsDateTime; StrToDateTime(myQuery.FieldByName('ActiveDate').AsString); StrToDate(myQuery.FieldByName('ActiveDate').AsString);
The failure message from the caught exception that gets logged is:
''2014-06-15'' is not a valid date and time
Is there a solution to this that doesn't involve a complicated string manipulation and that would not be affected by the locale of the server?
-
David Heffernan almost 10 yearsIf you must do this, use conversion functions that don't depend on global state. The overloads that accept a format settings parameter. But surely it's better to avoid converting to string at all.
-
David Heffernan almost 10 yearsIn other words the question is really about how to read a
date
field without using any string conversions. If possible. -
Chris Thornton almost 10 years@DavidHeffernan, Agreed. IMO, if you need it to be a date, use .AsDate instead of .AsString.
-
David Heffernan almost 10 yearsSo write that in the answer. Problem is, SQL date types aren't understood that way. Which is the essence of the question.
-
Remy Lebeau almost 10 yearsThe global formatting variables are not thread-safe, and have been completely removed in XE6. If you are going to use
FormatSettings
, the correct way is to use the overloaded version ofStrToDate()
that takes aTFormatSettings
as input:Fmt := TFormatSettings.Create; Fmt.ShortDateFormat := 'YYYY-MM-DD'; Fmt.DateSeparator := '-'; ... := StrToDate(myQuery.FieldByName('ActiveDate').AsString, Fmt);
-
Chris Thornton almost 10 years@RemyLebeau, good point about not being thread-safe. But DXE6 definitely does understand SysUtils.FormatSettings.ShortDateFormat. Anyway, I will take your advice on the overloaded StrToDate.
-
mvanella almost 10 yearsIs
.AsDate
supposed to be available before XE2? I am running XE1 and it doesn't recognize it:'TField' does not contain a member named 'AsDate'
I couldn't find it in Embarcadero's documentation pre-XE2: docwiki.embarcadero.com/Libraries/XE2/en/Data.DB.TParam.AsDate -
David Heffernan almost 10 years@Chris Remy is giving the exact same advice I did. You absolutely need to fix the answer.
-
Remy Lebeau almost 10 yearsI have fixed the answer.
-
David Heffernan almost 10 years@mvanella Ah well, I guess I should not have deleted my answer if I'd known you wanted a text processing based solution. I don't understand why you don't want to get to the bottom of this. Does it not concern you that you've no idea where this date formatting comes from? What happens if on some other machine it comes back with a different format? Until you actually know where this text comes from, I cannot see how you can proceed.
-
mvanella almost 10 years@davidheffernan Feel free to submit an answer and I will look it over. I never asked you to delete yours, that was all you. :)
-
David Heffernan almost 10 yearsYou already saw my answer. It wasn't very good. I think you really need to be trying to understand where this string comes from.
-
mvanella almost 10 years@DavidHeffernan Switching locales a few times didn't seem to change the result, no errors were introduced. I am a little curious as to why that value is coming in weird, and I think Ken gave me some things to look into. But for now this question has gotten a little out of hand so I think I'd like to keep it simple. Also, you are an unpleasant individual with which to interact so I'd prefer to keep that interaction to a minimum. Regardless, thank you for your help.
-
David Heffernan almost 10 yearsWhy is it unpleasant? I'm giving you my advice. It's up to you what you do with it. Surely you came here for advice. I don't like to see problems closed when they have not been properly solved. I find that frustrating.
-
David Heffernan almost 10 years@mvanella I'm happy now. Kobik's answer addresses the root problem quite nicely.