Converting Date Format in Advantage SQL - advantage-database-server

I have a simple problem in Advantage Database SQL.
I have dates in the format M/D/YYYY and want to convert them MM/DD/YYYY. Normally in SQL Server I would just use a convert(varchar(20), field, 101) but this does not work in Advantage.
What is the format for doing so?

I don't believe there is a simple conversion function like that available. To convert it directly in SQL would probably turn into a fairly messy statement (I think it would require a combination of CONVERT, YEAR, DAY, and MONTH scalars).
If the goal, though, is to force the display of date values in a specific format in the client application, then one possibility might be to specify the date format at connection time. How you do that depends on the client being used. If, for example, you are using a connection string, then you may be able to specify the date format as follows.
Data Source=\\server\share\yourdatapath;...;DateFormat=MM/DD/YYYY;

Related

How can I parse a particular representation of ISO 8601 timestamp (one without any whitespaces) using DateTimeFormatter?

I am trying to parse an ISO 8601 timestamp which looks like this: "20220603T054813Z". My supervisor gave me this timestamp asking me to parse it (she found it on wiki under the ISO-8601 page) but I couldnt find information regarding this type of timestamp anywhere else.
I am trying to parse it using a LocalDateTime instance and using a pre-defined format but I cant find any. Using any of the classes doesnt work neither do the pre-defined formatters for ISO 8601 timestamps. There's no example in the documentation that explains how to handle this particular case and that makes me wonder if this is a valid ISO 8601 case. It does work with my own created format but I am writing a logic to handle ISO 8601 cases without me having to define a custom format, as much as possible. atleast for the ISO 8601 timestamps. Is this a valid ISO 8601 timestamp even? Because usually they have separators for date and time.
Is there a way to handle timestamps like these, which doesnt have any separators or whitespaces, with a pre-defined formatter? Maybe i am missing something. Any help would be appreciated, thanks!

Different date format and one locale

I use I18n.t('date.formats.default') for date formatting.
The issue is that in different countries there are different date formats, but one english locale.
For example '%m.%d.%Y' fo US and '%d.%m.%Y' for Australia
I need the ideas how to handle with it.
While you might simply use something else for date formats, the easiest drop-in solution would be to store all possible variants in the same string and on retrieval do (assuming the country code is known):
'date.formats.default': 'US[%m.%d.%Y],AU[%d.%m.%Y]'
code = 'AU'
format = I18n.t('date.formats.default')
format[/(?<=#{code}\[).*?(?=\])/] || format
#⇒ "%d.%m.%Y"
The latter || format is needed to support normal format, without brackets.
If you don’t like regular expressions, store the JSON there, containing hash {CODE => FORMAT}, parse it and retrieve the value.
I think it is more convenient way to use different locales.
For example en-AU.yml, en-US.yml, en-CA.yml etc.? Especially i18n supports this.
Australia has different time format too.
Every time you have to take into account all these nuances for each country.
Using different locales simplifies this.

Time of Day in the JSON response model?

I am using ASP.NET Web Api 2 with Json.NET 6.0.1.
According to ISO 8601, dates should be interchanged in a certain way. I am using the IsoDateTimeConverter() in order to achieve this:
config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new IsoDateTimeConverter());
But how should "time of day" be returned in a JSON response model?
I cannot find anything for this in the ISO specification.
Should time perhaps be returned as a:
TimeSpan? (with expectation of the user to not use this as a duration representation)
DateTime? (with expectation of the user to drop off the date part)
A custom Time class
There is no standard structure in JSON for containing dates or times (see JSON.org). The de-facto stardard for dates-time values is using a string in ISO 8601 format, as you mentioned. But since there is no official standard it really comes down to what works best for you and consumers of your API.
Using a DateTime object is a reasonable choice because the support already exists in Json.Net and other serializers for converting these to and from ISO 8601 strings. So this would be the easiest to implement. However, users of your API would have to know to disregard the date portion, as you said. You could set the date to 0001-01-01 to emphasize its irrelevance. This isn't so different from the more common situation where you need only a date in your API and the time doesn't matter. Most people just set the time to midnight in this case and let it go. But, I would agree that this approach does seem to have a little bit of a "code smell" to it, given that part of the value is just noise.
Perhaps a cleaner idea is to format your DateTime value as ISO 8601, but then chop off the date portion before returning it. So users of the API would get a string that looks like 14:35:28.906Z. You could write a simple JsonConverter to handle this for you during serialization. This would sort of give you the best of both worlds -- a cleaner API, but you still can work with the familiar DateTime struct internally.
A custom Time class could also work here, but might be overkill, depending. If you do need to go there, you might want to look into a third-party library such as Noda Time, which has classes already built for these kinds of things, and also has pre-built converters for Json.Net.
I would definitely not choose TimeSpan for this purpose. Wrong tool for the job.

Overriding the system Date Format

In my application I am reading from one database and writing to a second. The app is quick and dirty so I am reading / writing using AsString on both the FieldByName and ParamByName of the queries.
This works for all my use cases apart from where the data type is Date or DateTime
As far as I can tell FieldByName.AsString uses the system ShortDateTime format to return dates as (in my case) dd/mm/yyyy. The database expects the date to be written in as yyyy-mm-dd
According to Delphi Basics I should be able to set ShortDateFormat to what I need, but it appears that in XE5 this is no longer the case (correct?)
Further digging on here returns these two questions that use TFormatSettings to override the local settings. However, both of these use the resulting FormatSettings in StrToDate and FormatDateTime directly.
So two questions
1) Can I tell my application to override the System ShortDateFormat?
2) If so, How (I have a Plan B if not)?
The use of a global variable for the date and time formats was a mistake committed long ago by the original RTL designers. Functions that rely on the global format settings, like the single parameter StrToDate are retained for backwards compatibility, but you should not be using them.
For conversions between date/time and string you should:
Initialise a TFormatSettings instance with your date format.
Call the two parameter StrToDate, passing your TFormatSettings to convert from a string to a date.
Call FormatDateTime overload that accepts a TFormatSettings when converting in the other direction.
Now, to the main thrust of your question. You should not be using strings at all for your dates and times in the scenario you describe. Use AsDateTime rather than AsString. If you happen to have a database column that does store a date/time as a string, then you'll should use the TFormatSettings based conversion functions to work around that design fault.
If you are absolutely dead set on doing this all with strings, and I cannot persuade you otherwise, then you need to use FormatSettings.ShortDateFormat from SysUtils to control your short date formatting.

Optimal way to store datetime values in SQLite database (Delphi)

I will be storing datetime values in an SQLite database (using Delphi and the DISqlite library). The nature of the db is such that it will never need to be transferred between computers or systems, so interoperability is not a constraint. My focus instead is on reading speed. The datetime field will be indexed and I will be searching on it a lot, as well as reading in thousands of datetime values in sequence.
Since SQLite does not have an explicit data type for datetime values, there are several options:
use REAL data type and store Delphi's TDateTime values directly: fastest, no conversion from string on loading; impossible to debug dates using a db manager such as SQLiteSpy, since dates will not be human-readable. Cannot use SQLite date functions (?)
use a simple string format, e.g. YYYYMMDDHHNNSS: conversion is required but relatively easy on the CPU (no need to scan for separators), data is human-readable. Still cannot use SQLite date functions.
do something else. What's the recommended thing to do?
I have read http://www.sqlite.org/lang_datefunc.html but there's no mention of what data type to use, and, not being formally schooled in programming, I don't quite grok the focus on Julian dates. Why the additional conversion? I will be reading in these values a lot, so any additional conversions between strings and TDateTime adds a significant cost.
You could use one of the SQLite supported string formats, eg. YYYY-MM-DD HH:MM:SS.SSS.
It would be just as easy as YYYYMMDDHHNNSS - you still wouldn't need to scan for separators, since all the numbers are fixed length - and you would get SQLite date function support.
If you need SQLite date function support, I would go with that method.
If not, I'd recommend using REAL values. You can still compare them to each other (higher numbers are later in time), and consider date and time separately (before and after the decimal point respectively) without converting to TDateTime.
One compromise would be to stick with REAL values, but store them as julian dates by using Delphi's DateTimeToJulianDate. That way they remain fast for reading, there's little performance lost in the converation, and they're still in a format that makes sense outside of Delphi.
For this I usually use an Integer data type and store the Unix timestamp value alike (eq # seconds since 1-1-2000 for example). Calculating this t/from a TDateTime is equal to multiplying/diving with/by 86400 and adding a constant for the 'since'.
If you need more precision You could use the DateTime as a FILETIME (eg int64) which has 100 ns increments. There are conversion routines in SysUtils for that and your timestamp is stored in UTC.
If your concern is only human readable format at database level, you can store two separate fields, for example:
DELPHI_DATE REAL (DOUBLE, if possible, but I don't know SQLite), Indexed. All your programmatic queries and comparisons should use this field.
HUMAN_READABLE_DATE Varchar(23) with format 'YYYY-MM-DD HH:MM:SS.SSS'. Maybe indexed (if really necessary). Majority of human input queries should include this field and you can use (as said by others) SQLite date functions.
It has some drawbacks:
Space consumption at database and network traffic grows,
insert operations will take a bit more because necessary conversion,
no automatic synch between values if updated outside your program
If it is suitable for your particular needs, is up to you.
I don't know if this answer is applicable to the DISqlite library but...
Below is some code that illustrates what works for me using both Delphi 2010 and Tim Anderson's SQLite3 wrapper.
SQL to create field:
sSQL := 'CREATE TABLE [someTable] (' +
' [somefield1] VARCHAR(12),' +
' [somefield2] VARCHAR(12),' +
' [myDateTime] DATETIME );';
SQL to populate field:
sSQL := 'INSERT INTO someTable(somefield1, somefield2, myDateTime)' +
' VALUES ( "baloney1", "baloney2","' + FloatToStr(Now) + '");';
Example of retrieving data from field:
var
sDBFilePathString: string;
sl3tbl: TSqliteTable;
fsldb : TSQLiteDatabase;
FromdbDTField : TDateTime;
begin
...
...
fsldb := TSQLiteDatabase.Create(sDBFilePathString);
sl3tbl := fsldb.GetTable('SELECT * FROM someTable');
FromdbDateTime := StrToFloat(sl3tbl.FieldAsString(sl3tbl.FieldIndex['myDateTime']));
Showmessage('DT: ' + DateTimeToStr(FromdbDTField));
end;
Result:
**DT: 10/10/2013 1:09:53 AM**
Like I mentioned on the first line - I don't know if this will work with the DISqlite library but if it does its a pretty clean way of handling things.
I leave it to you to make things prettier or more elegant.

Resources