How can I set the System Time in Java?
Asked Answered
A

9

22

Is it possible to change the System Time in Java?

It should run under Windows and Linux. I've tried it with the Runtime Class in but there is a problem with the permissions.

This is my code:

String cmd="date -s \""+datetime.format(ntp_obj.getDest_Time())+"\"";
try {
    Runtime.getRuntime().exec(cmd);
} catch (IOException e1) {
// TODO Auto-generated catch block
  e1.printStackTrace();
}
System.out.println(cmd);

The output of cmd is:

date -s "06/01/2011 17:59:01"

But the System time is the same as before.

I will set the time because I am writing an NTP-Client and there I get the time from a NTP-Server and will set it.

Automatic answered 1/6, 2011 at 15:39 Comment(4)
Why do you need to set the System time?Zorine
Also include the current relevant code and error/problem's encountered (e.g. what was "wrong" with the permissions?)Freely
@Zorine Because the System time is incorrect / not accurate?Oolite
You need a separate time command on Windows. Runtime.getRuntime().exec("cmd /C time " + strTimeToSet); // hh:mm:ssNecrolatry
K
26

Java doesn't have an API to do this.

Most system commands to do it require admin rights, so Runtime can't help unless you run the whole process as administrator/root or you use runas/sudo.

Depending on what you need, you can replace System.currentTimeMillis(). There are two approaches to this:

  1. Replace all calls to System.currentTimeMillis() with a call to a static method of your own which you can replace:

    public class SysTime {
        public static SysTime INSTANCE = new SysTime();
    
        public long now() {
            return System.currentTimeMillis();
        }
    }
    

    For tests, you can overwrite INSTANCE with something that returns other times. Add more methods to create Date and similar objects.

  2. If not all code is under your control, install a ClassLoader which returns a different implementation for System. This is more simple than you'd think:

    @Override
    public Class<?> loadClass( String name, boolean resolve ) {
        if ( "java.lang.System".equals( name ) ) {
            return SystemWithDifferentTime.class;
        }
    
        return super.loadClass( name, resolve );
    }
    
Keldah answered 1/6, 2011 at 15:46 Comment(4)
Will installing a class loader with a java.lang.* name always work?Oolite
Yes, there is nothing magic about java.lang as far as classloading is concerned. There should be nothing magic about it as far as JIT and VM are concerned - if you replace String.class with something else, this should work since the class is loaded like anything else.Keldah
I'm testing approach no. 2 and getting: java.lang.SecurityException: Prohibited package name: java.lang so I think there actually is something "magic" about java.lang.Liatris
@BoneGoat: No, there isn't. But you have a SecurityManager installed and then, things like that aren't possible anymore. Use joda-time instead.Keldah
S
25

One way would be using native commands.

for Windows, two commands (date and time) are required:

Runtime.getRuntime().exec("cmd /C date " + strDateToSet); // dd-MM-yy
Runtime.getRuntime().exec("cmd /C time " + strTimeToSet); // hh:mm:ss

for linux, a single command handles both date and time:

Runtime.getRuntime().exec("date -s " + strDateTimeToSet); // MMddhhmm[[yy]yy]

Update after 9 year

This is not a good way to set the time of system instead of that use java.util.Clock to get the current time and provide mock implementation wherever needed to fake out the time.

Spoonbill answered 1/6, 2011 at 15:40 Comment(9)
@Oolite Not sure if there is different command/util in Mac, you can try it out on Mac's terminalSpoonbill
@JigarJoshi problem is I don't have a MacOolite
(On Windows) btw date only changes the date, we'd also need to execute the command time to change the system time.Necrolatry
@Necrolatry look for command to set time, I guess date should do itSpoonbill
As exec() forks a new process for each call, I'd recommend to concat the two windows calls like so: Runtime.getRuntime().exec("cmd /C date " + strDateToSet + "& time " + strTimeToSet);Neurocoele
Other solution: #43615987Bresee
Is there any way to do it in a mac?Chomp
@JigarJoshi please check the question: #57709097Chomp
Is it really month-day-hour-minute-year? Who came up with that date format?Blab
L
4

You can only set the system time by running a command line tool as root or Adminstrator. The command are different but you can check the OS first and run the appropriate command for that OS.

Lavonnelaw answered 1/6, 2011 at 15:41 Comment(0)
C
2

You can use JNI for setting the system time. This would work on Windows. You need to know JNI and C.

This is the JNI function, the prototype will be generated by the javah utility

JNIEXPORT void JNICALL Java_TimeSetter_setSystemTime
  (JNIEnv *env, jobject obj, jshort hour, jshort minutes) {

    SYSTEMTIME st;
    GetLocalTime(&st);  
    st.wHour = hour;      
    st.wMinute = minutes;  
    SetLocalTime(&st);   
}

The Java JNI wrapper would be

class TimeSetter {

    public native void setSystemTime( short hour, short minutes);

    static {
        System.loadLibrary("TimeSetter");
    }
}

And finally, to use it

public class JNITimeSetter {

    public static void main(String[] args) {

        short hour = 8;
        short minutes = 30;

        // Set the system at 8h 30m

        TimeSetter ts = new TimeSetter();
        ts.setSystemTime(hour, minutes);
    }
}
Cortie answered 11/6, 2013 at 2:40 Comment(0)
A
2

There are cases where the process does not run with admin rights, but it still has the permissions to set the system time. It is possible to use Java Native Access to change the system time and have all the required sources in Java (simpler compared with JNI).

package github.jna;

import com.sun.jna.Native;
import com.sun.jna.platform.win32.WinBase.SYSTEMTIME;
import com.sun.jna.win32.StdCallLibrary;

/**
 * Provides access to the Windows SetSystemTime native API call.
 * This class is based on examples found in
 * <a href="https://github.com/twall/jna/blob/master/www/GettingStarted.md">JNA Getting Started</a>
 */
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);
    }       
}
Ariellearies answered 7/8, 2015 at 7:15 Comment(0)
S
0
package myTestProject;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

public class LocalTimeChangeTest {

    private static DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public static void main(String[] args) {
        try {
            String value = "2014-12-12 00:26:14";
            Date date = dateFormat.parse(value);
            value = dateFormat.format(date);
            final Process dateProcess = Runtime.getRuntime().exec("cmd /c date "+value.substring(0, value.lastIndexOf(' ')));
            dateProcess.waitFor();
            dateProcess.exitValue();
            final Process timeProcess = Runtime.getRuntime().exec("cmd /c time "+value.substring(value.lastIndexOf(' ')+1));
            timeProcess.waitFor();
            timeProcess.exitValue();
        } catch (Exception exception) {
            throw new RuntimeException(exception);
        }
    }
}

Run this code under windows administrator model.

Schach answered 20/11, 2014 at 9:20 Comment(0)
U
0
package com.test;

public class Exec {

    public static void main(String[] args) {
        try {
            String[] cmd = {"/bin/bash","-c","echo yourPassword | sudo -S date --set='2017-05-13 21:59:10'"};
            Runtime.getRuntime().exec(cmd);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
Ulent answered 30/5, 2017 at 6:18 Comment(0)
E
0

You can change the date or add the date in current date using below code. It is working perfectly in windows:

Calendar cal = Calendar.getInstance();
cal.add(Calendar.DATE, 1);
SimpleDateFormat s = new SimpleDateFormat("MM-dd-yyyy");    
String strExpectedDate = s.format(new Date(cal.getTimeInMillis()));
Runtime rt = Runtime.getRuntime();
rt.exec("cmd /C date " + strExpectedDate);

In above code I have added 1 day to current date, You can pass any date for strExpectedDate and this will only work on windows

Elspet answered 12/6, 2019 at 8:44 Comment(0)
E
0

I did it with shortcuts. Shortcut has link to cmd with commands, changing time or synchronize time with server time. As changing system settings shortcut should be called with admin permission there is a method automatically setting shortcut flag Run as administrator. To be sure that synchronization was succesfull there is a method safeSynchronize changing time to fake time and only after that ask the server time. For me it works perfectly.

package system;

import mslinks.ShellLink;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.time.DateUtils;

import java.io.*;
import java.nio.file.Files;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.util.Calendar;
import java.util.Date;
import java.util.Random;

public class TimeSynchronizer {

    Random random = new Random();

    private int WAIT_LAG = 1000;

    private DateFormat dateFormat = new SimpleDateFormat("dd-MM-yy");
    private DateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");

    public void synchronize() throws IOException, InterruptedException {
        File file = getFile();
        makeShortcut(file, "/c net start w32time");
        callShortcut(file);
        makeShortcut(file, "/c w32tm /resync");
        callShortcut(file);
        if (file.exists()) file.delete();
    }

    public void safeSynchronize() throws IOException, InterruptedException {
        Calendar rightNow = Calendar.getInstance();
        int minute = rightNow.get(Calendar.MINUTE);
        boolean isForward = minute < 30;
        Date date = DateUtils.addMinutes(Date.from(Instant.now()), 10 * (isForward ? 1 : -1));

        setTime(date);
        synchronize();
    }

    public void setTime(Date date) throws IOException, InterruptedException {
        setTime(date, false);
    }

    public void setTime(Date date, boolean withDate) throws IOException, InterruptedException {
        File file = getFile();
        if (withDate) {
            makeShortcut(file, "/c date " + dateFormat.format(date));
            callShortcut(file);
        }
        makeShortcut(file, "/c time " + timeFormat.format(date));
        callShortcut(file);
        if (file.exists()) file.delete();
    }

    private void callShortcut(File file) throws IOException, InterruptedException {
        Process process = Runtime.getRuntime().exec(
            getSystem32Path() + "\\cmd.exe /c start /wait \"\" \"" + file.getAbsolutePath() + "\""
        );
        process.waitFor();
        process.exitValue();
    }

    private String getSystem32Path() {
        return System.getenv("SystemRoot") + "\\system32";
    }

    private File getFile() {
        return new File(random.nextInt() + "shortcut.lnk");
    }

    private void makeShortcut(File file, String command) throws IOException, InterruptedException {
        String system32Path = getSystem32Path();
        ShellLink s = new ShellLink();
        s.setTarget(system32Path + "\\cmd.exe");
        s.setCMDArgs(command);
        s.saveTo(file.getAbsolutePath());
        Thread.sleep(WAIT_LAG);

        setRunAsAdmin(file);
    }

    private void setRunAsAdmin(File file) throws IOException {
        byte[] fileContent = Files.readAllBytes(file.toPath());
        fileContent[21] = (char)32;
        FileUtils.writeByteArrayToFile(file, fileContent);
    }
}
Eureetloir answered 25/6, 2021 at 23:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.