Spotlight on Date/Time parsing and formatting

As a bunch commits were just made, it is a good opportunity for a spotlight on dwsDateTime and TdwsFormatSettings.

The class was initially born out of two needs:

  1. to properly handle per-script date FormatSettings, with multiple scripts running in the same or different threads.
  2. to have date formatting and parsing be unambiguously based on the date format string.


By default the Delphi date formatting involves a variety of format settings, from the date format to date or time separator, salted with some implicit rules. The goal of dwsDateTime was thus to start from a cleanroom implementation, with “least surprise“, predictable behaviors.

Format-based Parsing

One key difference with the RTL date parsing is that date and time separators are not used.

If you parse a date with a format string of “yyyy-mm-dd”, then “-” will be the separator
If you parse for “yyyy/mm/dd”, then “/” will be the separator.

You can even mix & match date and time separator in your format string, to match whatever you have to parse or generate. It can handle strings with fixed and no separators as well.

Performance

The implementation is now also quite faster than the RTL date format functions.
For a common format like “yyyy-mm-dd hh:nn:ss” and with Delphi 10.3:

  • date formatting is about 3x faster than FormatDateTime
  • date parsing is about 10x faster than StrToDateTime

RTL’s FormatDateTime is rather snappy out of the box. To best it, the implementation had to involve a mini-parser and a mini-stack machine. This way, a given date/time format is only parsed once, and applying it consist only in running through a list of function calls.

What’s next

Upcoming improvement will revolve around providing detailed parsing error (rather than just a Boolean or an Exception). The parser has all the dirty details, but they’re just not surfaced yet,

Non numeric month/days names are currently parsed much slower, and may get a boost. They have been left by the wayside as I have not encountered yet large sets of date/time that were using them.

Test coverage is at 97%, enough to uncover an issue in the RTL EncodeDate function 😉