Rodrigo Castro
Rodrigo Castro

Reputation: 1583

Converto date in Java to integer and then to Delphi Time

I have a server-equipment configuration where I need to change the equip date config, using UDP. The server is written in Java and the equipment, in Delphi.

So, the flow of the data is this:

Java server (Java date) -> UDP (integer date) -> Delphi equipment (Delphi date)

The problem is that when I pass the date as an integer, java calculates miliseconds from 1970, and Delphi, seconds. I pass then the date as following: today.getTime() / 1000, but the equipment understands this as a 2008 date, when we're on 2012.

I can change the Java code, but the equipment is 3rd party and I don't have access to it's source code.

There's difference between Java and Delphi date parsing that allow this discrepancy?

EDIT: Thanks to MДΓΓ БДLL I noticed I was multiplying by 1000 instead of dividing by it, I now have a better date, but still wrong (was somewhen in 2033, now it's in 2008).

Upvotes: 6

Views: 3946

Answers (4)

Remy Lebeau
Remy Lebeau

Reputation: 595981

Delphi's DateUtils unit has UnixToDateTime() and DateTimeToUnix() functions for converting between TDateTime and Unix timestamps, which are expressed as seconds from the Unix epoch (Jan 1 1970 00:00:00 GMT):

// 1325606144 = Jan 3 2012 3:55:44 PM GMT

uses
  DateUtils;

var
  DT: TDateTime;
  Unix: Int64;
begin
  DT := UnixToDateTime(1325606144);
  // returns Jan 3 2012 3:55:44 PM

  Unix := DateTimeToUnix(EncodeDate(2012, 1, 3) + EncodeTime(15, 55, 44, 0));
  // returns 1325606144
end;

Java's Date class, on the other hand, is based on milliseconds from the Unix epoch instead. That is easy to take into account, though:

uses
  DateUtils;

function JavaToDateTime(Value: Int64): TDateTime;
begin
  Result := UnixToDateTime(Value div 1000);
end;

function DateTimeToJava(const Value: TDateTime): Int64;
begin
  Result := DateTimeToUnix(Value) * 1000;
end;

Alternatively:

uses
  SysUtils, DateUtils;

// UnixDateDelta is defined in SysUtils...

function JavaToDateTime(Value: Int64): TDateTime;
begin
  Result := IncMilliSecond(UnixDateDelta, Value);
 end;

function DateTimeToJava(const Value: TDateTime): Int64;
begin
  Result := MilliSecondsBetween(UnixDateDelta, Value);
  if Value < UnixDateDelta then
    Result := -Result;
end;

Either way:

// 1325606144000 = Jan 3 2012 3:55:44 PM GMT

var
  DT: TDateTime;
  Java: Int64;
begin
  DT := JavaToDateTime(1325606144000);
  // returns Jan 3 2012 3:55:44 PM

  Java := DateTimeToJava(EncodeDate(2012, 1, 3) + EncodeTime(15, 55, 44, 0));
  // returns 1325606144000
end;

Upvotes: 6

Jan Doggen
Jan Doggen

Reputation: 9096

Get the JSON superobect package from www.progdigy.com and extract the functions JavaToDelphiDateTime and v.v. from the source files.

Updated 3 Mar 2014:

Progdigy.com no longer serves these files. Get the files from Google. The official 1.2.4 ZIP file in the download section http://code.google.com/p/superobject/downloads/list dates from 2010, but the individual files in http://code.google.com/p/superobject/source/browse have updates up until Oct 2012.

You must use those updated files because there was an obscure error in datetime conversions happening around the switch to daylight savings time in leapyears.

Upvotes: 1

Henri Gourvest
Henri Gourvest

Reputation: 989

As far I know Java date is based on UTC so you also have to convert local time from/to UTC. These functions use milliseconds, adapt the code to your needs.

function TzSpecificLocalTimeToSystemTime(
  lpTimeZoneInformation: PTimeZoneInformation;
  lpLocalTime, lpUniversalTime: PSystemTime): BOOL; stdcall; external 'kernel32.dll';

function SystemTimeToTzSpecificLocalTime(
  lpTimeZoneInformation: PTimeZoneInformation;
  lpUniversalTime, lpLocalTime: PSystemTime): BOOL; stdcall; external 'kernel32.dll';

function JavaToDelphiDateTime(const dt: int64): TDateTime;
var
  t: TSystemTime;
begin
  DateTimeToSystemTime(25569 + (dt / 86400000), t);
  SystemTimeToTzSpecificLocalTime(nil, @t, @t);
  Result := SystemTimeToDateTime(t);
end;

function DelphiToJavaDateTime(const dt: TDateTime): int64;
var
  t: TSystemTime;
begin
  DateTimeToSystemTime(dt, t);
  TzSpecificLocalTimeToSystemTime(nil, @t, @t);
  Result := Round((SystemTimeToDateTime(t) - 25569) * 86400000)
end;

Upvotes: 3

Ken White
Ken White

Reputation: 125669

A Unix time stamp is the same as the one used in Java. Delphi's TDateTime, on the other hand, is based on a starting date of 12:01 AM on 12/30/1899 (it's a COM compatibility thing), so some conversion is necessary. These functions will do it; I've also added a quick piece of test code to show the conversion works correctly both ways.

const
  UnixStartDate = 25569.0;

function DateTimeToUnixTime(const ADateTime: TDateTime): Cardinal;
begin
  Result := Round(ADateTime - UnixStartDate) * 86400;
end;

function UnixTimeToDateTime(const UnixDate: Cardinal): TDateTime;
begin
  Result := UnixDate / 86400 + UnixStartDate;
end;

procedure TForm1.Button1Click(Sender: TObject);
var  StartDate: TDateTime;
  UnixDate: Cardinal;
begin
  StartDate := Date();
  Memo1.Lines.Add('Start Date: ' + DateToStr(StartDate));
  UnixDate := DateTimeToUnixTime(StartDate);
  Memo1.Lines.Add('DateTimeToUnixTime = ' + IntToStr(UnixDate));
  Memo1.Lines.Add('UnixTimeToDateTime = ' + DateToStr(UnixTimeToDateTime(UnixDate)));
end;

Upvotes: 5

Related Questions