Inverse function of FormatDateTime - delphi

I am looking for a function to reverse any string (YYYYMDD,YY/MM/DD,YYMMDD,...) created by the function FormatDateTime to datetime.
example
I have a string-date in format YYYYMMDDcreated by FormatDateTime
mydatestr:=FormatDateTime('YYYYMMDD',Mydate);
now how I can convert mydatestr to DateTime again?
UPDATE
these functions
function StrToDate(const S: string): TDateTime; overload;
function StrToDate(const S: string;
const FormatSettings: TFormatSettings): TDateTime; overload;
function StrToDateTime(const S: string): TDateTime; overload;
function StrToDateTime(const S: string;
const FormatSettings: TFormatSettings): TDateTime; overload;
do not support passing a string with the format to convert.
I am looking something like this
Mydatetime:=InvFormatDatetime('20091225','yyyymmdd');
or
Mydatetime:=InvFormatDatetime('20090108','yyyyddmm');

It is quite easy with existing solution, StrToDateFmt function in rxDateutil.pas unit from RX package, which can be downloaded here: http://sourceforge.net/projects/rxlib/
EDIT:
Mentioned above function and StrToDateFmt from rxDateutil.pas are doing exactly what you expect, converting string to datetime using specified string mask, the code is too large to be included as this unit contains also other date functions, some of them required for converting string to date.
Example of use:
Result := StrToDateFmtDef('MM/DD/YYYY', '11/11/2011', Now);

Note: Unfortunately, as pointed out by Martien in this answer's comments, this solution will not work for cases where the date includes no date separator. However, I'm going to leave the answer up for anyone that may find it useful regardless.
I liked Tuncay's answer but there were a couple of problems with it. I'd have left a comment but I don't have enough reputation points.
So, here's the corrected version of Tuncay's answer (amending "TFormatSetting" missing an "s" and specified the format settings date separator):
function AnyStringToDate(fmt, dt: String) : TDateTime;
var
fs : TFormatSettings;
Begin
fs := TFormatSettings.Create;
fs.DateSeparator := '-';
fs.ShortDateFormat := fmt;
result := StrToDateDef(dt, 0, fs);
End;
Identical to Tuncay's answer, AnyStringToDate can be used as follows:
mydate := AnyStringToDate('YYYY-MM-DD', '2015-01-20');

Without using any external library, you can do something like:
function AnyStringToDate(fmt, dt: String) : TDateTime;
var
fs : TFormatSettings;
Begin
fs := TFormatSettings.Create;
fs.ShortDateFormat := fmt;
result := StrToDateDef(dt, 0, fs);
End;
and then use it like:
mydate := AnyStringToDate('YYYY-MM-DD', '2015-01-20');
I havent compiled this, but the idea simple.

You could use StrToDateFmt function of JvJCLUtils unit belonging to JEDI Code Library
in your case :
Function InvFormatDatetime ( dateString :String; dateFormat :String ) : TDateTime;
begin
Result := JvJCLUtils.StrToDateFmt ( dateFormat, dateString );
end;

Did you check StrToDate and StrToDateTime ?

I know its too late but just for interest sake, with Delphi XE6 onwards you can now do the following
uses
System.DateUtils;
var
dt: TDateTime;
begin
dt := ISO8601ToDate('20190408');
end.
dt will now be 2019/04/08

Function InvFormatDatetime (Cadena:String; Formato:String) : TDateTime;
Var
PosD, PosM, PosY : Integer;
sD, sM, sY : String;
begin
sd := '0';
sm := '0';
sy := '0';
If Length(Cadena) = Length(Formato) Then
Begin
Formato := UpperCase(Formato);
PosD := Pos('D',Formato);
PosM := Pos('M',Formato);
PosY := Pos('Y',Formato);
sd := Copy(Cadena,PosD,2);
sm := Copy(Cadena,PosM,2);
if Length(Cadena) = 6 then
begin
sy := Copy(Cadena,PosY,2);
if StrToInt(sy) > 50 then
sy := '19'+sy
else
sy := '20'+sy;
end
else
sy := Copy(Cadena,Posy,4);
End;
Result := EncodeDate(StrToInt(sY),
StrToInt(sM),
StrToInt(sD));
End;
greetings

Related

How to convert string to date time (Non English) in Delphi

I am unable to convert my string format date (French) to TDateTime format. I am working on files which contain string format dates in English and other languages.
For example, 1st March 2021 will be in an English file as 1 mar 2021, and in a French file as 1 mars 2021.
var
_StrDate: String;
_MyDateTime: TDateTime;
begin
_StrDate := '1 mar 2021'; // English
_MyDateTime := VarToDateTime(_StrDate); // works perfect
_StrDate := '1 mars 2021'; // French
_MyDateTime := VarToDateTime(_StrDate); // error
end;
I'm getting this error msg:
Could not convert variant of type (UnicodeString) into type (Date)
I wrote a parser for the specific format your have. Well, I have done the basic work, you'll have to modify it for example to use both French and English month names as well as short names. You should also add some tests to filter invalid values out. And probably ignore character casing in the name of months.
const
MonthsFR : array [1..12] of String = (
'janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet',
'août', 'septembre', 'octobre', 'novembre', 'décembre');
function StrToDateFR(const S : String; out ADate : TDateTime) : Boolean;
var
A : TStringDynArray;
D : Word;
M : Word;
Y : Word;
begin
ADate := 0;
Result := FALSE;
A := SplitString(S, ' ');
if Length(A) <> 3 then
Exit;
D := StrToInt(A[0]);
M := High(MonthsFR);
while (M > Low(MonthsFR)) and (A[1] <> MonthsFR[M]) do
Dec(M);
if M < Low(MonthsFR) then
Exit;
Y := StrToInt(A[2]);
ADate := EncodeDate(Y, M, D);
Result := TRUE;
end;
One idea to expand the code is to have several similar functions for other languages. Since the function return TRUE only when the format is recognized, you may call various versions in sequence until one return true.
function StrToDateFR(const S: String; out ADate: TDateTime): Boolean;
var
A: TStringDynArray;
D: Word;
M: Word;
Y: Word;
i: integer;
begin
ADate := 0;
Result := FALSE;
A := SplitString(S, ' ');
if Length(A) <> 3 then
Exit;
D := StrToInt(A[0]);
M := 0;
for i := Low(MonthsFR) to High(MonthsFR) do
begin
if SameText(A[1], MonthsFR[i]) then
begin
M := i;
Break
end;
end;
if M = 0 then
Exit;
Y := StrToInt(A[2]);
ADate := EncodeDate(Y, M, D);
Result := TRUE;
end;

Is there a Delphi RTL function that can convert the ISO 8601 basic date format to a TDate?

ISO 8601 describes a so called basic date format that does not use the dashes:
20140507 is a valid representation of the more readable 2014-05-07.
Is there a Delphi RTL function that can interpret that basic format and convert it to a TDateTime value?
I tried
function TryIso2Date(const _s: string; out _Date: TDateTime): Boolean;
var
Settings: TFormatSettings;
begin
Settings := GetUserDefaultLocaleSettings;
Settings.DateSeparator := #0;
Settings.ShortDateFormat := 'yyyymmdd';
Result := TryStrToDate(_s, Date, Settings);
end;
TryIso2Date('20140507', dt);
but it did not work because the DateSeparator could not be found in the string.
The only solution I so far came up with (other than writing the parsing code myself) is adding the missing dashes before calling TryStrToDate:
function TryIso2Date(const _s: string; out _Date: TDateTime): Boolean;
var
Settings: TFormatSettings;
s: string;
begin
Settings := GetUserDefaultLocaleSettings;
Settings.DateSeparator := #0;
Settings.ShortDateFormat := 'yyyy-mm-dd';
s := Copy(_s,1,4) + '-' + Copy(_s, 5,2) + '-' + Copy(_s, 7);
Result := TryStrToDate(_s, Date, Settings);
end;
TryIso2Date('20140507', dt);
This works, but it feels rather clumsy.
This is Delphi XE6, so it should have the most recent RTL possible.
You can use Copy to pull out the values as you already do. And then you just need to encode the date:
function TryIso8601BasicToDate(const Str: string; out Date: TDateTime): Boolean;
var
Year, Month, Day: Integer;
begin
Assert(Length(Str)=8);
Result := TryStrToInt(Copy(Str, 1, 4), Year);
if not Result then
exit;
Result := TryStrToInt(Copy(Str, 5, 2), Month);
if not Result then
exit;
Result := TryStrToInt(Copy(Str, 7, 2), Day);
if not Result then
exit;
Result := TryEncodeDate(Year, Month, Day, Date);
end;

thousand separator in integer values [duplicate]

var i : integer;
i := 1234567;
Given the above, I want the string "1,234,567" as output (assuming UK locale). IntToStr just gives me "1234567". I'm sure there's a one-liner for this, but I can't find it...
Try the format function.
Label1.Caption := Format('%.0n', [i + 0.0]);
Or if you need to be threadsafe or want to ensure you use the system default locale or want to specify one:
function FormatIntFromLCID(const AValue: Integer; const LCID: Integer = LOCALE_SYSTEM_DEFAULT): string;
var
AFormatSettings: TFormatSettings;
begin
GetLocaleFormatSettings(LCID, AFormatSettings);
Result := FormatFloat('#,##0',AValue, AFormatSettings);
end;
see this post for a more complete discussion about formatting/locales
s := FormatFloat('#,##0', i);
I have this function to do it, where d means perhaps decimal number:
function dn(i: integer): string;
begin
result := format('%.0n', [i.ToDouble])
end;
Format('%n', [12345.678]);
stringreplace(format('%n',[1234567.0]),'.00','',[]);

Convert File Time To Julian Date in Delphi

I have a problem getting file modified time as julian date. My Delphi 2010 looks like this:
AHandle := FindFirstFile(PChar('C:\*'), FindData);
if (AHandle <> INVALID_HANDLE_VALUE) then
begin
repeat
if (FindData.dwFileAttributes And FILE_ATTRIBUTE_DIRECTORY = 0) then
ModifJulianDate := FileTimeToJulianDate(FindData.ftLastWriteTime);
until Not FindNextFile(AHandle, FindData);
end;
The problem is: FileTimeToJulianDate() returned result has one hour offset, ie. if the file's modified time is 10:01, this code returns 9:01!!
How can I fix this?
The functionality that you are looking for, assuming your answer is accurate, is most easily implemented using FileTimeToLocalFileTime.
function UTCFileTimeToLocalDateTime(const UTCFileTime: TFileTime): TDateTime;
var
LocalFileTime: TFileTime;
LocalSystemTime: TSystemTime;
begin
if not FileTimeToLocalFileTime(UTCFileTime, LocalFileTime) then
RaiseLastOSError;
if not FileTimeToSystemTime(LocalFileTime, LocalSystemTime) then
RaiseLastOSError;
Result := SystemTimeToDateTime(LocalSystemTime);
end;
Or if you prefer to use SystemTimeToTzSpecificLocalTime then do so like this:
function UTCFileTimeToLocalDateTime(const UTCFileTime: TFileTime): TDateTime;
var
UTCSystemTime, LocalSystemTime: TSystemTime;
begin
if not FileTimeToSystemTime(UTCFileTime, UTCSystemTime) then
RaiseLastOSError;
if not SystemTimeToTzSpecificLocalTime(nil, UTCSystemTime, LocalSystemTime) then
RaiseLastOSError;
Result := SystemTimeToDateTime(LocalSystemTime);
end;
With the help of LU RD & the code posted here, I managed to get what I wanted, in case someone need something like this, here's my code:
function GetDateFileModified(UTCTime : TFileTime{FindData : TWin32FindData}) : TDateTime;
// Return the file modified date as a string in local time
var
GMTsystemTime : Windows.TSystemTime;
LocalSysTime : Windows.TSystemTime;
TimeZone : Windows._TIME_ZONE_INFORMATION;
begin
Result := 0;
// Get Timezone Information
GetTimeZoneInformation(TimeZone);
// UTCTime := FindData.ftLastWriteTime;
if FileTimeToSystemTime(UTCTime, GMTsystemTime) then
begin
SystemTimeToTzSpecificLocalTime(#TimeZone, GMTsystemTime, LocalSysTime);
Result := SystemTimeToDateTime(LocalSysTime);
end;
end;

How can I test my WideReplace function?

OS: Hungarian Windows (Windows 1250)
Under Delphi 6 Prof there is no WideStringPos, WideStringCopy, WideStringReplace...
But in an XML based project I need to use them.
Because that I tried to write "something like" these functions.
But I'm not sure they are working as I want...
Because Delphi converts the Wide to Ansi and reverse in the background, I cannot be sure that my code is safe from these side effects... :-)
The code is very primitive - I need the solution quickly...
function WideStringCopy(WWhat : WideString; From, HowMany : integer) : WideString;
var
i : integer;
l : integer;
wc : WideChar;
begin
Result := '';
if WWhat = ''
then Exit;
if (HowMany <= 0)
then Exit;
if (From < 1)
then From := 1;
l := From + HowMany - 1;
if l > Length(WWhat)
then l := Length(WWhat);
for i := From to l do begin
wc := WWhat[i];
Result := Result + wc;
end;
end;
function WideStringPos(WWhere, WWhat : WideString) : integer;
var
wscomp : WideString;
i : integer;
begin
Result := 0;
for i := 1 to Length(WWhere) do begin
wscomp := WideStringCopy(WWhere, i, LengtH(WWhat));
if WideSameStr(wscomp, WWhat)
then begin
Result := i;
Exit;
end;
end;
end;
function WideStringReplace(WWhere, WFrom, WTo : WideString) : WideString;
var
actpos : integer;
wcomp : WideString;
wc : WideChar;
begin
Result := '';
actpos := 1;
while actpos <= Length(WWhere) do begin
wcomp := WideStringCopy(WWhere, actpos, Length(WFrom));
if WideSameStr(wcomp, WFrom) then begin
Result := Result + WTo;
inc(actpos, Length(WFrom));
end else begin
wc := WWhere[actpos];
Result := Result + wc;
inc(actpos);
end;
end;
end;
I have two questions about it:
Do you see any piece of code that surely making bad result (converting the Wide to Ansi silently, and causing character loosing)?
Do you know some character with I can test this code?
For example, chr(XXX) what is remaining when my converters are keeping the Wide rules, but loosing if I make wrong code...
Thanks for every info you will write...
Do you know some character with I can test this code?
Any codepage beyond Win1250 - for example Cyrillic Win1251, Greek, Hebrew - almost all letters there would be missed from 1250/1252
You can take Jedi CodeLibrary and use its locale conversion routines: make a string consisting of #128 till #255 in some encoding like aforementioned, convert it to Unicode from that codepage and then convert back from Unicode to Hungarian codepage.
function StringToWideStringEx(const S: AnsiString; CodePage: Word): WideString;
function WideStringToStringEx(const WS: WideString; CodePage: Word): AnsiString;
Or in one call
function TranslateString(const S: AnsiString; CP1, CP2: Word): AnsiString;
Then look which chars failed to translate and turned into ReplacementCharacter.
However in JCL you'd have your Pos function and such ready to use. And XML parser. So why bother ?

Resources