package tech.powerjob.server.common.utils; import tech.powerjob.common.RemoteConstant; import com.google.common.collect.Lists; import lombok.extern.slf4j.Slf4j; import org.apache.commons.net.ntp.NTPUDPClient; import org.apache.commons.net.ntp.NtpV3Packet; import org.apache.commons.net.ntp.TimeInfo; import java.net.InetAddress; import java.util.List; /** * 时间工具 * * @author tjq * @since 2020/5/19 */ @Slf4j public class TimeUtils { /** * NTP 授时服务器(阿里云 -> 交大 -> 水果) */ private static final List NTP_SERVER_LIST = Lists.newArrayList("ntp.aliyun.com", "ntp.sjtu.edu.cn", "time1.apple.com"); /** * 最大误差 5S */ private static final long MAX_OFFSET = 5000; /** * 根据蔡勒公式计算任意一个日期是星期几 * @param year 年 * @param month 月 * @param day 日 * @return 中国星期 */ public static int calculateWeek(int year, int month, int day) { if (month == 1) { month = 13; year--; } if (month == 2) { month = 14; year--; } int y = year % 100; int c = year /100 ; int h = (y + (y / 4) + (c / 4) - (2 * c) + ((26 * (month + 1)) / 10) + day - 1) % 7; //可能是负值,因此计算除以7的余数之后需要判断是大于等于0还是小于0,如果小于0则将余数加7。 if (h < 0){ h += 7; } // 国内理解中星期日为 7 if (h == 0) { return 7; } return h; } public static void check() throws TimeCheckException { NTPUDPClient timeClient = new NTPUDPClient(); try { timeClient.setDefaultTimeout((int) RemoteConstant.DEFAULT_TIMEOUT_MS); for (String address : NTP_SERVER_LIST) { try { TimeInfo t = timeClient.getTime(InetAddress.getByName(address)); NtpV3Packet ntpV3Packet = t.getMessage(); log.info("[TimeUtils] use ntp server: {}, request result: {}", address, ntpV3Packet); // RFC-1305标准:https://tools.ietf.org/html/rfc1305 // 忽略传输误差吧...也就几十毫秒的事(阿里云给力啊!) long local = System.currentTimeMillis(); long ntp = ntpV3Packet.getTransmitTimeStamp().getTime(); long offset = local - ntp; if (Math.abs(offset) > MAX_OFFSET) { String msg = String.format("inaccurate server time(local:%d, ntp:%d), please use ntp update to calibration time", local, ntp); throw new TimeCheckException(msg); } return; }catch (Exception ignore) { log.warn("[TimeUtils] ntp server: {} may down!", address); } } throw new TimeCheckException("no available ntp server, maybe alibaba, sjtu and apple are both collapse"); }finally { timeClient.close(); } } public static final class TimeCheckException extends RuntimeException { public TimeCheckException(String message) { super(message); } } }