Avatar of QC20N
QC20N
Flag for Denmark asked on

How do you convert integer8?

In AD almost everything is in integer8 format. How do you convert it to something useful? For an exampel, I need to find the date of LastLogon and LastLogonTimeStamp.
Editors IDEsDelphi

Avatar of undefined
Last Comment
aikimark

8/22/2022 - Mon
Geert G

ins't this just int64 ?
Geert G

QC20N

ASKER
I'm sure you are correct.

I'm sorry, but I don't know how to convert VB to Delphi. :)
Experts Exchange is like having an extremely knowledgeable team sitting and waiting for your call. Couldn't do my job half as well as I do without it!
James Murphy
MerijnB

Geert G

ok, i have set this up using adoquery for myself to actually try and reproduce your problem
i get the same error and i solved it for the lastLogin like this :

procedure TForm1.Button1Click(Sender: TObject);
var adUsr : IADsUser;
  dt: TDateTime;
  n: integer;
begin
  ADsGetObject('LDAP://'+ADOQuery1.FieldByName('distinguishedName').AsString, IADsUser, adusr);
  n := adusr.Get('logonCount');
  if n > 0 then
  begin
    ShowMessage(DateTimeToStr(adusr.LastLogin));
  end;
end;
QC20N

ASKER
Yes, I have found out that also, but if you look in the attachment the logonCount can be 0 and lastLogon can be 0, but lastLogonTimeStamp there is a value and that is what I could use.
ad.JPG
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
Geert G

actually the correct answer to this Q:
in a difficult way !

i'm still trying ...
Geert G

damn i'm good !
procedure TfrmWhoopie.Button1Click(Sender: TObject);
var adUsr : IADsUser;
  n: integer;
  disp: IDISPATCH;
  li: IADsLargeInteger;
  x: LARGE_INTEGER;
  time:Double;
  logonDate: TDateTime;
begin
  ADsGetObject('LDAP://'+ADOQuery1.FieldByName('distinguishedName').AsString, IADsUser, adusr);
  n := adusr.Get('logonCount');
  if n > 0 then
  begin
    disp := adusr.Get('LastLogonTimeStamp');
    li   := disp as IADsLargeInteger;
    x.LowPart := li.LowPart;
    x.HighPart := li.HighPart;
    time := Li2Double(x);
 
    time := time / 60;
    time := time / 10000000;
    time := time / 1440;
    logonDate := EncodeDate(1601, 1, 1);
    logonDate := logonDate + time;
 
    // this is in GMT
 
    ShowMessage(DateTimeToStr(logonDate));

Open in new window

Geert G

here is the complete code:
function Li2Double(x: LARGE_INTEGER): Double;
begin
  Result := x.HighPart * 4.294967296E9 + x.LowPart
end;
 
function GetTimeZoneBias: Integer;
var
  tz: TTimeZoneInformation;
begin
  case GetTimeZoneInformation(tz) of
    TIME_ZONE_ID_STANDARD: Result := -(tz.StandardBias + tz.Bias) div (24*60);
    TIME_ZONE_ID_DAYLIGHT: Result := -(tz.DaylightBias + tz.Bias) div (24*60);
  else
    Result := 0;
  end;
end;
 
procedure TfrmWhoopie.Button1Click(Sender: TObject);
var adUsr : IADsUser;
  n: integer;
  disp: IDISPATCH;
  li: IADsLargeInteger;
  x: LARGE_INTEGER;
  time, bias:Double;
  logonDate: TDateTime;
  fmt: TFormatSettings;
begin
  ADsGetObject('LDAP://'+ADOQuery1.FieldByName('distinguishedName').AsString, IADsUser, adusr);
  n := adusr.Get('logonCount');
  if n > 0 then
  begin
    disp := adusr.Get('LastLogonTimeStamp');
    li   := disp as IADsLargeInteger;
    x.LowPart := li.LowPart;
    x.HighPart := li.HighPart;
    time := Li2Double(x);
    bias := GetTimeZoneBias/24;
    time := time / 60;
    time := time / 10000000;
    time := time / 1440;
    logonDate := EncodeDate(1601, 1, 1);
    logonDate := logonDate + time + bias;
 
    ShowMessage(DateTimeToStr(logonDate));
  end;
end;

Open in new window

Experts Exchange has (a) saved my job multiple times, (b) saved me hours, days, and even weeks of work, and often (c) makes me look like a superhero! This place is MAGIC!
Walt Forbes
QC20N

ASKER
:)

I get a undeclared identifier in line 18 on Li2Double(x)
QC20N

ASKER
Ohhh, forget that the last comment.
aikimark

@Geert

Wouldn't it have been easier to use the (wrapped) FileTimeToSystemTime function?
http://www.swissdelphicenter.ch/torry/showcode.php?id=30
http://www.jpgriffiths.com/tutorial/api%5Cfiletimetodatetime.html
https://www.experts-exchange.com/questions/23013334/Convert-PT-SYSTIME-to-Delphi-TDateTime.html

I'm not poo-pooing your solution, but it seems to reinvent the wheel (so to speak).
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
Geert G

well, if you supply the routine for converting li to TFileTime
then i'm sure that will work

disp := adusr.Get('LastLogonTimeStamp');
li   := disp as IADsLargeInteger;

QC20N

ASKER
I'm lost.

disp := adusr.Get('LastLogonTimeStamp');
li   := disp as IADsLargeInteger;

it seems to be the same, right?
Geert G

i was hoping aikimark would post the next lines for converting disp or li to TFileTime ...
All of life is about relationships, and EE has made a viirtual community a real community. It lifts everyone's boat
William Peck
aikimark

I thought the Integer8 = Int64 argument was an agreed upon fact from earlier in this discussion thread.  There shouldn't be any need to convert the bytes, just cast them.
aikimark

By the time I return to this thread, someone else will probably have posted.  If not, I'll post this evening.  Billable work awaits.
Geert G

ok here is the billable work  :)
and a bow with a flourish of the hat to aikimark

procedure TfrmWhoopie.Button1Click(Sender: TObject);
var adUsr : IADsUser;
  n: integer;
  disp: IDISPATCH;
  li: IADsLargeInteger;
  logonDate: TDateTime;
  lpSysTime: TSystemTime;
  ft: TFileTime;
begin
  ADsGetObject('LDAP://'+ADOQuery1.FieldByName('distinguishedName').AsString, IADsUser, adusr);
  n := adusr.Get('logonCount');
  if n > 0 then
  begin
    disp := adusr.Get('LastLogonTimeStamp');
    li   := disp as IADsLargeInteger;
 
    ft.dwLowDateTime := li.LowPart;
    ft.dwHighDateTime := li.HighPart;
    if FileTimeToSystemTime(ft, lpSysTime) then
    begin
      LogonDate := SystemTimeToDateTime(lpSysTime);
      ShowMessage(DateTimeToStr(logonDate));
    end;
  end;
end;

Open in new window

⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
aikimark

Geert

Most excellent, dude.  No flourish necessary, but I do appreciate the kudos.

Your answer is certainly more complete than the one I would have posted, since I don't have any AD access on my system.  You were able to post a tested solution.
Geert G

well, i admit, i rarely test things,
but for this i made an exception
aikimark

@Geert

Did your message box timestamp equal what you saw in AD?  If not, then you might need to adjust the time zone.  I added one variable declaration and one statement to your (excellent) code to do this.  

However, I don't know if the questioner has to worry about UTC timestamp adjustments in a worldwide enterprise.
procedure TfrmWhoopie.Button1Click(Sender: TObject);
var adUsr : IADsUser;
  n: integer;
  disp: IDISPATCH;
  li: IADsLargeInteger;
  logonDate: TDateTime;
  lpSysTime: TSystemTime;
  ft: TFileTime;
  localft: TFileTime;   //*NEW*
begin
  ADsGetObject('LDAP://'+ADOQuery1.FieldByName('distinguishedName').AsString, IADsUser, adusr);
  n := adusr.Get('logonCount');
  if n > 0 then
  begin
    disp := adusr.Get('LastLogonTimeStamp');
    li   := disp as IADsLargeInteger;
 
    ft.dwLowDateTime := li.LowPart;
    ft.dwHighDateTime := li.HighPart;
    if FileTimeToLocalFileTime(ft, localft) then   //*NEW* time zone shift
      if FileTimeToSystemTime(localft, lpSysTime) then
      begin
        LogonDate := SystemTimeToDateTime(lpSysTime);
        ShowMessage(DateTimeToStr(logonDate));
      end;
  end;
end;

Open in new window

This is the best money I have ever spent. I cannot not tell you how many times these folks have saved my bacon. I learn so much from the contributors.
rwheeler23
QC20N

ASKER
Could you please clarify, what you mean by "...about UTC timestamp adjustments in a worldwide enterprise."?
Geert G

in my last example i didn't have to add a bias for the time zone
in the one before that (with the reinvention of the wheel) i did ...
Geert G

he means that depending on the country and daylaight saving time,
you need to add a offset to the UTC (or GMT) time
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
aikimark

@QC20N

FileTimes (and other timestamps stored in 8 byte non floating point format) are actually UTC formats.  Coordinated Universal Time is a date/time large integer value representing the number of 100 nanosecond intervals since midnight 1/1/1601.
Reference.
http://msdn.microsoft.com/en-us/library/ms724290(VS.85).aspx

Such times are expressed in GMT, so that they may be compared across time zones.  For instance, if I collect system log data from both an East coast and West coast data center, GMT timestamps give me a time standard that is independent of geographic location.

==============================
If your AD data comes from the UK, there would be no difference between the AD timestamps and the adjusted/local time.  However, you might see a lastLogonTimestamp value displayed in AD that is some hours different than that displayed by the Delphi code without local time adjustment.  

Moreover, you might be collecting login times from several different AD servers from several different time zones.  If you wanted to report these times relative to your (reporting system) time zone, you would want to adjust the UTC values for local time.

You do not have to make the local time adjustment.  But be aware of the potential difference between your local time and the AD timestamps.
QC20N

ASKER
Well, ok. No, that is not important.
aikimark

@QC20N

Using unadjusted-time version of Geert's most recent routine post, is there a difference between the timestamp displayed by the program and the timestamp you see in AD?
Your help has saved me hundreds of hours of internet surfing.
fblack61
QC20N

ASKER
Well the date and time for user is:
15-09-2008 11:02:53

Geert outcome is:
15-09-2008 09:02:53
Aikimark outcome is:
15-09-2008 10:02:53

but you have to have in mind that Time Zone is: CET +1 and we are running daylight. I don't know if some of this is causing that the time is not correct.
ASKER CERTIFIED SOLUTION
Geert G

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.
QC20N

ASKER
So what should I do now?
SOLUTION
aikimark

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.