时区转换工具+PWA离线网页

一、时区转换工具对比

工具 说明
Date 原生 JS API,有限的时区支持,无法指定时区,仅使用本地时区。
Intl.DateTimeFormat 原生格式化显示,可指定时区,但不能修改时区逻辑。
luxon 强烈推荐,现代、轻量、功能强,原生支持时区、时间戳、格式化等。
dayjs + timezone 插件 类似 moment,更现代,但时区支持需插件。
moment-timezone 功能全面但体积大,moment 官方已不推荐用于新项目。

二、Luxon 使用示例

1. 美国时间 -> 中国时间

import { DateTime } from 'luxon'

const usTime = DateTime.fromISO('2025-04-01T11:11:00', { zone: 'America/Los_Angeles' })

const timestamp = usTime.toMillis()

const cnTime = usTime.setZone('Asia/Shanghai')

console.log('美国时间:', usTime.toFormat('yyyy-MM-dd HH:mm:ss ZZZZ'))
console.log('时间戳:', timestamp)
console.log('对应的中国时间:', cnTime.toFormat('yyyy-MM-dd HH:mm:ss ZZZZ'))
美国时间:2025-04-01 11:11:00 GMT-7
时间戳:1743521460000
对应的中国时间:2025-04-02 02:11:00 GMT+8

2. 中国时间 -> 美国时间

const cn = DateTime.fromISO('2025-04-01T11:11:00', { zone: 'Asia/Shanghai' })

const us = cn.setZone('America/Los_Angeles')

console.log('中国时间:', cn.toFormat('yyyy-MM-dd HH:mm:ss ZZZZ'))
console.log('对应的美国时间:', us.toFormat('yyyy-MM-dd HH:mm:ss ZZZZ'))
console.log('时间戳(UTC):', cn.toMillis())

3. 转换逻辑总结

场景 方法
指定时区的时间 → 时间戳 DateTime.fromISO(...).toMillis()
时间戳 → 指定时区时间 DateTime.fromMillis(...).setZone(...)
不同时区之间转换 .setZone(...)
时间格式化 .toFormat('yyyy-MM-dd HH:mm:ss') 等

4. 常用时区 ID 表

名称 IANA 时区 ID
北京/上海(Asia/Shanghai) Asia/Shanghai
香港(Asia/Hong_Kong) Asia/Hong_Kong
日本(Asia/Tokyo) Asia/Tokyo
韩国(Asia/Seoul) Asia/Seoul
新加坡(Asia/Singapore) Asia/Singapore
印度(Asia/Kolkata) Asia/Kolkata
美国西部 - 洛杉矶(America/Los_Angeles) America/Los_Angeles
美国中部 - 芝加哥(America/Chicago) America/Chicago
美国东部 - 纽约(America/New_York) America/New_York
英国(Europe/London) Europe/London
德国(Europe/Berlin) Europe/Berlin
法国(Europe/Paris) Europe/Paris
澳大利亚 - 悉尼(Australia/Sydney) Australia/Sydney
新西兰(Pacific/Auckland) Pacific/Auckland
夏威夷(Pacific/Honolulu) Pacific/Honolulu
UTC(协调世界时) UTC

三、时区转换脚本

1. NodeJS 脚本(使用 luxon)

const { DateTime } = require('luxon')

function convertTime({
timeStr = '2025-04-01 11:11:00',
fromZone = 'America/Los_Angeles',
toZone = 'Asia/Shanghai'
}) {
const fromTime = DateTime.fromFormat(timeStr, 'yyyy-MM-dd HH:mm:ss', { zone: fromZone }) const toTime = fromTime.setZone(toZone) console.log(`原始时间 (${fromZone}):`, fromTime.toFormat('yyyy-MM-dd HH:mm:ss ZZZZ'))
console.log(`时间戳(UTC 毫秒):`, fromTime.toMillis())
console.log(`转换后 (${toZone}):`, toTime.toFormat('yyyy-MM-dd HH:mm:ss ZZZZ'))
} // 修改这里的参数即可
convertTime({
timeStr: '2025-04-01 11:11:00',
fromZone: 'America/Los_Angeles',
toZone: 'Asia/Shanghai'
})

2. Python 脚本(使用 pytz)

pip install pytz
from datetime import datetime
import pytz def convert_time(time_str='2025-04-01 11:11:00', from_zone='America/Los_Angeles', to_zone='Asia/Shanghai'):
from_tz = pytz.timezone(from_zone)
to_tz = pytz.timezone(to_zone) naive_dt = datetime.strptime(time_str, '%Y-%m-%d %H:%M:%S')
from_dt = from_tz.localize(naive_dt) to_dt = from_dt.astimezone(to_tz) print(f'原始时间 ({from_zone}): {from_dt.strftime("%Y-%m-%d %H:%M:%S %Z%z")}')
print(f'时间戳(UTC 秒): {int(from_dt.timestamp())}')
print(f'转换后 ({to_zone}): {to_dt.strftime("%Y-%m-%d %H:%M:%S %Z%z")}') # 修改参数即可
convert_time(
time_str='2025-04-01 11:11:00',
from_zone='America/Los_Angeles',
to_zone='Asia/Shanghai'
)

四、网页小工具

使用 Luxon + HTML 原生控件制作的小工具,支持:

  • 输入时间
  • 原始/目标时区选择
  • 时间戳显示
  • 一键复制

1. 代码展示

<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<title> 时区时间转换工具</title>
<script src="https://cdn.jsdelivr.net/npm/luxon@3/build/global/luxon.min.js"></script>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
padding: 2rem;
max-width: 700px;
margin: auto;
background: #f8f9fa;
}
h2 {
text-align: center;
margin-bottom: 2rem;
}
label {
font-weight: bold;
margin-top: 1rem;
display: block;
}
input, select, button {
width: 100%;
padding: 0.6rem;
margin: 0.4rem 0 1rem;
border: 1px solid #ccc;
border-radius: 5px;
font-size: 1rem;
}
button {
background: #007bff;
color: white;
cursor: pointer;
border: none;
transition: background 0.3s;
}
button:hover {
background: #0056b3;
}
.result {
background: #fff;
border-left: 5px solid #007bff;
padding: 1rem;
margin-top: 1rem;
border-radius: 5px;
white-space: pre-wrap;
font-size: 0.95rem;
}
.error {
color: red;
margin-top: 1rem;
}
.copy-btn {
margin-top: 0.5rem;
background: #28a745;
}
.copy-btn:hover {
background: #1e7e34;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 2rem;
background: #fff;
}
th, td {
border: 1px solid #ddd;
padding: 0.6rem;
text-align: left;
}
th {
background-color: #007bff;
color: white;
}
</style>
</head>
<body>
<h2> 时区转换小工具</h2> <label for="inputDate">选择时间</label>
<input type="datetime-local" id="inputDate" /> <label for="fromZone">原始时区</label>
<select id="fromZone"></select> <label for="toZone">目标时区</label>
<select id="toZone"></select> <button onclick="convertTime()">转换时间</button> <div class="result" id="output"> 转换结果将在这里显示</div>
<button class="copy-btn" onclick="copyResult()"> 复制结果</button>
<div class="error" id="error"></div> <script>
const { DateTime } = luxon const timezones = [
{ label: '北京(Asia/Shanghai)', value: 'Asia/Shanghai' },
{ label: '香港(Asia/Hong_Kong)', value: 'Asia/Hong_Kong' },
{ label: '日本(Asia/Tokyo)', value: 'Asia/Tokyo' },
{ label: '韩国(Asia/Seoul)', value: 'Asia/Seoul' },
{ label: '新加坡(Asia/Singapore)', value: 'Asia/Singapore' },
{ label: '印度(Asia/Kolkata)', value: 'Asia/Kolkata' },
{ label: '美国西部 - 洛杉矶(America/Los_Angeles)', value: 'America/Los_Angeles' },
{ label: '美国中部 - 芝加哥(America/Chicago)', value: 'America/Chicago' },
{ label: '美国东部 - 纽约(America/New_York)', value: 'America/New_York' },
{ label: '英国(Europe/London)', value: 'Europe/London' },
{ label: '德国(Europe/Berlin)', value: 'Europe/Berlin' },
{ label: '法国(Europe/Paris)', value: 'Europe/Paris' },
{ label: '澳大利亚 - 悉尼(Australia/Sydney)', value: 'Australia/Sydney' },
{ label: '新西兰(Pacific/Auckland)', value: 'Pacific/Auckland' },
{ label: '夏威夷(Pacific/Honolulu)', value: 'Pacific/Honolulu' },
{ label: 'UTC(协调世界时)', value: 'UTC' },
] function renderTimezoneOptions() {
const fromSelect = document.getElementById('fromZone')
const toSelect = document.getElementById('toZone')
const tableBody = document.getElementById('timezoneTable') timezones.forEach(({ label, value }) => {
const opt1 = new Option(label, value)
const opt2 = new Option(label, value)
fromSelect.appendChild(opt1)
toSelect.appendChild(opt2)
}) fromSelect.value = 'Asia/Shanghai'
toSelect.value = 'America/Los_Angeles'
} document.addEventListener('DOMContentLoaded', () => {
renderTimezoneOptions()
const now = new Date()
const local = now.toISOString().slice(0, 16)
document.getElementById('inputDate').value = local
}) function convertTime() {
const input = document.getElementById('inputDate').value
const fromZone = document.getElementById('fromZone').value
const toZone = document.getElementById('toZone').value
const output = document.getElementById('output')
const error = document.getElementById('error') error.textContent = '' if (!input) {
error.textContent = ' 请选择一个时间'
return
} try {
const dt = DateTime.fromISO(input, { zone: fromZone })
const toTime = dt.setZone(toZone) const result = `
原始时间(${fromZone}):
${dt.toFormat('yyyy-MM-dd HH:mm:ss ZZZZ')} 时间戳(UTC 毫秒):
${dt.toMillis()} ️ 转换后时间(${toZone}):
${toTime.toFormat('yyyy-MM-dd HH:mm:ss ZZZZ')}
`.trim() output.textContent = result
}
catch (e) {
error.textContent = ' 转换失败,请检查输入'
}
} function copyResult() {
const result = document.getElementById('output').textContent
if (!result || result.includes('将在这里显示'))
return
navigator.clipboard.writeText(result).then(() => {
alert(' 已复制到剪贴板!')
})
}
</script>
</body>
</html>

2. 示例截图

五、PWA 应用支持

1. PWA 结构

.
├── icons
│ ├── time_192.png
│ └── time_512.png
├── index.html
├── luxon.min.js
├── manifest.json
└── service-worker.js

2. manifest.json

用于定义名称、图标、启动方式等:

{
"name": "时区时间转换工具",
"short_name": "时区转换",
"start_url": "./index.html",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#007bff",
"description": "支持多时区时间互转、时间戳生成的轻量工具",
"icons": [
{
"src": "icons/time_192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icons/time_512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}

3. service-worker.js

实现核心缓存功能,支持离线访问:

const CACHE_NAME = 'timezone-converter-0.0.1'
const urlsToCache = [
'./',
'./index.html',
'./manifest.json',
'./service-worker.js',
'./icons/time_192.png',
'./icons/time_512.png',
'./luxon.min.js'
] // 安装时预缓存核心资源
self.addEventListener('install', event => {
self.skipWaiting()
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => cache.addAll(urlsToCache))
)
}) // 激活时清除旧缓存
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(keys =>
Promise.all(keys.filter(k => k !== CACHE_NAME).map(k => caches.delete(k)))
)
)
self.clients.claim()
}) // 拦截所有请求,优先从缓存读取,失败则网络请求
self.addEventListener('fetch', event => {
const request = event.request event.respondWith(
caches.match(request).then(cachedResponse => {
if (cachedResponse) return cachedResponse return fetch(request)
.then(networkResponse => {
if (
networkResponse &&
networkResponse.status === 200 &&
request.url.startsWith(self.location.origin)
) {
const cloned = networkResponse.clone()
caches.open(CACHE_NAME).then(cache => {
cache.put(request, cloned)
})
}
return networkResponse
})
.catch(() => {
if (request.headers.get('accept')?.includes('text/html')) {
return caches.match('./index.html')
}
})
})
)
})

4. html 文件

整合 Luxon + PWA 注册逻辑

<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<title> 时区时间转换工具1</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#007bff" /> <link rel="manifest" href="manifest.json" />
<link rel="icon" href="icons/time_192.png" />
<link rel="apple-touch-icon" href="icons/time_512.png" /> <script src="./luxon.min.js"></script> <style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
padding: 2rem;
max-width: 700px;
margin: auto;
background: #f8f9fa;
}
h2 {
text-align: center;
margin-bottom: 2rem;
}
label {
font-weight: bold;
margin-top: 1rem;
display: block;
}
input, select, button {
width: 100%;
padding: 0.6rem;
margin: 0.4rem 0 1rem;
border: 1px solid #ccc;
border-radius: 5px;
font-size: 1rem;
}
button {
background: #007bff;
color: white;
cursor: pointer;
border: none;
transition: background 0.3s;
}
button:hover {
background: #0056b3;
}
.result {
background: #fff;
border-left: 5px solid #007bff;
padding: 1rem;
margin-top: 1rem;
border-radius: 5px;
white-space: pre-wrap;
font-size: 0.95rem;
}
.error {
color: red;
margin-top: 1rem;
}
.copy-btn {
margin-top: 0.5rem;
background: #28a745;
}
.copy-btn:hover {
background: #1e7e34;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 2rem;
background: #fff;
}
th, td {
border: 1px solid #ddd;
padding: 0.6rem;
text-align: left;
}
th {
background-color: #007bff;
color: white;
}
</style>
</head>
<body>
<h2> 时区转换小工具</h2> <label for="inputDate">选择时间</label>
<input type="datetime-local" id="inputDate" /> <label for="fromZone">原始时区</label>
<select id="fromZone"></select> <label for="toZone">目标时区</label>
<select id="toZone"></select> <button onclick="convertTime()">转换时间</button> <div class="result" id="output"> 转换结果将在这里显示</div>
<button class="copy-btn" onclick="copyResult()"> 复制结果</button>
<div class="error" id="error"></div> <script>
const { DateTime } = luxon const timezones = [
{ label: '北京(Asia/Shanghai)', value: 'Asia/Shanghai' },
{ label: '香港(Asia/Hong_Kong)', value: 'Asia/Hong_Kong' },
{ label: '日本(Asia/Tokyo)', value: 'Asia/Tokyo' },
{ label: '韩国(Asia/Seoul)', value: 'Asia/Seoul' },
{ label: '新加坡(Asia/Singapore)', value: 'Asia/Singapore' },
{ label: '印度(Asia/Kolkata)', value: 'Asia/Kolkata' },
{ label: '美国西部 - 洛杉矶(America/Los_Angeles)', value: 'America/Los_Angeles' },
{ label: '美国中部 - 芝加哥(America/Chicago)', value: 'America/Chicago' },
{ label: '美国东部 - 纽约(America/New_York)', value: 'America/New_York' },
{ label: '英国(Europe/London)', value: 'Europe/London' },
{ label: '德国(Europe/Berlin)', value: 'Europe/Berlin' },
{ label: '法国(Europe/Paris)', value: 'Europe/Paris' },
{ label: '澳大利亚 - 悉尼(Australia/Sydney)', value: 'Australia/Sydney' },
{ label: '新西兰(Pacific/Auckland)', value: 'Pacific/Auckland' },
{ label: '夏威夷(Pacific/Honolulu)', value: 'Pacific/Honolulu' },
{ label: 'UTC(协调世界时)', value: 'UTC' }
] function renderTimezoneOptions() {
const fromSelect = document.getElementById('fromZone')
const toSelect = document.getElementById('toZone') timezones.forEach(({ label, value }) => {
const opt1 = new Option(label, value)
const opt2 = new Option(label, value)
fromSelect.appendChild(opt1)
toSelect.appendChild(opt2) }) fromSelect.value = 'Asia/Shanghai'
toSelect.value = 'America/Los_Angeles'
} function convertTime() {
const input = document.getElementById('inputDate').value
const fromZone = document.getElementById('fromZone').value
const toZone = document.getElementById('toZone').value
const output = document.getElementById('output')
const error = document.getElementById('error') error.textContent = '' if (!input) {
error.textContent = ' 请选择一个时间'
return
} try {
const dt = DateTime.fromISO(input, { zone: fromZone })
const toTime = dt.setZone(toZone) const result = `
原始时间(${fromZone}):
${dt.toFormat('yyyy-MM-dd HH:mm:ss ZZZZ')} 时间戳(UTC 毫秒):
${dt.toMillis()} ️ 转换后时间(${toZone}):
${toTime.toFormat('yyyy-MM-dd HH:mm:ss ZZZZ')}
`.trim() output.textContent = result
} catch (e) {
error.textContent = ' 转换失败,请检查输入'
}
} function copyResult() {
const result = document.getElementById('output').textContent
if (!result || result.includes('将在这里显示')) return
navigator.clipboard.writeText(result).then(() => {
alert(' 已复制到剪贴板!')
})
} // 初始化
document.addEventListener('DOMContentLoaded', () => {
renderTimezoneOptions()
const now = new Date()
const local = now.toISOString().slice(0, 16)
document.getElementById('inputDate').value = local
}) // 注册 PWA service worker
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('service-worker.js')
.then(() => console.log(' Service Worker 注册成功'))
.catch(err => console.log(' 注册失败:', err))
})
}
</script>
</body>
</html>

5. Live server 启动

启动完成安装到本地即可

六、总结

本项目对比并选用 Luxon 实现多时区转换,支持各时区时间互转。

提供 NodeJS 与 Python 脚本、网页小工具及 PWA 应用,功能完整、结构清晰。

适用于快速使用、系统集成或离线访问,具备良好扩展性。

时区转换工具+PWA离线网页的更多相关文章

  1. 音乐解锁工具v1.10.3,QQ音乐,网易云,酷狗音乐格式转换工具,ncm转mp3,kgm转mp3,kgma转mp3,mgg转mp3,mflac转mp3,qmc转mp3,xm转mp3,kwm转mp3

    现在主流的听歌软件开会员听歌和下载单曲已经是两套业务了,即使开了会员下载的单曲也只能用固定的播放器进行播放,不能使用其他软件播放. 目前QQ音乐.网抑云音乐.酷狗等会员歌曲下载后都不再是传统的音频文件 ...

  2. web字体格式及几种在线格式转换工具介绍

    原文地址:http://blog.csdn.net/xiaolongtotop/article/details/8316554 目前,文字信息仍是网站最主要的内容,随着CSS3技术的不断成熟,Web字 ...

  3. 推荐一款免费的PDF转换工具 | PDFCandy

    相信大家在用的PDF转换工具也很多,下面良心推荐这款软件(PDFCandy)给大家,方便在今后的工作中进行运用.提高大家的工作效率. PDFCandy分为两种:网页端和客户端.(根据大家的喜好度来进行 ...

  4. 爬虫 Http请求,urllib2获取数据,第三方库requests获取数据,BeautifulSoup处理数据,使用Chrome浏览器开发者工具显示检查网页源代码,json模块的dumps,loads,dump,load方法介绍

    爬虫 Http请求,urllib2获取数据,第三方库requests获取数据,BeautifulSoup处理数据,使用Chrome浏览器开发者工具显示检查网页源代码,json模块的dumps,load ...

  5. 使用wget工具抓取网页和图片 及 相关工具几个

    想保存一些网页,最后找到这 wget 的 shell脚本,虽然不是太理想,亲测可用呢. 使用wget工具抓取网页和图片   来源 https://my.oschina.net/freestyletim ...

  6. SQL Server全时区转换

    SQL Server全时区转换 假如你的应用程序是跨国(例如跨国银行交易)使用的话,那么数据库的一些国际化特性支持可以说是非常重要 其中最常见的就是各国时区上的差异,由于SQL Server getd ...

  7. Unicode编码解码在线转换工具

    // Unicode编码解码在线转换工具 Unicode 是基于通用字符集(Universal Character Set)的标准来发展,并且同时也以书本的形式(The Unicode Standar ...

  8. android px,dp,sp大小转换工具

    package com.voole.playerlib.util; import android.content.Context; /** * Android大小单位转换工具类<br/> ...

  9. Json与javaBean之间的转换工具类

    /**  * Json与javaBean之间的转换工具类  *  * {@code 现使用json-lib组件实现  *    需要  *     json-lib-2.4-jdk15.jar  * ...

  10. Rsa加解密Java、C#、php通用代码 密钥转换工具

    之前发了一篇"TripleDes的加解密Java.C#.php通用代码",后面又有项目用到了Rsa加解密,还是在不同系统之间进行交互,Rsa在不同语言的密钥格式不一样,所以过程中主 ...

随机推荐

  1. 插入dp学习笔记

    定义 插入 \(\text{dp}\) 适用于计数.求最优解且具有选择.排列元素过程等题目. 插入 \(\text{dp}\) 大致分为两类: 乱搞型:状态定义天马行空,但始终围绕着将新元素插入到旧元 ...

  2. ESP32 idf常用脚本命令及git命令

    一.Linux环境 1.下载并安装相关的工具 ./install.sh 2.添加ESP-IDF工具到PATH中 . ./export.sh 3.打开配置界面 idf.py menuconfig 4.设 ...

  3. 微信小程序slot(二)

    在组件的 wxml 中可以包含 slot 节点,用于承载组件使用者提供的 wxml 结构. 默认情况下,一个组件的 wxml 中只能有一个 slot .需要使用多 slot 时,可以在组件 js 中声 ...

  4. SQL SERVER日常运维(二)

    以下语句请使用SA用户或者有DBA权限的用户进行执行,否则可能会出现权限不足报错. 查看当前用户查看当前用户 select system_user; 检查SQL Agent是否开启 IF EXISTS ...

  5. SOUI4新版本的日志系统介绍

    原来的日志输出宏用法有点奇怪,感觉总是不够理想.这近有点时间终于把它重整了一下. 以前的用法就不介绍了,重点介绍一下新版本的用法. 在SOUI中使用的日志系统包含两个部分:日志输出宏及日志到文件的打印 ...

  6. 斩获“年度突破成果”奖!天翼云构建强大AI算力基础,制胜人工智能新时代

    8月18-19日,2023中国算力大会在宁夏银川举办.在大会"年度突破成果"发布环节,中国电信天翼云<基于异构多云环境下的息壤算力调度应用实践>荣获2023中国算力大会 ...

  7. AllPairs工具助力正交表测试用例设计

    AllPairs工具助力正交表测试用例设计 正交表法是一种高效的测试方法,特别适用于软件测试中需要处理多个控件及其多种取值组合的情况.以下是对正交表法的详细解释: 一.正交表法概述 正交表法是一种利用 ...

  8. iceberg调研-查询Iceberg表流程

    1.查询表结构 show create table data_lake_ods.dws_service_subclazz_lesson_user_learn_stat_rt_v2 CREATE TAB ...

  9. CSP 2024 游记

    初赛 Day -1 唐,rp--了. 上午语文正卷满分,然后作文挂完了靠.我没想到我作文能挂到 40pts. 吃饭的时候 gcy 说了什么奇怪的东西,然后喷饭爆金币了,社死现场.吃饭的时候还 tm 咬 ...

  10. Luogu P3177 树上染色 [ 蓝 ] [ 树形 dp ] [ 贡献思维 ]

    一道很好的树形 dp !!!!! 树上染色. 错误思路 定义 \(dp[u][i]\) 表示以 \(u\) 为根的子树中,把 \(i\) 个点染成黑色的最大收益. 但这样写,就在转移的时候必须枚举每一 ...