
날짜와 시간 얻기 -> Date 객체 사용: new Date()을 사용하면 현재 날짜와 시간을 나타내는 Date 객체가 생성됨.
Date 객체를 다양한 메서드를 통해 다른 형식으로 출력할 수 있음. Date안에는 다양한 메서드가 있음.
Date 객체의 개별 구성 요소를 추출할때 쓸 수 있는 메서드들 예시
console.log(currentDate.getFullYear()); // 예: 2024
console.log(currentDate.getMonth() + 1);
// 예: 6 (월은 0부터 시작하므로 1을 더함)
console.log(currentDate.getDate()); // 예: 12
console.log(currentDate.getHours()); // 예: 14
console.log(currentDate.getMinutes()); // 예: 20
console.log(currentDate.getSeconds()); // 예: 30
현재 시간을 밀리초 단위의 정수로 받기: Date 객체와 getTime() 메서드를 사용
const now = new Date();
const timestamp = now.getTime();
console.log(timestamp); // 예: 1686568830000 (밀리초 단위의 정수 형태)
현재 시간을 초 단위의 정수로 받기:밀리초 단위 대신 초 단위로 받고 싶으면, 밀리초 단위를 1000으로 나누면 됨
const now = new Date();
const timestampInSeconds = Math.floor(now.getTime() / 1000);
console.log(timestampInSeconds); // 예: 1686568830 (초 단위의 정수 형태)
Date.now() 메서드: 현재 시간을 밀리초 단위의 정수 형태로 반환!
padStart: JavaScript의 String 객체 메서드로, 문자열의 시작 부분을 특정 문자로 채워 지정된 길이의 문자열을 반환해줌.
const number = 5;
const formattedNumber = number.toString().padStart(2, '0');
console.log(formattedNumber); // "05"
Date 객체 생성자에는 다양한 형태의 인수를 사용할 수 있다.
메세지로 나오는 게 좋기는 한데, 그래도 구체적인 날씨정보를 수치로 확인하고 싶은 마음이 들었음.
그래서 메세지 area를 클릭하면 detail이 보이도록 만들어 보았음.
openWeatherMap에서 날씨 데이터에는 아래와 같은 내용이 포함되어 있음
sys: {
type: 1,
id: 8105,
country: 'KR',
sunrise: 1718223019,
sunset: 1718276047
},
timezone: 32400,
이 중에서 내가 사용할 부분은 sunrise, sunset,timezone
sunrise와 sunset은 시간을 초단위 타임스탬프로 보여주고 있음. 그래서,
이 녀석들을 우선 밀리세컨즈로 변환하여 Date 객체를 생성하고
그리고 getUTCHours()와 getUTCMinutes()를 사용해서 시간, 분을 추출하고
padStart를 사용하여 두자리로 포맷팅 할 것이다!
코드
export function convertSuntime(timestamp: number) {
// 밀리세컨즈로 변환하여 Date 객체 생성
const date = new Date(timestamp * 1000);
// 시간, 분 추출 + 두 자리 포맷팅
const hours = date.getHours().toString().padStart(2, "0");
const minutes = date.getMinutes().toString().padStart(2, "0");
return `${hours}:${minutes}`;
}
사용부
<p>
일출: <span>{convertSuntime(sunrise)}</span> | 일몰:
<span>{convertSuntime(sunset)}</span>
</p>
결과

Ta-da!
시간, 분을 추출할 때 getUTCHours, getUTCMinutes를 사용하면 특정 타임존에 맞는 시간을 보여줄 수 있다. 특정 지역의 일출/일몰 시간을 계산해서 보여주고 싶을때 쓸 수 있겠음.
그냥 getHours, getMinutes를 쓰면 시스템의 로컬 시간대로 변환하기 때문에 시스템의 로컬 시간대에 따라 결과가 달라질 수 있음!
나는 특정 지역의 일출/일몰 시간을 사용자의 로컬 시간대로 보고 싶기 때문에 그냥 getHours, getMinutes를 사용함
완성 코드
//src>app>components>CasterOptions.tsx
import { Caster } from "../service/openai";
import { useCaster } from "../context/CasterContext";
type Props = {
onClose: () => void;
};
export type ExtendedCaster = Caster | "랜덤";
const CASTERS: ExtendedCaster[] = [
"랜덤",
"할머니",
"이장님",
"엄마",
"여자캐스터",
"남자캐스터",
"KPOP매니아",
"먹방유튜버",
];
export default function CasterOptions({ onClose }: Props) {
const { setCaster } = useCaster();
const handleOptions = (event: React.MouseEvent<HTMLLIElement>) => {
const clickedText = event.currentTarget.innerText as ExtendedCaster;
if (clickedText === "랜덤") {
const randomIndex = Math.floor(Math.random() * CASTERS.length);
setCaster(CASTERS[randomIndex] as Caster);
} else {
setCaster(clickedText);
}
onClose();
};
return (
<ul className="flex flex-col items-center w-full h-full justify-around ">
{CASTERS.map((caster) => (
<li
onClick={handleOptions}
className="hover:cursor-pointer flex justify-center items-center w-full h-full hover:bg-indigo-50 border-b"
key={caster}
>
{caster}
</li>
))}
</ul>
);
}
// src>app>components>CasterAvatar.tsx
import Image from "next/image";
import { useCaster } from "../context/CasterContext";
import { Caster } from "../service/openai";
import { useState } from "react";
import ModalPortal from "./ModalPortal";
import CasterOptions from "./CasterOptions";
import CasterModal from "./CasterModal";
type CasterDetail = {
name: Caster;
src: string;
};
export const CASTERS: CasterDetail[] = [
{ name: "할머니", src: "/images/grandma.webp" },
{ name: "이장님", src: "/images/viliageChief.webp" },
{ name: "엄마", src: "/images/mom.webp" },
{ name: "여자캐스터", src: "/images/femaleCaster.webp" },
{ name: "남자캐스터", src: "/images/maleCaster.webp" },
{ name: "KPOP매니아", src: "/images/kpopMania.webp" },
{ name: "먹방유튜버", src: "/images/foodVlogger.webp" },
];
export default function CasterAvatar() {
const [openModal, setOpenModal] = useState(false);
const { caster } = useCaster();
const currentCaster = CASTERS.find((c) => c.name === caster);
return (
<section className="flex flex-col py-2">
<div className="relative w-[400px] h-[400px]">
{currentCaster && (
<Image
priority
src={currentCaster.src}
alt={`image of ${currentCaster.name} `}
fill
/>
)}
</div>
<button
className="mt-5 p-3 bg-white bg-opacity-50 rounded-md font-bold hover:bg-opacity-30"
onClick={() => setOpenModal(true)}
>
{caster}
</button>
{openModal && (
<ModalPortal>
<CasterModal onClose={() => setOpenModal(false)}>
<CasterOptions onClose={() => setOpenModal(false)} />
</CasterModal>
</ModalPortal>
)}
</section>
);
}
// src>app>context>CasterAvatar.tsx
import React, {
Dispatch,
SetStateAction,
createContext,
useContext,
useState,
} from "react";
import { ExtendedCaster } from "../components/CasterOptions";
type CasterContextType = {
caster: ExtendedCaster;
setCaster: Dispatch<SetStateAction<ExtendedCaster>>;
};
export const CasterContext = createContext<CasterContextType>({
caster: "할머니",
setCaster: () => {},
});
export const CasterProvider = ({ children }: { children: React.ReactNode }) => {
const [caster, setCaster] = useState<ExtendedCaster>("할머니");
return (
<CasterContext.Provider value={{ caster, setCaster }}>
{children}
</CasterContext.Provider>
);
};
export const useCaster = () => useContext(CasterContext);