14

I have to store date values (TDateTime) in a string format. What is the best way to do this? I considered the following approaches:

FloatToStr : looses precision, depends on locale settings

`FloatToStr' with format settings : looses precision

DateTimeToStr : depends on locale settings

DateTimeToStr with format settings : ?

Are there any other alternatives? How do they compare in terms of

  • Size in memory
  • Independence of locale settings
  • Precision
Toby Allen
  • 10,997
  • 11
  • 73
  • 124
jpfollenius
  • 16,456
  • 10
  • 90
  • 156

4 Answers4

17

Use ISO-8601 format, as detailed in http://en.wikipedia.org/wiki/ISO_8601

If you need to save storage space, you can use the "compact" layout, e.g. '20090621T054523'.

You can use e.g. FormatDateTime('yyyymmddThhnnss',aDateTime) to produce it.

About time zone and localisation (from wikipedia):

There are no time zone designators in ISO 8601. Time is only represented as local time or in relation to UTC.

If no UTC relation information is given with a time representation, the time is assumed to be in local time. While it may be safe to assume local time when communicating in the same time zone, it is ambiguous when used in communicating across different time zones. It is usually preferable to indicate a time zone (zone designator) using the standard’s notation.

So you should better convert the time into UTC, then append 'Z' at the end of the timestamp. Or use +hh/-hh according to your local time zone. The following times all refer to the same moment: "18:30Z", "22:30+04", "1130-0700", and "15:00-03:30".

For a better resolution, you can add sub-second timing by adding a fraction after either a comma or a dot character: e.g. to denote "14 hours, 30 minutes, 10 seconds and 500 ms", represent it as "14:30:10,5", "143010,5", "14:30:10.5", or "143010.5". You can add several decimals to increase resolution.

If you need fast Iso8601 conversion routines (working with UTF-8 content), take a look at the corresponding part in SynCommons.pas. It's much faster than the default SysUtils functions.

PS:

If your purpose is just to store TDateTime as text in a pure Delphi application, you can use a not standard but fast:

function DateTimeToText(const aDateTime: TDateTime): string;
begin
  result := IntToStr(PInt64(@aDateTime)^);
end;

function TextToDateTime(const aText: string): TDateTime;
begin
  PInt64(@result)^ := StrToInt64Def(aText,0);
end;

Using the Int64 binary layout of TDateTime/double memory structure will be faster than any other floating-point related conversion.

Arnaud Bouchez
  • 42,305
  • 3
  • 71
  • 159
6

Generally I would recommend to store datetimes in ISO format as string: yyyy-mm-dd hh:nn:ss.mmmm

EDIT: if you want to minimize space, you can leave out all the separators and format it like: yyyymmddhhnnssmmmm

Thorsten Engler
  • 2,333
  • 12
  • 13
3

FormatDateTime('yyyymmddhhnnss.zzz', Now)

Misha
  • 1,816
  • 1
  • 13
  • 16
  • 3
    I would suggest using yyyymmddhhnnss.zzz as the format string. This way, it'll be locale independent and on top of that you'd be able to perform sorting on them. – HeartWare May 19 '11 at 08:26
  • 1
    HeartWare is right, it's not a good idea to *store* dates with 'dd/mm' at the beginning. Perhaps better for display in non English countries, but less logical for the computer POV. – Arnaud Bouchez May 19 '11 at 08:35
  • Edited to reflect the above comments. BTW, I always store times as UTC times. – Misha May 19 '11 at 08:54
  • @A.Bouchez Uh, the "original" English country (England) also uses d-m-y order. I believe it is only the States where the month comes before the day. But I can understand why you would think it is an English thing, with all the English speaking software coming from the States... – Marjan Venema May 19 '11 at 08:56
  • @Marjan You're right... from my "douce France", my view is a bit rude and wrong. ;) – Arnaud Bouchez May 19 '11 at 09:03
0

How much precision do you need? You could take, say, the number of milliseconds since, say, 1/1/1970, and just store that as a number converted to a string. If space is really tight, you could base64 that value. The downside would be that neither would be human readable.

Kevin Hsu
  • 1,726
  • 11
  • 14
  • what's the point of saving an integer value as a string other than wasting space and making it harder to read for machines (because they need to convert the string to a proper integer again) in turn? – 0xC0000022L May 22 '11 at 21:58
  • 1
    Because, the OP says: "I have to store date values (TDateTime) in a string format." I already know your point because it's obvious, but I was respecting the OP's constraint. – Kevin Hsu May 22 '11 at 22:45
  • 1
    Just to add, converting to integer removes the possibility of invalid date values such as "2/30/2011". – Kevin Hsu May 22 '11 at 22:47