DateTime data format handling

Posted by lace28 on 22-Jul-2009 07:46

Hi.

I'm using the DateTime data type for the first time and I'm having a little problem with it.

I thought this would make my life easier but it didn't make it quite as easy as I thought. Here's my problem:

I'm building a string which I'll use in a query-prepare statement, and that string includes some DateTime handling. Example:

Suppose I have a table TableX which has a field CreateDateTime of type DateTime. Then my string would look like:

DateTimeVar = DateTime(Today,mtime - 10000).

QueryString = "Preselect each TableX where TableX.CreateDateTime > " + string(DateTimeVar).

You get what I'm trying to do but the string(DateTimeVar) part doesn't work. How would I do this?

Thanks. Olivier.

All Replies

Posted by Admin on 22-Jul-2009 07:57

Try something like:

QueryString = SUBSTITUTE ("Preselect each TableX where TableX.CreateDateTime > &1 ",

                                          QUOTER (DateTimeVar)) .

Posted by lace28 on 22-Jul-2009 09:51

Thanks Mike this seems to work.

QueryString = SUBSTITUTE ("Preselect each TableX where TableX.CreateDateTime > &1 ", QUOTER (DateTimeVar)) .

I found a few other ways:

QueryString = "Preselect each TableX where TableX.CreateDateTime > " + QUOTER (DateTimeVar). // Pretty much the same as Mike's solution

or more complicated:

QueryString = "Preselect each TableX where TableX.CreateDateTime > datetime(" + string(today) + "," + string(mTime - 10000) + ")".

I'm curious about one thing.

I tried doing a simple for each from a character screen and it didn't work, it gave me an 'Incompatible data types' when I do the CreateDateTime = QUOTER(DateTimeVar).

I get why this does not work, I don't get why it works in the query-prepare statement!

I know some of you will say "It works, just be happy!!!" but hey it's in my nature to want to understand things so I'm only half-happy!!

Thanks again.

Olivier.

Posted by Peter Judge on 22-Jul-2009 09:58

I'm curious about one thing.

I tried doing a simple for each from a character screen and it didn't work, it gave me an 'Incompatible data types' when I do the CreateDateTime = QUOTER(DateTimeVar).

I get why this does not work, I don't get why it works in the query-prepare statement!

CreateDateTime is defined as DATETIME and QueryString as (probably) CHARACTER. The QUOTER function returns CHARACTER, and so this is a simple typing (as in data types) error.

-- peter

Posted by Admin on 22-Jul-2009 15:55

or more complicated:

That cries for SUBSTITUTE then ....

Posted by Håvard Danielsen on 23-Jul-2009 10:18

I get why this does not work, I don't get why it works in the query-prepare statement!
The QUERY-PREPARE has special treatment of value expressions because the query is parsed at run time. The query parser expects date-format to be “dmy” and a numeric-format to be “American”. This consistency rule makes a lot of sense when these values are hard coded in source code, as always was the case before the dynamic query was introduced. But it creates a problem when the complete query is built at runtime from non-character variables because the STRING function is resolved according to the session settings. 
This problem was resolved by changing the "syntax" of a query string to allow quotes around any "hardcoded" data. The quotes around the expression make the query parser evaluate the expression according to session settings.

Applications that build query strings at runtime with the STRING function will likely give a run time error or, perhaps even worse, simply give wrong results with non-default session format settings.

I know some of you will say "It works, just be happy!!!" but hey it's
in my nature to want to understand things so I'm only half-happy!!

Well, it was a very important question...   I have seen too much code with dynamic queries built without quotes around non-character expressions.

Posted by Admin on 23-Jul-2009 10:23

I guess in case of date-time fields the quotes are also required because of the space characters in the default format as in:

23/07/2009 17:23:13,568+02:00

Posted by Håvard Danielsen on 23-Jul-2009 10:37

I guess in case of date-time fields the quotes are also required because of the space characters in the default format as in:

23/07/2009 17:23:13,568+02:00

Yes, but that's almost a blessing, since you are forced to fix it. With dates and decimals the parser and compiler may not always protest, but could still return wrong data.

Posted by Håvard Danielsen on 23-Jul-2009 10:54

Here's a simple test that illustrates the problem with decimals. In this case the problem only happens when the criteria has decimals. A search value of 200 would not cause any problems.  With dates you are more likely to get a compiler warning, but a date like for example 01/04/12 would compile in all date-formats, but give very different results depending on the setting.

define temp-table test
   field decvalue as decimal.
define variable searchvalue as decimal no-undo.  
define variable querystring as character no-undo.  
  
create test.
decvalue = 200.
create test.
decvalue = 20000.

searchvalue = 199.99.
querystring = "preselect each test where decvalue > " + string(searchvalue).

run runquery("Non quoted american value",querystring).

/* european will go wrong if query has decimals - query parser assumes american - query engine uses session settings */
session:numeric-format="european".
run runquery("Non quoted american value - compiles, but evaluates as european", querystring).

querystring = "preselect each test where decvalue > " + string(searchvalue).
run runquery("Not quoted european value", querystring).

/* quotes around the expression makes the query parser evaluate the expression according to session settings */
querystring = "preselect each test where decvalue > " + quoter(searchvalue).
run runquery("quoted",querystring).

/* works also with american  of course */
session:numeric-format="american".
querystring = "preselect each test where decvalue > " + quoter(searchvalue).
run runquery("quoted",querystring).

/**************************/
procedure runquery:
  define input  parameter msgtitle as character no-undo.
  define input  parameter querystring as character no-undo.
 
  define variable hquery as handle no-undo.  
  define variable msg as char no-undo.  
  create query hquery.
  msgtitle = session:numeric-format + " - " + msgtitle.
  do on error undo, throw:
      hquery:add-buffer(buffer test:handle).
      hQuery:query-prepare(querystring).
      hquery:query-open().  
      message  msg skip
           "Query:" querystring skip(1)
           "Num records: " hquery:num-results
          view-as alert-box title msgtitle.   
      catch  e as Progress.Lang.Error :
         message "Query:" querystring skip(1) skip
                  e:GetMessage(1)
         view-as alert-box error title msgtitle .
      end catch.
  end.
end.

Posted by lace28 on 23-Jul-2009 11:26

Thanks Havard.

I tried your code and saw exactly what you meant. It's nice to know how the query parser works.

Olivier

Posted by rbf on 23-Jul-2009 17:07

A small correction:

> The query parser expects date-format to be “dmy” and a numeric-format to be “American”.

That should be: '.. expects the date-format to be "mdy"...'

And while I am at it, I should issue a word of warning about the practice of quoting these expressions. Remember that if you cross the AppServer boundary, the session settings of the client might well be different from the server. Therefore, do not send those values accross as characters when they originate on the client. Instead, send them over in their native data types and quote them on the server.

Posted by Håvard Danielsen on 24-Jul-2009 08:22

rbf wrote:

A small correction:

> The query parser expects date-format to be “dmy” and a numeric-format to be “American”.

That should be: '.. expects the date-format to be "mdy"...'


oops... thanks.

And while I am at it, I should issue a word of warning about the practice of quoting these expressions. Remember that if you cross the AppServer boundary, the session settings of the client might well be different from the server. Therefore, do not send those values accross as characters when they originate on the client. Instead, send them over in their native data types and quote them on the server.

Also an important reminder. The quoting and the querying must be done with the same settings. This can also be achieved by ensuring that the server has the same settings as the client as we do in Dynamics.

This thread is closed