I'm working with an agent java application and it is installed on several Windows machines in different places of the world. I would like periodically synchronize windows clock (Date and Time). I have already found the native command to set time in windows by java code:
Runtime.getRuntime().exec("cmd /C date " + strDateToSet); // dd-MM-yy
Runtime.getRuntime().exec("cmd /C time " + strTimeToSet); // hh:mm:ss
or to execute
Runtime.getRuntime().exec("cmd /C date " + strDateToSet + "& time " + strTimeToSet);
But the main problem is focalizied on set date, because is possible that the date format on windows machines is not the same for all machines. For example I could have dd-MM-yy for Italian machine and yy-MM-dd for US machine. So if my application set the date with format dd-MM-yy wuold be wrong for US machine.
Knowing that I cant't use NTP (Machines into LAN with Firewall with out rules only protocol HTTPS port 443)
how can I set date correctly by java application for all windows machines ?
Which is the best solution both semplicity and maintainability ?
Note: Agent java application has already the timestamp to be set on windows machine passed by web service response, therefore is necessary only to do the setDateAndTime
TEST exec date command with format date yyyy-MM-dd on Windows (set wrong date):
I tried to implement the solution with JNA importing kernel32.dll performed the test on Windows 7 machine with timezone UTC+1 (Italy country).
I describe the steps:
1) I imported my maven project the followed dependencies:
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna-platform</artifactId>
<version>4.4.0</version>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>4.3.0</version>
</dependency>
2) I implemented the followed class:
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import com.sun.jna.Native;
import com.sun.jna.platform.win32.WinBase.SYSTEMTIME;
import com.sun.jna.win32.StdCallLibrary;
@Component
@Qualifier("windowsSetSystemTime")
public class WindowsSetSystemTime {
/**
* Kernel32 DLL Interface. kernel32.dll uses the __stdcall calling
* convention (check the function declaration for "WINAPI" or "PASCAL"), so
* extend StdCallLibrary Most C libraries will just extend
* com.sun.jna.Library,
*/
public interface Kernel32 extends StdCallLibrary {
boolean SetLocalTime(SYSTEMTIME st);
Kernel32 instance = (Kernel32) Native.loadLibrary("kernel32.dll", Kernel32.class);
}
public boolean SetLocalTime(SYSTEMTIME st) {
return Kernel32.instance.SetLocalTime(st);
}
public boolean SetLocalTime(short wYear, short wMonth, short wDay, short wHour, short wMinute, short wSecond) {
SYSTEMTIME st = new SYSTEMTIME();
st.wYear = wYear;
st.wMonth = wMonth;
st.wDay = wDay;
st.wHour = wHour;
st.wMinute = wMinute;
st.wSecond = wSecond;
return SetLocalTime(st);
}
}
3) By the test class I tried to set the followed date and time
public void setTime(){
System.out.println("START SYNC " + windowsSetSystemTime);
windowsSetSystemTime.SetLocalTime((short)2017, (short)10,(short) 29,(short) 11,(short) 35,(short) 0);
}
TEST RESULT:
As result in this case I obtained the correct date and time because the function considered daylight winter time saving that enter at 29 October 2017 3:00.
Before test, clock was set:
After test clock set:
I found out the logic SetLocalTime method into Kernel32.dll by Windows dev center documentation at link:
SetLocalTime documentation
Windows Dev center REMARKS SetLocalTime:
The system uses UTC internally. Therefore, when you call SetLocalTime, the system uses the current time zone information to perform the conversion, including the daylight saving time setting. Note that the system uses the daylight saving time setting of the current time, not the new time you are setting. Therefore, to ensure the correct result, call SetLocalTime a second time, now that the first call has updated the daylight saving time setting.