如何在Java中设置系统时间?

时间:2011-06-01 15:39:26

标签: java systemtime

是否可以在Java中更改系统时间?

它应该在Windows和Linux下运行。我已尝试使用Runtime类,但权限存在问题。

这是我的代码:

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);

cmd的输出是:

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

但系统时间与以前相同。

我将设置时间,因为我正在编写NTP客户端,并且我从NTP服务器获得时间并将其设置。

9 个答案:

答案 0 :(得分:23)

Java没有API来执行此操作。

执行此操作的大多数系统命令都需要管理员权限,因此除非您以管理员/ root身份运行整个过程或使用Runtime / runas,否则sudo无法提供帮助。

根据您的需要,您可以替换System.currentTimeMillis()。有两种方法:

  1. 通过调用您自己可以替换的静态方法替换对System.currentTimeMillis()的所有来电:

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

    对于测试,您可以使用其他时间返回的内容覆盖INSTANCE。添加更多方法来创建Date和类似对象。

  2. 如果并非所有代码都在您的控制之下,请安装ClassLoader,它会为System返回不同的实现。这比你想象的更简单:

    @Override
    public Class<?> loadClass( String name, boolean resolve ) {
        if ( "java.lang.System".equals( name ) ) {
            return SystemWithDifferentTime.class;
        }
    
        return super.loadClass( name, resolve );
    }
    

答案 1 :(得分:22)

一种方法是使用本机命令。

对于Windows,需要两个命令(日期和时间):

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

对于linux,单个命令处理日期和时间:

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

答案 2 :(得分:4)

您只能通过以root用户身份或管理员身份运行命令行工具来设置系统时间。命令不同但您可以先检查操作系统并为该操作系统运行相应的命令。

答案 3 :(得分:2)

您可以使用JNI来设置系统时间。这适用于Windows。您需要了解JNIC

这是JNI函数,原型将由javah实用程序

生成
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);   
}

Java JNI包装器将是

class TimeSetter {

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

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

最后,使用它

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);
    }
}

答案 4 :(得分:2)

在某些情况下,进程不会以管理员权限运行,但仍具有设置系统时间的权限。可以使用Java Native Access来更改系统时间并使用Java中的所有必需源(与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);
    }       
}

答案 5 :(得分: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);
        }
    }
}

在Windows管理员模型下运行此代码。

答案 6 :(得分: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();
        }
    }
}

答案 7 :(得分:0)

您可以使用以下代码更改日期或在当前日期中添加日期。它在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);

在上面的代码中,我将1天添加到了当前日期,您可以为strExpectedDate传递任何日期,这仅适用于Windows

答案 8 :(得分:0)

我用快捷方式做到了。快捷方式通过命令链接到 cmd,更改时间或将时间与服务器时间同步。由于应使用管理员权限调用更改系统设置快捷方式,因此有一种方法可以自动设置快捷方式标志 Run as administrator。为了确保同步成功,有一个方法 safeSynchronize 将时间更改为假时间,然后才询问服务器时间。对我来说它完美无缺。

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 w32tm start");
        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);
    }
}