From d05a8a7065a128ebda5f638634e7377bf6dfc337 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=A8=E9=9C=96=E9=93=83?= Date: Fri, 19 Dec 2025 22:25:27 +0800 Subject: [PATCH] =?UTF-8?q?feat(timestamp):=20=E5=AE=9E=E7=8E=B0=E6=97=B6?= =?UTF-8?q?=E9=97=B4=E6=88=B3=E4=B8=8E=E6=97=A5=E6=9C=9F=E6=97=B6=E9=97=B4?= =?UTF-8?q?=E8=BD=AC=E6=8D=A2=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增日期时间转时间戳组件 DatetimeToTimestamp - 新增时间戳转日期时间组件 TimestampToDatetime - 新增当前时间戳显示组件 TimestampExecution - 重构 TimestampPage 页面,拆分功能到独立组件 - 扩展 timeUtils 工具函数,支持时区处理和格式化 - 添加时区选择器和时间单位切换功能 - 优化时间戳转换逻辑,支持毫秒和秒单位切换 - 改进 App.css 样式宽度设置 --- src/App.css | 2 +- src/components/DatetimeToTimestamp.js | 60 ++++++++++ src/components/TimestampExecution.js | 45 +++++++ src/components/TimestampToDatetime.js | 69 +++++++++++ src/pages/TimestampPage.js | 166 ++------------------------ src/utils/timeUtils.js | 60 +++++++++- 6 files changed, 243 insertions(+), 159 deletions(-) create mode 100644 src/components/DatetimeToTimestamp.js create mode 100644 src/components/TimestampExecution.js create mode 100644 src/components/TimestampToDatetime.js diff --git a/src/App.css b/src/App.css index 1d9e23d..94526e5 100644 --- a/src/App.css +++ b/src/App.css @@ -3,7 +3,7 @@ margin: 0 auto; padding: 20px; font-family: Arial, sans-serif; - width: 300px; + width: 350px; height: 100vh; } diff --git a/src/components/DatetimeToTimestamp.js b/src/components/DatetimeToTimestamp.js new file mode 100644 index 0000000..aacd844 --- /dev/null +++ b/src/components/DatetimeToTimestamp.js @@ -0,0 +1,60 @@ +import {formatWithDate, formatWithZone, TimezoneOptions} from "../utils/timeUtils"; +import {useMemo, useState} from "react"; + +export function DatetimeToTimestamp() { + const [dateValue, setDateValue] = useState(() => formatWithZone(Date.now())); + const [selectedZone, setSelectedZone] = useState('Asia/Shanghai'); + const [result, setResult] = useState(''); + const [unit, setUnit] = useState('milliseconds'); + const timeZoneList = useMemo(() => ['America/New_York', 'America/Chicago', 'America/Denver', 'America/Los_Angeles', 'America/Anchorage', 'America/Honolulu', 'Europe/London', 'Europe/Paris', 'Europe/Berlin', 'Europe/Moscow', 'Asia/Tokyo', 'Asia/Shanghai', 'Asia/Hong_Kong', 'Asia/Singapore', 'Asia/Dubai', 'Asia/Kolkata', 'Australia/Sydney', 'Pacific/Auckland',], []); + + const handleConvertDatetimeToTimestamp = () => { + const timestamp = unit === 'milliseconds' ? formatWithDate(dateValue, selectedZone) : Math.floor(formatWithDate(dateValue, selectedZone) / 1000); + setResult(timestamp); + }; + + return (
+

日期时间转时间戳

+
+
+ setDateValue(e.target.value)}/> + +
+ +
+ +
+ +
+ + +
+
+
) +} \ No newline at end of file diff --git a/src/components/TimestampExecution.js b/src/components/TimestampExecution.js new file mode 100644 index 0000000..fba72fc --- /dev/null +++ b/src/components/TimestampExecution.js @@ -0,0 +1,45 @@ +import {useEffect, useState} from "react"; +import CopyButton from "./CopyButton"; + +export function TimestampExecution() { + const [currentTimestamp, setCurrentTimestamp] = useState(Math.floor(Date.now())); + const [showMilliseconds, setShowMilliseconds] = useState(true); + const [isRunningTimestamp, setIsRunningTimestamp] = useState(true); + // 定时更新时间戳 + useEffect(() => { + const timerId = isRunningTimestamp ? setInterval(() => { + setCurrentTimestamp(Math.floor(Date.now())); + }, showMilliseconds ? 100 : 1000) : null; + + return () => clearInterval(timerId); + }, [isRunningTimestamp, showMilliseconds]); + + const toggleUnit = () => setShowMilliseconds(prev => !prev); + const toggleTimestamp = () => setIsRunningTimestamp(prev => !prev); + + return (
+

当前时间戳

+

+ {Math.floor(currentTimestamp / (showMilliseconds ? 1 : 1000))} + {showMilliseconds ? '毫秒' : '秒'} +

+
+ + + +
+
) +} \ No newline at end of file diff --git a/src/components/TimestampToDatetime.js b/src/components/TimestampToDatetime.js new file mode 100644 index 0000000..5b50936 --- /dev/null +++ b/src/components/TimestampToDatetime.js @@ -0,0 +1,69 @@ +import {useMemo, useState} from "react"; +import {formatWithZone, TimezoneOptions} from "../utils/timeUtils"; + +export function TimestampToDatetime() { + const [timestampValue, setTimestampValue] = useState(Date.now()); + const [timestampResult, setTimestampResult] = useState(''); + const [unit, setUnit] = useState('milliseconds'); + const [selectedZone, setSelectedZone] = useState('Asia/Shanghai'); + const timeZoneList = useMemo(() => ['America/New_York', 'America/Chicago', 'America/Denver', 'America/Los_Angeles', 'America/Anchorage', 'America/Honolulu', 'Europe/London', 'Europe/Paris', 'Europe/Berlin', 'Europe/Moscow', 'Asia/Tokyo', 'Asia/Shanghai', 'Asia/Hong_Kong', 'Asia/Singapore', 'Asia/Dubai', 'Asia/Kolkata', 'Australia/Sydney', 'Pacific/Auckland',], []); + + function handleConvertTimestampToDate() { + if (!timestampValue) { + setTimestampResult('请输入时间戳'); + return; + } + + const result = formatWithZone(timestampValue, selectedZone, unit); + setTimestampResult(result); + } + + const handleInputChange = (e) => setTimestampValue(e.target.value); + + return ( +
+

时间戳转日期时间

+
+
+ + +
+ +
+ +
+ +
+ + +
+
+
+ ) +} \ No newline at end of file diff --git a/src/pages/TimestampPage.js b/src/pages/TimestampPage.js index a22310f..5577dac 100644 --- a/src/pages/TimestampPage.js +++ b/src/pages/TimestampPage.js @@ -1,163 +1,15 @@ -import {useState, useEffect} from 'react'; -import CopyButton from "../components/CopyButton"; -import {formatDate} from "../utils/timeUtils"; +import {TimestampToDatetime} from "../components/TimestampToDatetime"; +import {DatetimeToTimestamp} from "../components/DatetimeToTimestamp"; +import {TimestampExecution} from "../components/TimestampExecution"; + const TimestampPage = () => { - const [currentTimestamp, setCurrentTimestamp] = useState(Math.floor(Date.now())); - const [showMilliseconds, setShowMilliseconds] = useState(true); - const [isRunningTimestamp, setIsRunningTimestamp] = useState(true); - const [timestampValue, setTimestampValue] = useState(Date.now()); - const [dateValue, setDateValue] = useState(formatDate(Date.now())); - const [timestampResult, setTimestampResult] = useState(''); - const [dateResult, setDateResult] = useState(''); - // 定时更新时间戳 - useEffect(() => { - let timerId = null; - - if (isRunningTimestamp) { - timerId = setInterval(() => { - setCurrentTimestamp(Math.floor(Date.now())); - }, 1000); - } - - return () => { - if (timerId) { - clearInterval(timerId); - timerId = null; - } - } - }, [isRunningTimestamp]); - - function toggleUnit() { - setShowMilliseconds(prev => !prev); - } - - function toggleTimestamp() { - setIsRunningTimestamp((prev => !prev)); - } - - function handleConvertTimestampToDate() { - if (!timestampValue) { - setTimestampResult('请输入时间戳'); - return; - } - - setTimestampResult(formatDate(new Date(Number(timestampValue)))); - } - - function handleConvertDateToTimestamp() { - if (!dateValue) { - setDateResult('请输入日期222'); - return; - } - - const date = new Date(dateValue); - - if (isNaN(date.getTime())) { - setDateResult('请输入日期333'); - return; - } - - setDateResult(date.getTime()); - } - - return ( -
-
-

当前时间戳

-

- {Math.floor(currentTimestamp / (showMilliseconds ? 1 : 1000))} - {showMilliseconds ? '毫秒' : '秒'} -

-
- - - -
-
- -
-

时间戳转日期时间

-
-
- setTimestampValue(Number(e.target.value))}/> - -
- -
- -
- -
- - -
-
-
- -
-

日期时间转时间戳

-
-
- setDateValue(e.target.value)}/> - -
- -
- -
- -
- - -
-
-
-
- ); + return (
+ + + +
); }; export default TimestampPage; diff --git a/src/utils/timeUtils.js b/src/utils/timeUtils.js index ac78ed7..e655469 100644 --- a/src/utils/timeUtils.js +++ b/src/utils/timeUtils.js @@ -1,4 +1,4 @@ -export function formatDate(value) { +export function formatDate(value, timezone = 'Asia/Shanghai') { return (new Intl.DateTimeFormat('zh-CN', { year: 'numeric', month: 'numeric', @@ -6,6 +6,64 @@ export function formatDate(value) { hour: 'numeric', minute: 'numeric', second: 'numeric', + timeZone: timezone, })).format(value); } +export const TimezoneOptions = ({zones}) => { + return (zones.map((zone) => ())); +} + +export const formatWithZone = (timestamp, zone = 'Asia/Shanghai', unit = 'milliseconds') => { + try { + const ms = unit === 'milliseconds' ? Number(timestamp) : Number(timestamp) * 1000; + return new Intl.DateTimeFormat('zh-CN', { + year: 'numeric', + month: 'numeric', + day: 'numeric', + hour: 'numeric', + minute: 'numeric', + second: 'numeric', + timeZone: zone, + }).format(ms); + } catch (e) { + return '格式错误'; + } +} + +export const getTimeZoneOffset = (timeZone) => { + const now = new Date(); + const utc = new Date(now.toLocaleString('en-US', {timeZone: 'UTC'})); + const target = new Date(now.toLocaleString('en-US', {timeZone: timeZone})); + return target.getTime() - utc.getTime(); +} + +export const formatWithDate = ( + date, + timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone +) => { + try { + // 创建日期对象 + const dateObj = new Date(date); + + // 检查日期是否有效 + if (isNaN(dateObj.getTime())) { + return '无效的日期'; + } + + // 如果提供了时区,则需要特殊处理 + if (timeZone) { + // 获取给定时区相对于UTC的时间差(毫秒) + const utc = dateObj.getTime() + dateObj.getTimezoneOffset() * 60000; + + // 计算目标时区相对于UTC的偏移量 + const targetOffset = getTimeZoneOffset(timeZone); + + return utc + targetOffset; + } else { + return dateObj.getTime(); + } + } catch (error) { + return '日期转换错误: ' + error.message; + } +}