In order to test java-code with date / time set into the past or future I want to try libfaketime (currently we just adjust the system clock, but it causes much trouble like non working kerberos, etc).
I try with this small test program:
$ cat time.java
import java.util.*;
class TimeTest {
public static void main(String[] s) {
long timeInMillis = System.currentTimeMillis();
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(timeInMillis);
java.util.Date date = cal.getTime();
System.out.println("Date: " + date);
}
}
And executes this:
LD_ASSUME_KERNEL=2.6.18 LD_PRELOAD=/usr/lib64/libfaketime.so.1 FAKETIME="-15d" /opt/IBM/WebSphere/AppServer/java_1.7_64/bin/java TimeTest
Invalid clock_id for clock_gettime: -172402[root#myhost ~]#
But as you can see I just get an error message.
The test is performed on a RHEL 6.5 server, kernel 2.6.32-431 and
libfaketime 0.9.6
Do you have any suggestions how I can solve this? I'm also interested in hearing your experiences with libfaketime and java on RHEL.
I have also reported this issue at: https://github.com/wolfcw/libfaketime/issues
Best reagards,
Erling
I've observed this incorrect behaviour as well in IBM JVM 1.7.0 while in Oracle JVM 1.6.0 this works as expected.
The explanation is that IBM JVM apparatently has an internal bug which manifests by calling clock_gettime system call with incorrect clock_id parameter (random negative value).
The workaround (not a fix) is to modify libfaketime.c to reset the clock_id to valid value in fake_clock_gettime function.
case FT_START_AT: /* User-specified offset */
if (user_per_tick_inc_set)
{
/* increment time with every time() call*/
next_time(tp, &user_per_tick_inc);
}
else
{
if (clk_id < 0) { // jvm calls clock_gettime() with invalid random negative clock_id value
clk_id = CLOCK_REALTIME;
}
switch (clk_id)
// the rest is the same
This will prevent the libfaketime.so.1 library from existing on error you are observing
printf("\nInvalid clock_id for clock_gettime: %d", clk_id);
exit(EXIT_FAILURE);
Please note this workaround has a drawback that in case JVM is incorrectly asking system for invalid clockid, we will assume valid clockid which may be not what application expects.
Related
We have [GetServerTimeZoneInformation] used defined function in MS SQL Server which returns DaylightName or StandardName, ActiveTimeBias, Bias, DaylightBias, IsDST It uses Windows registry key to get these information but I have to write the code where linux(CentOs) operating system is being used and I have to get these information using Java. What is the Java API available which can give these values?
The TimeZone class gives you access to all or most of these data, for example:
TimeZone tz = TimeZone.getDefault();
String daylightName = tz.getDisplayName(true, TimeZone.LONG);
String standardName = tz.getDisplayName(false, TimeZone.LONG);
int rawOffset = tz.getRawOffset();
int daylightOffset = tz.getDSTSavings();
boolean isInDSTNow = tz.inDaylightTime(new Date());
Note however, that Java uses its own version of tzdb, and not the system-wide installed tzdb, so there may be differences between what Java reports and what you would get from native operating system tools, especially for time zones that have been changed recently.
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.
Would it be possible to set system time with milliseconds component on Windows OS using Java?
I am trying to synchronize clocks between couple of computers but the OS API seems to offer only set time in format: HH:MM:SS.
This is what i tried:
public static void main(String[] args) throws InterruptedException, IOException {
String time="10:00:20"; // this works
String timeWithMiliseconds = "10:00:20.100"; // this doesn't change time at all
Runtime rt = Runtime.getRuntime();
rt.exec("cmd /C time " + time);
}
I am wondering how do NTP clients work if it's not possible to set milliseconds component ?
One way to deal with this issue could be to calculate time in milliseconds when server should reach next second, and sleep for that time. Is there a better, more direct way to achieve this ?
As mentioned by immibis you could use the Windows function SetSystemTime to set the time.
Find below a snippet which call the Windows function using JNA 4.2
Kernel32 kernel = Kernel32.INSTANCE;
WinBase.SYSTEMTIME newTime = new WinBase.SYSTEMTIME();
newTime.wYear = 2015;
newTime.wMonth = 11;
newTime.wDay = 10;
newTime.wHour = 12;
newTime.wMinute = 0;
newTime.wSecond = 0;
newTime.wMilliseconds = 0;
kernel.SetSystemTime(newTime);
For further information have a look into the sources of JNA and on those links
SetSystemTime Windows function and
SYSTEMTIME structure.
An introduction to JNA from 2009. Simplify Native Code Access with JNA
I found that Java gives incorrect time in MSK timezone, ignoring operating system data:
As you see, the Java time is hour ahead.
The code is follows:
package tests;
import java.util.Date;
public class Try_CurrentTime {
public static void main(String[] args) {
System.out.println(new Date());
}
}
java version is 1.8.0_25
We have no DST.
Is it possible to fix?
UPDATE
It doesn't think we have DST, because TimeZone.getDefault().inDaylightTime( new Date() ) returns false.
Refer to the Timezone Data Versions in the JRE Software chart. The change you are referring to was made in tzdata 2014f - which was first introduced in TZUpdater 1.4.6, or JRE 1.8 update 31. You said you are running 1.8 update 25.
Simply update your Java runtime to the current version.
My system time zone is (UTC+02:00) Istanbul. When I run a simple java program to display time zone, it displays "America/Rio_Branco" (which is incorrect). But when I set to any other time zones it works correctly. Also I updated my jre using tzupdater.jar (I set my path to ..\jre\lib). What could be the reason?
My code is :
import java.util.*;
import java.text.*;
public class Time
{
public static void main(String[] args){
TimeZone timeZone = TimeZone.getDefault();
System.out.println("timeZone : "+timeZone);
}
}
I replaced tzmappings file with the one from jre8 and it solved my problem.
If you read the JavaDoc you'll see this:
Gets the default TimeZone for this host. The source of the default TimeZone may vary with implementation.
Thus reason you're getting "America/Rio_Branco" is because the JDK implementation for your host (operating system) thinks you are in Rio Branco's timezone. In the comments you mention you're running Windows 7, so it might be the case that Windows incorrectly has a timezone set somewhere. I think Java on Windows checks in the registry here:
HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/TimeZoneInformation
Maybe you can check that value?