#!/usr/bin/env bash # ============================================================================ # MAX Timezone & TimeSync — 时区管理与 NTP 时间同步 # 原创脚本,支持一键设置上海/UTC/自定义时区、NTP多源优化配置、时间同步校准 # # 风险等级: 🟡 修改配置 — 修改系统时区、NTP 服务与硬件时钟 # 用法: bash <(curl -fsSL https://dl.unvmax.com/linux/scripts/max-tools/max-timezone.sh) # ============================================================================ set -e R='\033[1;31m' G='\033[38;5;220m' Y='\033[1;33m' B='\033[38;5;220m' C='\033[38;5;220m' M='\033[38;5;242m' W='\033[38;5;250m' N='\033[0m' GR='\033[38;5;242m' BW='\033[38;5;255m' BG='\033[38;5;220m' echo -e "${B}┌─────────────────────────────────────────────┐${N}" echo -e "${B}│${N} ${G}MAX 时区管理与 NTP 时间同步${N} ${GR}(修改配置)${N}" echo -e "${B}└─────────────────────────────────────────────┘${N}" echo # ── 检测当前时间与时区状态 ── get_current_info() { CUR_TZ="" CUR_TIME="" CUR_UTC="" NTP_SYNC="未知" NTP_ACTIVE="未知" NTP_DAEMON="无" if command -v timedatectl &>/dev/null; then local td_out td_out=$(timedatectl 2>/dev/null || true) CUR_TZ=$(echo "$td_out" | grep -i "Time zone:" | sed -e 's/^[ \t]*Time zone:[ \t]*//' || echo "") CUR_TIME=$(echo "$td_out" | grep -i "Local time:" | sed -e 's/^[ \t]*Local time:[ \t]*//' || echo "") CUR_UTC=$(echo "$td_out" | grep -i "Universal time:" | sed -e 's/^[ \t]*Universal time:[ \t]*//' || echo "") NTP_SYNC=$(echo "$td_out" | grep -i "System clock synchronized:" | awk '{print $NF}' || echo "no") NTP_ACTIVE=$(echo "$td_out" | grep -i "NTP service:" | awk '{print $NF}' || echo "inactive") fi if [ -z "$CUR_TZ" ]; then if [ -f /etc/timezone ]; then CUR_TZ=$(cat /etc/timezone | tr -d ' \r\n') elif [ -h /etc/localtime ]; then CUR_TZ=$(readlink /etc/localtime | sed 's|.*/zoneinfo/||') else CUR_TZ=$(date +%Z 2>/dev/null || echo "未知") fi fi [ -z "$CUR_TIME" ] && CUR_TIME=$(date +"%Y-%m-%d %H:%M:%S %Z" 2>/dev/null || echo "未知") [ -z "$CUR_UTC" ] && CUR_UTC=$(date -u +"%Y-%m-%d %H:%M:%S UTC" 2>/dev/null || echo "未知") # 检测活跃守护进程 if systemctl is-active --quiet systemd-timesyncd 2>/dev/null; then NTP_DAEMON="systemd-timesyncd" elif systemctl is-active --quiet chronyd 2>/dev/null || systemctl is-active --quiet chrony 2>/dev/null; then NTP_DAEMON="chrony" elif systemctl is-active --quiet ntpd 2>/dev/null || systemctl is-active --quiet ntp 2>/dev/null; then NTP_DAEMON="ntpd" fi } show_status_box() { get_current_info echo -e " ${C}当前时区:${N} ${BW}$CUR_TZ${N}" echo -e " ${C}本地时间:${N} ${W}$CUR_TIME${N}" echo -e " ${C}UTC 时间:${N} ${GR}$CUR_UTC${N}" local sync_color=$G [ "$NTP_SYNC" != "yes" ] && sync_color=$Y echo -e " ${C}NTP 状态:${N} ${sync_color}已同步: $NTP_SYNC${N} ${GR}(服务: $NTP_ACTIVE / 守护: $NTP_DAEMON)${N}" echo } # ── 核心操作函数 ── ensure_ntp_service() { echo -e " ${GR}检查并激活时间同步服务...${N}" if command -v timedatectl &>/dev/null; then timedatectl set-ntp true 2>/dev/null || true fi # 如果没有可用的 NTP 守护进程,尝试安装并启动 systemd-timesyncd 或 chrony if ! systemctl is-active --quiet systemd-timesyncd 2>/dev/null && \ ! systemctl is-active --quiet chronyd 2>/dev/null && \ ! systemctl is-active --quiet chrony 2>/dev/null && \ ! systemctl is-active --quiet ntp 2>/dev/null; then if command -v apt-get &>/dev/null; then echo -e " ${Y}安装 systemd-timesyncd...${N}" apt-get update -qq 2>/dev/null || true apt-get install -y -qq systemd-timesyncd 2>/dev/null || apt-get install -y -qq chrony 2>/dev/null || true elif command -v yum &>/dev/null; then echo -e " ${Y}安装 chrony...${N}" yum install -y chrony 2>/dev/null || true elif command -v dnf &>/dev/null; then dnf install -y chrony 2>/dev/null || true fi fi if systemctl list-unit-files systemd-timesyncd.service &>/dev/null; then systemctl enable --now systemd-timesyncd 2>/dev/null || true elif systemctl list-unit-files chronyd.service &>/dev/null; then systemctl enable --now chronyd 2>/dev/null || true elif systemctl list-unit-files chrony.service &>/dev/null; then systemctl enable --now chrony 2>/dev/null || true fi } apply_timezone() { local target_tz="$1" local tz_desc="$2" if [ ! -f "/usr/share/zoneinfo/$target_tz" ]; then echo -e " ${R}✘ 时区文件不存在: /usr/share/zoneinfo/$target_tz${N}" return 1 fi echo -e " ${Y}正在设置时区为: ${BW}$target_tz${Y} (${tz_desc})...${N}" if command -v timedatectl &>/dev/null; then timedatectl set-timezone "$target_tz" 2>/dev/null || { ln -sf "/usr/share/zoneinfo/$target_tz" /etc/localtime echo "$target_tz" > /etc/timezone 2>/dev/null || true } else ln -sf "/usr/share/zoneinfo/$target_tz" /etc/localtime echo "$target_tz" > /etc/timezone 2>/dev/null || true fi echo -e " ${G}✔ 时区设置成功: $target_tz${N}" } trigger_sync() { echo -e " ${Y}正在执行 NTP 时间强制同步...${N}" ensure_ntp_service # 如果是 timesyncd,重启服务触发即时校准 if systemctl is-active --quiet systemd-timesyncd 2>/dev/null; then systemctl restart systemd-timesyncd 2>/dev/null || true fi # 如果是 chrony,触发立即步进同步 if command -v chronyc &>/dev/null; then chronyc makestep 2>/dev/null || chronyc -a 'burst 4/4' 2>/dev/null || true fi # 如果有时钟同步命令 if command -v ntpdate &>/dev/null; then ntpdate -u ntp.aliyun.com 2>/dev/null || true fi # 同步至硬件 RTC 时钟 if command -v hwclock &>/dev/null; then hwclock --systohc 2>/dev/null || true fi sleep 1 echo -e " ${G}✔ 时间同步命令已执行完毕${N}" } optimize_ntp_conf() { echo -e " ${Y}正在配置高可用 NTP 上游服务器...${N}" # 优质 NTP 池:阿里云、腾讯云、国家授时中心、Cloudflare、Google、公共池 local ntp_servers="ntp.aliyun.com ntp.tencent.com ntp.ntsc.ac.cn cn.pool.ntp.org time.cloudflare.com" local fallback_servers="time.google.com time.apple.com pool.ntp.org" # 1. 尝试配置 systemd-timesyncd if [ -d /etc/systemd ]; then mkdir -p /etc/systemd/timesyncd.conf.d 2>/dev/null || true cat < /etc/systemd/timesyncd.conf.d/max-timesync.conf [Time] NTP=$ntp_servers FallbackNTP=$fallback_servers RootDistanceMaxSec=5 PollIntervalMinSec=32 PollIntervalMaxSec=2048 EOF echo -e " ${G}✔ 已写入 /etc/systemd/timesyncd.conf.d/max-timesync.conf${N}" fi # 2. 如果存在 chrony,同步配置 if [ -f /etc/chrony/chrony.conf ] || [ -f /etc/chrony.conf ]; then local cconf="/etc/chrony/chrony.conf" [ ! -f "$cconf" ] && cconf="/etc/chrony.conf" if ! grep -q "ntp.aliyun.com" "$cconf" 2>/dev/null; then cat <> "$cconf" # MAX NTP Servers server ntp.aliyun.com iburst minpoll 4 maxpoll 10 server ntp.tencent.com iburst minpoll 4 maxpoll 10 server ntp.ntsc.ac.cn iburst minpoll 4 maxpoll 10 server time.cloudflare.com iburst minpoll 4 maxpoll 10 EOF echo -e " ${G}✔ 已追加优质 NTP 源至 $cconf${N}" fi fi trigger_sync } show_detailed_diag() { echo -e "\n ${M}── timedatectl 详细状态 ──${N}" if command -v timedatectl &>/dev/null; then timedatectl status 2>/dev/null || true echo if timedatectl timesync-status &>/dev/null; then echo -e " ${M}── NTP 同步链路追踪 ──${N}" timedatectl timesync-status 2>/dev/null || true fi else date -R 2>/dev/null || true fi if command -v chronyc &>/dev/null; then echo -e "\n ${M}── Chrony 源与偏差 ──${N}" chronyc sources -v 2>/dev/null || true fi } # ── 交互菜单 ── show_status_box echo -e " ${M}请选择操作:${N}" echo -e " ${C}1${N}) ${G}设为中国上海时区 (Asia/Shanghai, CST+8) + 立即校准时间${N} ${GR}(推荐)${N}" echo -e " ${C}2${N}) ${G}仅立即同步网络时间 (NTP 校准)${N} ${GR}(保持当前时区)${N}" echo -e " ${C}3${N}) ${W}设为标准 UTC 时区 (Etc/UTC, +0000) + 立即校准时间${N}" echo -e " ${C}4${N}) ${W}选择其他常用时区 / 自定义时区${N}" echo -e " ${C}5${N}) ${W}优化配置高可用 NTP 上游源${N} ${GR}(阿里/腾讯/国家授时/Cloudflare)${N}" echo -e " ${C}6${N}) ${W}查看详细时钟与 NTP 诊断信息${N} ${GR}(只读)${N}" echo -e " ${C}0${N}) 返回主菜单 ${GR}(q 同样可用)${N}" echo read -r -p "$(echo -e " ${C}选择 (1-6/0): ${N}")" choice || choice=0 case "$choice" in 1) echo apply_timezone "Asia/Shanghai" "中国标准时间 CST+8" optimize_ntp_conf ;; 2) echo trigger_sync ;; 3) echo apply_timezone "Etc/UTC" "世界协调时间 UTC+0" trigger_sync ;; 4) echo echo -e " ${M}常用时区列表:${N}" echo -e " ${C}1${N}) 香港 Asia/Hong_Kong (UTC+8)" echo -e " ${C}2${N}) 东京 Asia/Tokyo (UTC+9)" echo -e " ${C}3${N}) 新加坡 Asia/Singapore (UTC+8)" echo -e " ${C}4${N}) 伦敦 Europe/London (UTC+0/+1)" echo -e " ${C}5${N}) 美西 America/Los_Angeles (UTC-8/-7)" echo -e " ${C}6${N}) 美东 America/New_York (UTC-5/-4)" echo -e " ${C}7${N}) 手动输入时区名称 (如 Europe/Berlin)" echo -e " ${C}0${N}) 取消返回" echo read -r -p "$(echo -e " ${C}选择 (1-7/0): ${N}")" sub_choice case "$sub_choice" in 1) apply_timezone "Asia/Hong_Kong" "香港时间"; trigger_sync ;; 2) apply_timezone "Asia/Tokyo" "东京时间"; trigger_sync ;; 3) apply_timezone "Asia/Singapore" "新加坡时间"; trigger_sync ;; 4) apply_timezone "Europe/London" "伦敦时间"; trigger_sync ;; 5) apply_timezone "America/Los_Angeles" "美西时间"; trigger_sync ;; 6) apply_timezone "America/New_York" "美东时间"; trigger_sync ;; 7) read -r -p "$(echo -e " ${C}请输入时区全称 (如 Asia/Shanghai 或 Europe/Berlin): ${N}")" custom_tz custom_tz=$(echo "$custom_tz" | tr -d ' ') if [ -n "$custom_tz" ]; then apply_timezone "$custom_tz" "自定义" && trigger_sync else echo -e " ${R}时区名称不能为空${N}" fi ;; 0|q|Q) echo -e " ${GR}已取消${N}" ;; *) echo -e " ${R}无效选择${N}" ;; esac ;; 5) echo optimize_ntp_conf ;; 6) show_detailed_diag ;; 0|q|Q) echo -e " ${GR}返回主菜单${N}" exit 0 ;; *) echo -e " ${R}无效选择${N}" exit 1 ;; esac echo echo -e " ${M}最新状态验证:${N}" get_current_info echo -e " ${G}✔${N} ${C}时区:${N} ${BW}$CUR_TZ${N}" echo -e " ${G}✔${N} ${C}时间:${N} ${W}$CUR_TIME${N}" echo -e " ${G}✔${N} ${C}NTP:${N} ${W}$NTP_SYNC (服务: $NTP_ACTIVE / $NTP_DAEMON)${N}" echo echo -e "${GR}👉 更多工具: max-sysinfo.sh | 服务巡检: max-service-check.sh${N}" echo -e "${GR}👉 一键执行: bash <(curl -fsSL https://dl.unvmax.com/linux/scripts/max-tools/max-timezone.sh)${N}"