在 Next.js 中处理时区的几种推荐方案:
1. 使用 UTC 作为统一标准
最佳实践是在服务器端始终使用 UTC 时间存储和处理,只在显示给用户时才转换为本地时区。
import { format } from 'date-fns';
import { utcToZonedTime } from 'date-fns-tz';
interface TimeDisplayProps {
utcTimestamp: string | Date;
}
export function TimeDisplay({ utcTimestamp }: TimeDisplayProps) {
// 获取用户时区
const userTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
// 将 UTC 时间转换为用户时区时间
const localTime = utcToZonedTime(new Date(utcTimestamp), userTimeZone);
// 格式化显示
return <time>{format(localTime, 'yyyy-MM-dd HH:mm:ss')}</time>;
}
2. 使用客户端时区检测
可以在应用启动时检测用户时区:
import { useEffect } from 'react';
function MyApp({ Component, pageProps }) {
useEffect(() => {
// 将用户时区存储在全局状态或 localStorage 中
const userTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
localStorage.setItem('userTimeZone', userTimeZone);
}, []);
return <Component {...pageProps} />;
}
3. 使用现代时间处理库
推荐使用 dayjs
或 date-fns-tz
这样的库来处理时区转换:
import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
import timezone from 'dayjs/plugin/timezone';
dayjs.extend(utc);
dayjs.extend(timezone);
export function formatLocalTime(utcTime: string | Date, format = 'YYYY-MM-DD HH:mm:ss') {
const userTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
return dayjs(utcTime).tz(userTimeZone).format(format);
}
关键建议:
-
服务器端存储:
- 始终使用 UTC 时间存储数据
- 在数据库操作时确保时间戳是 UTC
-
API 响应:
- API 返回的时间始终使用 UTC
- 可以额外返回服务器时区信息供调试
-
客户端显示:
- 使用
Intl.DateTimeFormat()
获取用户时区 - 在显示时才进行时区转换
- 使用
-
测试注意事项:
- 在不同时区的服务器上测试
- 使用不同时区的浏览器测试
- 考虑夏令时的影响
示例测试代码:
describe('Time formatting', () => {
it('should correctly convert UTC to different timezones', () => {
const utcTime = '2024-03-20T10:00:00Z';
// 模拟不同时区
const mockTimeZones = ['America/New_York', 'Asia/Shanghai', 'Europe/London'];
mockTimeZones.forEach(timezone => {
// 测试每个时区的转换
const localTime = formatLocalTime(utcTime);
expect(localTime).toBeDefined();
});
});
});
这样的设置可以确保您的应用在全球范围内都能正确显示时间。记住要在部署前在不同时区进行充分测试,特别是在处理跨日期边界的情况时。