diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 71aa5ad..9da2a82 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "dependencies": { "@tanstack/react-query": "^5.90.16", + "dayjs": "^1.11.19", "framer-motion": "^11.0.8", "lucide-react": "^0.344.0", "react": "^18.2.0", @@ -1519,6 +1520,12 @@ "devOptional": true, "license": "MIT" }, + "node_modules/dayjs": { + "version": "1.11.19", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz", + "integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==", + "license": "MIT" + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", diff --git a/frontend/package.json b/frontend/package.json index 57e3e39..2049573 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,6 +10,7 @@ }, "dependencies": { "@tanstack/react-query": "^5.90.16", + "dayjs": "^1.11.19", "framer-motion": "^11.0.8", "lucide-react": "^0.344.0", "react": "^18.2.0", diff --git a/frontend/src/pages/mobile/Home.jsx b/frontend/src/pages/mobile/Home.jsx index 34b4539..ad38875 100644 --- a/frontend/src/pages/mobile/Home.jsx +++ b/frontend/src/pages/mobile/Home.jsx @@ -2,6 +2,7 @@ import { motion } from 'framer-motion'; import { ChevronRight, Clock, Tag } from 'lucide-react'; import { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; +import { getTodayKST } from '../../utils/date'; // 모바일 홈 페이지 function MobileHome() { @@ -24,8 +25,8 @@ function MobileHome() { .then(data => setAlbums(data.slice(0, 2))) .catch(console.error); - // 다가오는 일정 로드 (startDate + limit 방식) - const today = new Date().toISOString().split('T')[0]; + // 다가오는 일정 로드 + const today = getTodayKST(); fetch(`/api/schedules?startDate=${today}&limit=3`) .then(res => res.json()) .then(data => setSchedules(data)) diff --git a/frontend/src/pages/pc/Home.jsx b/frontend/src/pages/pc/Home.jsx index f079200..c9cc756 100644 --- a/frontend/src/pages/pc/Home.jsx +++ b/frontend/src/pages/pc/Home.jsx @@ -2,6 +2,7 @@ import { useState, useEffect } from 'react'; import { motion } from 'framer-motion'; import { Link } from 'react-router-dom'; import { Calendar, ArrowRight, Clock, Link2, Tag } from 'lucide-react'; +import { getTodayKST } from '../../utils/date'; function Home() { const [members, setMembers] = useState([]); @@ -15,11 +16,7 @@ function Home() { .catch(error => console.error('멤버 데이터 로드 오류:', error)); // 다가오는 일정 로드 (오늘 이후 3개) - // KST 기준으로 오늘 날짜 계산 - const now = new Date(); - const kstOffset = 9 * 60; // KST는 UTC+9 - const kstTime = new Date(now.getTime() + (kstOffset + now.getTimezoneOffset()) * 60000); - const todayStr = kstTime.toISOString().split('T')[0]; + const todayStr = getTodayKST(); fetch(`/api/schedules?startDate=${todayStr}&limit=3`) diff --git a/frontend/src/pages/pc/Schedule.jsx b/frontend/src/pages/pc/Schedule.jsx index 2de8734..4401752 100644 --- a/frontend/src/pages/pc/Schedule.jsx +++ b/frontend/src/pages/pc/Schedule.jsx @@ -4,18 +4,11 @@ import { motion, AnimatePresence } from 'framer-motion'; import { Clock, ChevronLeft, ChevronRight, ChevronDown, Tag, Search, ArrowLeft, Link2 } from 'lucide-react'; import { useInfiniteQuery } from '@tanstack/react-query'; import { useInView } from 'react-intersection-observer'; +import { getTodayKST } from '../../utils/date'; function Schedule() { const navigate = useNavigate(); - // KST 기준 오늘 날짜 (YYYY-MM-DD) - const getTodayKST = () => { - const now = new Date(); - const kstOffset = 9 * 60 * 60 * 1000; // 9시간 - const kstDate = new Date(now.getTime() + kstOffset); - return kstDate.toISOString().split('T')[0]; - }; - const [currentDate, setCurrentDate] = useState(new Date()); const [selectedDate, setSelectedDate] = useState(getTodayKST()); // KST 기준 오늘 const [showYearMonthPicker, setShowYearMonthPicker] = useState(false); diff --git a/frontend/src/pages/pc/admin/AdminSchedule.jsx b/frontend/src/pages/pc/admin/AdminSchedule.jsx index b45f6c4..c5ed412 100644 --- a/frontend/src/pages/pc/admin/AdminSchedule.jsx +++ b/frontend/src/pages/pc/admin/AdminSchedule.jsx @@ -11,18 +11,11 @@ import { useInView } from 'react-intersection-observer'; import Toast from '../../../components/Toast'; import Tooltip from '../../../components/Tooltip'; import useScheduleStore from '../../../stores/useScheduleStore'; +import { getTodayKST } from '../../../utils/date'; function AdminSchedule() { const navigate = useNavigate(); - // KST 기준 오늘 날짜 (YYYY-MM-DD) - const getTodayKST = () => { - const now = new Date(); - const kstOffset = 9 * 60 * 60 * 1000; - const kstDate = new Date(now.getTime() + kstOffset); - return kstDate.toISOString().split('T')[0]; - }; - // Zustand 스토어에서 상태 가져오기 const { searchInput, setSearchInput, diff --git a/frontend/src/utils/date.js b/frontend/src/utils/date.js new file mode 100644 index 0000000..3367fbb --- /dev/null +++ b/frontend/src/utils/date.js @@ -0,0 +1,81 @@ +/** + * 날짜 관련 유틸리티 함수 + * dayjs를 사용하여 KST(한국 표준시) 기준으로 날짜 처리 + */ +import dayjs from "dayjs"; +import utc from "dayjs/plugin/utc"; +import timezone from "dayjs/plugin/timezone"; + +// 플러그인 확장 +dayjs.extend(utc); +dayjs.extend(timezone); + +// 기본 타임존 설정 +const KST = "Asia/Seoul"; + +/** + * KST 기준 오늘 날짜 (YYYY-MM-DD) + * @returns {string} 오늘 날짜 문자열 + */ +export const getTodayKST = () => { + return dayjs().tz(KST).format("YYYY-MM-DD"); +}; + +/** + * KST 기준 현재 시각 + * @returns {dayjs.Dayjs} dayjs 객체 + */ +export const nowKST = () => { + return dayjs().tz(KST); +}; + +/** + * 날짜 문자열 포맷팅 + * @param {string|Date} date - 날짜 + * @param {string} format - 포맷 (기본: 'YYYY-MM-DD') + * @returns {string} 포맷된 날짜 문자열 + */ +export const formatDate = (date, format = "YYYY-MM-DD") => { + return dayjs(date).tz(KST).format(format); +}; + +/** + * 날짜에서 년, 월, 일, 요일 추출 + * @param {string|Date} date - 날짜 + * @returns {object} { year, month, day, weekday } + */ +export const parseDateKST = (date) => { + const d = dayjs(date).tz(KST); + const weekdays = ["일", "월", "화", "수", "목", "금", "토"]; + return { + year: d.year(), + month: d.month() + 1, + day: d.date(), + weekday: weekdays[d.day()], + }; +}; + +/** + * 두 날짜 비교 (같은 날인지) + * @param {string|Date} date1 + * @param {string|Date} date2 + * @returns {boolean} + */ +export const isSameDay = (date1, date2) => { + return ( + dayjs(date1).tz(KST).format("YYYY-MM-DD") === + dayjs(date2).tz(KST).format("YYYY-MM-DD") + ); +}; + +/** + * 날짜가 오늘인지 확인 + * @param {string|Date} date + * @returns {boolean} + */ +export const isToday = (date) => { + return isSameDay(date, dayjs()); +}; + +// dayjs 인스턴스도 export (고급 사용용) +export { dayjs };