大家好,欢迎来到IT知识分享网。
//什么是开机时间?返回自启动以来的毫秒数,包括睡眠时间 long elapsedRealtime = SystemClock.elapsedRealtime(); //什么是ntp网络时间? 是网络时间协议(Network Time Protocol),它是用来同步网络中各个计算机的时间的协议。直接copy复制以下NTPClient代码即可。
解决方案:NTP网络协议时间+开机时间(返回自启动以来的毫秒数,包括睡眠时间)
步骤一:新建一个类可以命名为NTPClient.java或其他自定义名称(已验证,可直接copy使用)
public class NTPClient {
private static final int ORIGINATE_TIME_OFFSET = 24; private static final int RECEIVE_TIME_OFFSET = 32; private static final int TRANSMIT_TIME_OFFSET = 40; private static final int NTP_PACKET_SIZE = 48; private static final int NTP_PORT = 123; private static final int NTP_MODE_CLIENT = 3; private static final int NTP_VERSION = 3; // Number of seconds between Jan 1, 1900 and Jan 1, 1970 // 70 years plus 17 leap days private static final long OFFSET_1900_TO_1970 = ((365L * 70L) + 17L) * 24L * 60L * 60L; private long mOffSet; public long getOffset() {
return mOffSet; } public boolean requestTime(String host, int timeout) {
DatagramSocket socket = null; try {
socket = new DatagramSocket(); socket.setSoTimeout(timeout); InetAddress address = InetAddress.getByName(host); byte[] buffer = new byte[NTP_PACKET_SIZE]; DatagramPacket request = new DatagramPacket(buffer, buffer.length, address, NTP_PORT); // set mode = 3 (client) and version = 3 // mode is in low 3 bits of first byte // version is in bits 3-5 of first byte buffer[0] = NTP_MODE_CLIENT | (NTP_VERSION << 3); // get current time and write it to the request packet long requestTime = System.currentTimeMillis(); long requestTicks = SystemClock.elapsedRealtime(); writeTimeStamp(buffer, TRANSMIT_TIME_OFFSET, requestTime); socket.send(request); // read the response DatagramPacket response = new DatagramPacket(buffer, buffer.length); socket.receive(response); long responseTicks = SystemClock.elapsedRealtime(); long responseTime = requestTime + (responseTicks - requestTicks); // extract the results long originateTime = readTimeStamp(buffer, ORIGINATE_TIME_OFFSET); long receiveTime = readTimeStamp(buffer, RECEIVE_TIME_OFFSET); long transmitTime = readTimeStamp(buffer, TRANSMIT_TIME_OFFSET); long roundTripTime = responseTicks - requestTicks - (transmitTime - receiveTime); // receiveTime = originateTime + transit + skew // responseTime = transmitTime + transit - skew // clockOffset = ((receiveTime - originateTime) + (transmitTime - responseTime))/2 // = ((originateTime + transit + skew - originateTime) + // (transmitTime - (transmitTime + transit - skew)))/2 // = ((transit + skew) + (transmitTime - transmitTime - transit + skew))/2 // = (transit + skew - transit + skew)/2 // = (2 * skew)/2 = skew long clockOffset = ((receiveTime - originateTime) + (transmitTime - responseTime)) / 2; // if (false) Log.d(TAG, "round trip: " + roundTripTime + " ms"); // if (false) Log.d(TAG, "clock offset: " + clockOffset + " ms"); mOffSet = clockOffset; } catch (Exception e) {
return false; } finally {
if (socket != null) {
socket.close(); } } return true; } / * Reads an unsigned 32 bit big endian number from the given offset in the buffer. */ private long read32(byte[] buffer, int offset) {
byte b0 = buffer[offset]; byte b1 = buffer[offset + 1]; byte b2 = buffer[offset + 2]; byte b3 = buffer[offset + 3]; // convert signed bytes to unsigned values int i0 = ((b0 & 0x80) == 0x80 ? (b0 & 0x7F) + 0x80 : b0); int i1 = ((b1 & 0x80) == 0x80 ? (b1 & 0x7F) + 0x80 : b1); int i2 = ((b2 & 0x80) == 0x80 ? (b2 & 0x7F) + 0x80 : b2); int i3 = ((b3 & 0x80) == 0x80 ? (b3 & 0x7F) + 0x80 : b3); return ((long) i0 << 24) + ((long) i1 << 16) + ((long) i2 << 8) + (long) i3; } / * Reads the NTP time stamp at the given offset in the buffer and returns * it as a system time (milliseconds since January 1, 1970). */ private long readTimeStamp(byte[] buffer, int offset) {
long seconds = read32(buffer, offset); long fraction = read32(buffer, offset + 4); return ((seconds - OFFSET_1900_TO_1970) * 1000) + ((fraction * 1000L) / 0xL); } / * Writes system time (milliseconds since January 1, 1970) as an NTP time stamp * at the given offset in the buffer. */ private void writeTimeStamp(byte[] buffer, int offset, long time) {
long seconds = time / 1000L; long milliseconds = time - seconds * 1000L; seconds += OFFSET_1900_TO_1970; // write seconds in big endian format buffer[offset++] = (byte) (seconds >> 24); buffer[offset++] = (byte) (seconds >> 16); buffer[offset++] = (byte) (seconds >> 8); buffer[offset++] = (byte) (seconds >> 0); long fraction = milliseconds * 0xL / 1000L; // write fraction in big endian format buffer[offset++] = (byte) (fraction >> 24); buffer[offset++] = (byte) (fraction >> 16); buffer[offset++] = (byte) (fraction >> 8); // low order bits should be random data buffer[offset++] = (byte) (Math.random() * 255.0); } }
步骤二:新建一个工具类TimeUtils ,获取当前校准过后的时间(已验证,可直接copy使用)
public class TimeUtils {
private String[] ntpServerPool = {
"ntp1.aliyun.com", "ntp.ntsc.ac.cn", "time.google.com", "time.windows.com", "time.nist.gov", "time.apple.com", "time1.cloud.tencent.com", "time2.apple.com", "time2.google.com", "3.asia.pool.ntp.org"}; //校准时间起始开机时间 private long startRealTime; private static TimeUtils instance; //校准后 开始时间 private long startTime; //是否校准 public boolean isCalibrated = false; public static TimeUtils getInstance() {
if (null == instance) {
instance = new TimeUtils(); } return instance; } / * 返回自启动以来的毫秒数,包括睡眠时间 * * @return */ public long getElapsedRealtime() {
return SystemClock.elapsedRealtime(); } / * 获取时间 * * @return */ public Date getDate() {
long elapsedRealtime = SystemClock.elapsedRealtime(); return startRealTime == 0 ? new Date(System.currentTimeMillis() - SystemClock.elapsedRealtime() + elapsedRealtime) : new Date(elapsedRealtime - this.startRealTime + startTime); } / * 使用ntp网络时间与本地时间进行校准 */ public void checkTime() {
//异步调用获取ntp协议网络时间 new Thread(new Runnable() {
@Override public void run() {
NTPClient ntpclient = new NTPClient(); for (String ntpHost : ntpServerPool) {
if (ntpclient.requestTime(ntpHost, 30000)) {
long currTime = ntpclient.getNtpTime() + SystemClock.elapsedRealtime() - ntpclient.getNtpTimeReference(); long nowTime = currTime / 1000; //当前获取到的准确ntp时间戳(秒单位) startRealTime = SystemClock.elapsedRealtime(); startTime = System.currentTimeMillis() + ntpclient.getTimeOffset(); isCalibrated = true; //为true代表当前已经拉到网络ntp break; } } } }).start(); } }
步骤三:接口调用实现(已验证,可直接copy使用)
//1、在你初始化或者在你需要初始化获取ntp网络时间的地方调用一次即可,以下举例子: public void init(Context context){
TimeUtils.getInstance().checkTime(); } //2、在你想要获取准确时间处调用以下代码,获取当前已校准的用户时间(实时) long cunrrent_time = TimeUtils.getInstance().getDate().getTime();//单位为毫秒,如需到秒需除以1000
完结:总之,经过自动化以及各种环境测试,无论用户怎么更改本地时间或者日期更改多往前往后此方案都可以解决。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/148718.html