1. DateTime 타입 알아보기
날짜랑 시간은 모든 비즈니스 로직의 기본 벽돌 같은 거라서, 아무리 간단한 프로젝트라도 무시할 수 없어. 언제 사용자가 가입했는지, 언제 메일을 보내야 하는지, 비행 스케줄 처리, 타임존... 다 날짜랑 관련 있지! 근데 실제로 날짜랑 시간 다루는 게 프로그래밍에서 제일 골치 아픈 주제 중 하나야. 😅
C#에서는 시간 다룰 때 특히 중요한 타입이 두 개 있어: DateTime이랑 DateTimeOffset. 간단히 말하면, 하나는 단순한 상황용이고, 다른 하나는 타임존이나 정확한 시간 저장이 필요할 때 써.
DateTime이 뭐야?
DateTime 타입은 System 네임스페이스에 정의된 구조체야. 날짜와 시간을 100 나노초(1/10십억초) 단위로 저장할 수 있어.
- 값 타입(struct)이라서 값 복사됨.
- 날짜랑 시간 둘 다 저장함.
- 날짜만(2025-05-24) 또는 날짜+시간(2025-05-24 15:17:42) 둘 다 저장 가능.
- 명시적으로 지정하지 않으면 타임존 정보 없음.
2. DateTime 만들기
여러 방법이 있는데, 주요한 것만 볼게.
1. 현재 날짜와 시간
DateTime now = DateTime.Now; // 컴퓨터의 로컬 시간
DateTime utcNow = DateTime.UtcNow; // 그리니치 표준시(UTC)
- Now — "네 컴퓨터 기준"이고, Windows의 로컬 타임존을 반영해.
- UtcNow — "유니버설", 즉 전세계 공통 시간. DB나 글로벌 시스템에서 시간 저장할 때 진짜 편함.
2. 생성자
// 연, 월, 일
var date1 = new DateTime(2025, 5, 24);
// 연, 월, 일, 시, 분, 초
var date2 = new DateTime(2025, 5, 24, 12, 0, 0);
// 연, 월, 일, 시, 분, 초, 밀리초
var date3 = new DateTime(2025, 5, 24, 12, 0, 0, 500);
월은 0부터 시작 안 해! 즉, 1월은 1, 12월은 12야.
3. 문자열에서 파싱
날짜가 문자열로 들어오는 경우가 진짜 많아! 예를 들어, 사용자가 직접 날짜를 입력할 때.
string userInput = "2025-05-24 18:30";
DateTime parsed = DateTime.Parse(userInput); // 예외 발생할 수 있음!
안전하게 파싱하려면 TryParse를 써:
string input = "2025-05-24 18:30";
if (DateTime.TryParse(input, out DateTime result))
{
Console.WriteLine($"변환 성공: {result}");
}
else
{
Console.WriteLine("문자열을 날짜로 변환 실패.");
}
4. "시간 없는" 날짜 얻기
DateTime today = DateTime.Today; // 오늘 날짜, 시간은 00:00:00
날짜와 시간 컴포넌트 추출
모든 속성은 바로 꺼낼 수 있어:
var dt = new DateTime(2025, 5, 24, 15, 17, 42);
int year = dt.Year; // 2025
int month = dt.Month; // 5 (5월)
int day = dt.Day; // 24
int hour = dt.Hour; // 15
int minute = dt.Minute; // 17
int second = dt.Second; // 42
DayOfWeek dow = dt.DayOfWeek; // 금요일
3. DateTime 타입 다루기
날짜 더하기/빼기
프로그래밍에서 시간은 순식간에 지나가니까, "마감까지 몇 시간 남았지?" 이런 거 직접 계산하지 말고, 클래스 메서드 써:
DateTime now = DateTime.Now;
DateTime tomorrow = now.AddDays(1); // 내일
DateTime afterFiveHours = now.AddHours(5); // 5시간 후
DateTime inTenMinutes = now.AddMinutes(10); // 10분 후
두 날짜의 차이: TimeSpan
두 날짜의 차이는 별도의 타입 TimeSpan으로 나타내:
DateTime deadline = new DateTime(2026, 6, 1);
DateTime now = DateTime.Now;
TimeSpan untilDeadline = deadline - now;
Console.WriteLine($"마감까지 남은 일수: {untilDeadline.Days}");
Console.WriteLine($"마감까지 남은 시간: {untilDeadline.TotalHours:N2}");
TimeSpan은 "차이"지, "특정 날짜/시간"이 아니야!
미래/과거 날짜 체크
if (deadline > now)
Console.WriteLine("마감 아직 남았어!");
else
Console.WriteLine("마감 지났어! 빨리 제출하자!");
4. 날짜가 내부적으로 저장되는 방식
날짜 더하고 빼기 쉽게 하려고, 프로그래머들은 모든 날짜를 우리 시대 시작부터 지난 초의 수로 저장하기로 했어. 범위 값은:
| 속성 | 값 |
|---|---|
| 최소 날짜 | = 0001-01-01 00:00:00 |
| 최대 날짜 | = 9999-12-31 23:59:59.9999999 |
| 단위 | 1 틱 = 100 나노초 |
DateTime은 그냥 초가 아니라, "틱"(ticks)의 개수를 저장해. 기준 날짜는 0001년 1월 1일(공룡은 모름, 프로그래머 달력은 엄격함). 한 틱 = 100 나노초야.
5. DateTimeOffset 타입
가끔 DateTime만으로 부족할 때가 있어. 예를 들어, 회사가 두 나라에 있는데, 타임존이 다르고, 모든 미팅이 "내 시간 기준"으로 잡혀있을 때. 어떻게 해야 할까?
DateTime으로 저장된 시간은 보통 "추상적"이야: 그냥 숫자랑 틱일 뿐, 어느 타임존인지 명확히 안 알려주면 모름. 예를 들어, "2025-05-24 15:00"을 받았을 때, 이게 나이로비 시간인지, 바그다드인지, 베를린인지 알 수 없어(썸머타임까지 있으면 더 헷갈림!).
그래서 정확한 시점이 필요한 경우, 즉 "달력 날짜"가 아니라 "진짜 순간"이 필요할 때 두 번째 타입 DateTimeOffset이 나왔어. DateTimeOffset을 만들 때 오프셋(예: 나이로비 +3시간)을 지정할 수 있어:
var localTime = new DateTimeOffset(2025, 5, 24, 15, 0, 0, TimeSpan.FromHours(3));
DateTimeOffset을 써야 할 때:
- 정확한 시점이 필요할 때(예: 서버 시간에 맞춘 로그 이벤트).
- 프로그램이 여러 타임존의 사용자랑 동작할 때.
- 타임존 정보까지 저장/전달해야 할 때(예: 트랜잭션, 이벤트, 스케줄).
6. DateTimeOffset 만들기
- 현재 시점
DateTimeOffset now = DateTimeOffset.Now; // 로컬 시간 + 오프셋 DateTimeOffset utc = DateTimeOffset.UtcNow; // UTC(오프셋 0) - 명시적으로 만들기
// 연, 월, 일, 시, 분, 초, 오프셋(예: +2시간) DateTimeOffset custom = new DateTimeOffset(2025, 5, 24, 20, 0, 0, TimeSpan.FromHours(2)); - DateTime에서 변환
DateTime dt = DateTime.Now; DateTimeOffset dto = new DateTimeOffset(dt); // 로컬 오프셋 자동 적용
컴포넌트 추출
DateTimeOffset dto = DateTimeOffset.Now;
var datePart = dto.Date; // 날짜만
var timePart = dto.TimeOfDay; // 시간만
var offset = dto.Offset; // UTC 기준 오프셋, 예: 03:00:00
타임존 변환
오프셋 마법:
// UTC로 변환
var now = DateTimeOffset.Now;
var utc = now.ToUniversalTime();
Console.WriteLine(utc); // 그리니치 표준시
// 다른 타임존으로 변환
var berlinTime = utc.ToOffset(TimeSpan.FromHours(2));
Console.WriteLine(berlinTime); // 베를린(CET +2)
7. DateTime이랑 DateTimeOffset 언제 써야 해?
선택 철학
뭔가 단순하고 로컬한 거라면 — 예를 들어, 생일, 게시글 날짜, 설문 마감 15:00 이런 거면 보통 DateTime이면 충분해. 이런 경우엔 절대적인 시간이 중요하지 않고, 그냥 그날 그 시간에 일이 일어났다는 게 중요하지, 타임존은 신경 안 써도 돼.
근데 정확한 시점이랑 타임존까지 기록해야 한다면, 예를 들어 로그, 트랜잭션, 분산 시스템 등에서는 DateTimeOffset을 쓰는 게 좋아. 시스템끼리 시간 주고받을 때 헷갈릴 일 없고, 특히 타임존이 다르면 필수야.
| 시나리오 | 타입 | 이유 |
|---|---|---|
| 생일 | |
날짜만 중요, 타임존은 보통 신경 안 씀 |
| 로그인 시간 | |
정확한 시점과 오프셋이 중요함 |
| 상품 유효기간 | |
만료 날짜만 중요, 타임존은 신경 안 씀 |
| 로그 이벤트 시간 | |
항상 오프셋과 함께 저장하는 게 좋음 |
GO TO FULL VERSION