- Temporal documentation1
- Is It Time for the JavaScript Temporal API?2
- JS Dates Are About to Be Fixed | TimeTime
- Using Intl.RelativeTimeFormat for Localized Relative Timings
- Everything You Need to Know About Date in JavaScript | CSS-Tricks3
- 자바스크립트에서 타임존 다루기 (1) : NHN Cloud Meetup4
- 자바스크립트에서 타임존 다루기 (2) : NHN Cloud Meetup
Footnotes
RSC에서 날짜 처리: 쿠키 기반 타임존
문제: Date 객체 직렬화, 서버/클라이언트 타임존 불일치, 하이드레이션 FOUT
해결: 서버에서 타임존 적용해서 렌더링
// proxy.js (Next.js 16 — 예전 middleware.js) - 타임존 감지
export function proxy(request) {
const timezone =
request.cookies.get('user-timezone')?.value ||
request.headers.get('x-vercel-ip-timezone') || // Vercel. request.geo 는 15 에서 제거
'UTC'
const requestHeaders = new Headers(request.headers)
requestHeaders.set('x-user-timezone', timezone)
// 응답 헤더가 아니라 요청 헤더로 넘겨야 서버 컴포넌트의 headers() 가 읽는다
return NextResponse.next({ request: { headers: requestHeaders } })
}
// 서버 컴포넌트
const getUserTimezone = cache(async () => {
return (await headers()).get('x-user-timezone') || 'UTC' // 15 부터 async
})
// 클라이언트 - 타임존 자동 감지 후 쿠키 저장
useEffect(() => {
const tz = Intl.DateTimeFormat().resolvedOptions().timeZone
document.cookie = `user-timezone=${tz}; path=/; max-age=31536000`
}, [])
첫 방문은 인프라 추정값 사용, 이후 정확한 타임존 적용. FOUT 없음.123
대안: useSyncExternalStore (client component 전용)
'use client'
const timezoneStore = {
getSnapshot: () => Intl.DateTimeFormat().resolvedOptions().timeZone,
getServerSnapshot: () => 'UTC',
subscribe: () => () => {},
}
function useTimezone() {
return useSyncExternalStore(
timezoneStore.subscribe,
timezoneStore.getSnapshot,
timezoneStore.getServerSnapshot
)
}
서버: UTC → 클라이언트: 실제 타임존. 하이드레이션 에러 없음, 대신 FOUT 발생 — getServerSnapshot 은 서버 렌더와 하이드레이션 때만 쓰이고, 그 뒤 getSnapshot 값으로 다시 그린다.4
Footnotes
-
proxy.js – Next.js: “The
middlewarefile convention is deprecated and has been renamed toproxy.” / “NextResponse.next({ request: { headers: requestHeaders } })to makerequestHeadersavailable upstream” ↩ -
How to upgrade to version 15 – Next.js: “The
geoandipproperties onNextRequesthave been removed as these values are provided by your hosting provider.” / “Previously synchronous Request-time APIs that rely on request information are now asynchronous” ↩ -
Request headers – Vercel: “The name of the time zone for the location of the requester’s public IP address in ICANN Time Zone Database name format such as
America/Chicago.” ↩ -
useSyncExternalStore – React: “optional getServerSnapshot: A function that returns the initial snapshot of the data in the store. It will be used only during server rendering and during hydration of server-rendered content on the client.” ↩