可以用于计算vps剩余时间:


<!doctype html>

<html lang="zh-CN">

<head>

  <meta charset="utf-8" />

  <meta name="viewport" content="width=device-width, initial-scale=1" />

  <title>时刻间隔(天/小时)计算器</title>

  <style>

    :root{

      --accent:#2563eb;

      --bg:#f5f7fb;

      --card:#ffffff;

      --border:#dbe3f0;

      --text:#0f172a;

      --muted:#64748b;

      --good:#16a34a;

      --warn:#ef4444;

      --mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;

    }

    /* 兼容你全站的 data-theme="dark" */

    html[data-theme="dark"]{

      --bg:#0b1220;

      --card:#0f1a2f;

      --border:#22314f;

      --text:#e5e7eb;

      --muted:#9ca3af;

      --accent:#60a5fa;

    }

    @media (prefers-color-scheme: dark){

      html:not([data-theme="light"]){

        --bg:#0b1220;

        --card:#0f1a2f;

        --border:#22314f;

        --text:#e5e7eb;

        --muted:#9ca3af;

        --accent:#60a5fa;

      }

    }

    body{

      margin:0;

      padding:16px;

      background:var(--bg);

      color:var(--text);

      font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;

    }

    .wrap{

      width:520px;

      max-width:100%;

      margin:0 auto;

    }

    .card{

      background:var(--card);

      border:1px solid var(--border);

      border-radius:14px;

      box-shadow:0 10px 26px rgba(0,0,0,.06);

      padding:14px;

    }

    h2{

      margin:0 0 10px;

      text-align:center;

      font-size:20px;

      color:var(--accent);

      letter-spacing:.2px;

    }

    .row{

      display:flex;

      gap:10px;

      align-items:center;

      flex-wrap:wrap;

      margin:10px 0;

    }

    .label{

      width:86px;

      font-size:13px;

      color:var(--muted);

      flex:0 0 auto;

    }

    .input{

      flex:1 1 220px;

      display:flex;

      gap:8px;

      align-items:center;

      flex-wrap:wrap;

    }

    input[type="datetime-local"]{

      flex:1 1 210px;

      min-width:190px;

      padding:10px 10px;

      border-radius:10px;

      border:1px solid var(--border);

      background:transparent;

      color:var(--text);

      outline:none;

    }

    input[type="datetime-local"]:disabled{

      opacity:.75;

      cursor:not-allowed;

    }

    .btn{

      border:1px solid var(--border);

      background:var(--accent);

      color:#fff;

      padding:9px 10px;

      border-radius:10px;

      cursor:pointer;

      font-size:13px;

      white-space:nowrap;

    }

    .btn.secondary{

      background:transparent;

      color:var(--text);

    }

    .btn:active{ transform:translateY(1px); }

    .chk{

      display:flex;

      align-items:center;

      gap:6px;

      font-size:13px;

      color:var(--muted);

      user-select:none;

    }

    .hr{

      height:1px;

      background:var(--border);

      margin:12px 0;

    }

    .result{

      padding:12px;

      border:1px dashed var(--border);

      border-radius:12px;

      background:rgba(37,99,235,.06);

    }

    html[data-theme="dark"] .result{

      background:rgba(96,165,250,.10);

    }

    .big{

      font-size:18px;

      font-weight:700;

      margin:0 0 6px;

    }

    .small{

      margin:0;

      font-size:13px;

      color:var(--muted);

      line-height:1.55;

    }

    .mono{ font-family:var(--mono); }

    .pill{

      display:inline-block;

      padding:2px 8px;

      border-radius:999px;

      border:1px solid var(--border);

      font-size:12px;

      margin-left:8px;

      vertical-align:1px;

    }

    .pill.good{ color:var(--good); }

    .pill.warn{ color:var(--warn); }

    .footer{

      margin-top:10px;

      font-size:12px;

      color:var(--muted);

      text-align:center;

    }

  </style>

</head>

<body>

  <div class="wrap">

    <div class="card">

      <h2>时刻间隔(天 / 小时)计算器</h2>

      <div class="row">

        <div class="label">起点时刻</div>

        <div class="input">

          <input id="start" type="datetime-local" />

          <button class="btn" id="startNow">设为当前</button>

          <label class="chk">

            <input id="startFollow" type="checkbox" />

            跟随当前

          </label>

        </div>

      </div>

      <div class="row">

        <div class="label">终点时刻</div>

        <div class="input">

          <input id="end" type="datetime-local" />

          <button class="btn" id="endNow">设为当前</button>

          <label class="chk">

            <input id="endFollow" type="checkbox" />

            跟随当前

          </label>

        </div>

      </div>

      <div class="row">

        <div class="label">操作</div>

        <div class="input">

          <button class="btn secondary" id="swap">交换起点/终点</button>

          <button class="btn secondary" id="copy">复制结果</button>

        </div>

      </div>

      <div class="hr"></div>

      <div class="result" id="resultBox">

        <p class="big" id="mainLine">请先选择两个时刻</p>

        <p class="small" id="subLine"></p>

        <p class="small mono" id="detailLine"></p>

      </div>

      <div class="footer">说明:按“终点 - 起点”计算;为正表示“剩余”,为负表示“已过”。</div>

    </div>

  </div>

<script>

(function(){

  const $ = (id) => document.getElementById(id);

  const startEl = $("start");

  const endEl = $("end");

  const startNowBtn = $("startNow");

  const endNowBtn = $("endNow");

  const startFollow = $("startFollow");

  const endFollow = $("endFollow");

  const swapBtn = $("swap");

  const copyBtn = $("copy");

  const mainLine = $("mainLine");

  const subLine = $("subLine");

  const detailLine = $("detailLine");

  let timer = null;

  function pad(n){ return String(n).padStart(2, "0"); }

  // 生成 datetime-local 需要的格式:YYYY-MM-DDTHH:mm

  function toLocalInputValue(d){

    const y = d.getFullYear();

    const m = pad(d.getMonth()+1);

    const da = pad(d.getDate());

    const h = pad(d.getHours());

    const mi = pad(d.getMinutes());

    return `${y}-${m}-${da}T${h}:${mi}`;

  }

  function parseLocalInputValue(v){

    // datetime-local 不带时区,这里按本地时间解析

    if(!v) return null;

    const dt = new Date(v);

    if(Number.isNaN(dt.getTime())) return null;

    return dt;

  }

  function setStartNow(){

    startEl.value = toLocalInputValue(new Date());

  }

  function setEndNow(){

    endEl.value = toLocalInputValue(new Date());

  }

  function updateFollowStates(){

    startEl.disabled = startFollow.checked;

    startNowBtn.disabled = startFollow.checked;

    endEl.disabled = endFollow.checked;

    endNowBtn.disabled = endFollow.checked;

  }

  function ensureTimer(){

    const need = startFollow.checked || endFollow.checked;

    if(need && !timer){

      timer = setInterval(()=>{

        const now = new Date();

        if(startFollow.checked) startEl.value = toLocalInputValue(now);

        if(endFollow.checked) endEl.value = toLocalInputValue(now);

        calc();

      }, 1000);

    }else if(!need && timer){

      clearInterval(timer);

      timer = null;

    }

  }

  function humanDiff(ms){

    const sign = ms >= 0 ? 1 : -1;

    const abs = Math.abs(ms);

    const dayMs = 24 * 60 * 60 * 1000;

    const hourMs = 60 * 60 * 1000;

    const days = Math.floor(abs / dayMs);

    const hours = Math.floor((abs % dayMs) / hourMs);

    // 额外给一个总小时(带两位小数),方便你需要“小时数”时直接用

    const totalHours = abs / hourMs;

    return { sign, days, hours, totalHours };

  }

  function calc(){

    const s = parseLocalInputValue(startEl.value);

    const e = parseLocalInputValue(endEl.value);

    if(!s || !e){

      mainLine.textContent = "请先选择两个时刻";

      subLine.textContent = "";

      detailLine.textContent = "";

      return;

    }

    const diff = e.getTime() - s.getTime();

    const { sign, days, hours, totalHours } = humanDiff(diff);

    const status = sign >= 0 ? "剩余" : "已过";

    const pillClass = sign >= 0 ? "good" : "warn";

    mainLine.innerHTML =

      `${status}:<span class="mono">${days}</span> 天 <span class="mono">${hours}</span> 小时` +

      ` <span class="pill ${pillClass}">${diff === 0 ? "同一时刻" : (sign >= 0 ? "倒计时" : "已超时")}</span>`;

    subLine.textContent = `起点:${s.toLocaleString()} | 终点:${e.toLocaleString()}`;

    detailLine.textContent = `总小时(绝对值):${totalHours.toFixed(2)} h  |  原始差值:${diff} ms`;

  }

  // 事件

  startEl.addEventListener("input", calc);

  endEl.addEventListener("input", calc);

  startNowBtn.addEventListener("click", ()=>{ setStartNow(); calc(); });

  endNowBtn.addEventListener("click", ()=>{ setEndNow(); calc(); });

  startFollow.addEventListener("change", ()=>{

    updateFollowStates();

    ensureTimer();

    if(startFollow.checked) setStartNow();

    calc();

  });

  endFollow.addEventListener("change", ()=>{

    updateFollowStates();

    ensureTimer();

    if(endFollow.checked) setEndNow();

    calc();

  });

  swapBtn.addEventListener("click", ()=>{

    const sv = startEl.value;

    startEl.value = endEl.value;

    endEl.value = sv;

    // 交换时不动“跟随当前”的勾选状态(更符合直觉:只是交换数值)

    calc();

  });

  copyBtn.addEventListener("click", async ()=>{

    const text = [

      mainLine.textContent || "",

      subLine.textContent || "",

      detailLine.textContent || ""

    ].filter(Boolean).join("\n");

    try{

      await navigator.clipboard.writeText(text);

      copyBtn.textContent = "已复制";

      setTimeout(()=>copyBtn.textContent="复制结果", 800);

    }catch(e){

      // 兼容极少数环境

      const ta = document.createElement("textarea");

      ta.value = text;

      document.body.appendChild(ta);

      ta.select();

      try{ document.execCommand("copy"); }catch(_){}

      document.body.removeChild(ta);

      copyBtn.textContent = "已复制";

      setTimeout(()=>copyBtn.textContent="复制结果", 800);

    }

  });

  // 默认初始化:两端都给当前时刻(你也可以改成 end=now+1h)

  setStartNow();

  setEndNow();

  updateFollowStates();

  ensureTimer();

  calc();

})();

</script>

</body>

</html>