是否可以在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服务器获得时间并将其设置。
答案 0 :(得分:23)
Java没有API来执行此操作。
执行此操作的大多数系统命令都需要管理员权限,因此除非您以管理员/ root身份运行整个过程或使用Runtime
/ runas
,否则sudo
无法提供帮助。
根据您的需要,您可以替换System.currentTimeMillis()
。有两种方法:
通过调用您自己可以替换的静态方法替换对System.currentTimeMillis()
的所有来电:
public class SysTime {
public static SysTime INSTANCE = new SysTime();
public long now() {
return System.currentTimeMillis();
}
}
对于测试,您可以使用其他时间返回的内容覆盖INSTANCE。添加更多方法来创建Date
和类似对象。
如果并非所有代码都在您的控制之下,请安装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。您需要了解JNI
和C
。
这是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);
}
}