System.DateTime은 1년부터 9999년까지의 날짜와 하루 중 시각을 100나노초(1 "틱") 정밀도로 나타냅니다. System.TimeSpan은 기간, 즉 두 DateTime 값의 차이를 나타냅니다. 둘 다 불변 값 형식(구조체)이므로 모든 연산이 새 값을 반환합니다.
출력:
2026-09-24 00:00:00
2026-09-24 14:30:00
14:30:05.250
2026 9 24
14:30
Thursday
267
2026-09-24 00:00
14:30:00
이 페이지의 모든 예제는 명시적인 서식 문자열로 날짜를 출력합니다. 기본 ToString()은 현재 문화권을 따르므로(미국에서는 9/24/2026 2:30:00 PM, 독일에서는 24.09.2026 14:30:00) 출력이 컴퓨터에 따라 달라집니다. 서식 코드는 DateTime 서식에 있습니다.
잘못된 날짜는 예외를 던집니다. new DateTime(2026, 2, 30)은 ArgumentOutOfRangeException을 발생시키고, 13월이나 24시도 마찬가지입니다.
Now, UtcNow, Today
세 정적 속성이 시계를 읽습니다:
출력 예:
Now: 2026-09-24 18:20:41 (Local)
UtcNow: 2026-09-24 16:20:41 (Utc)
Today: 2026-09-24 00:00:00
이 예에서는 로컬 시간대가 UTC보다 두 시간 빠르므로 처음 두 줄이 두 시간 차이 납니다. UTC로 설정된 컴퓨터에서는 같습니다. Kind 속성은 값이 Local, Utc, Unspecified(직접 만든 날짜의 기본값) 중 무엇인지 기록합니다. 저장하거나, 로그에 남기거나, 비교하거나, 다른 시스템에 보내는 모든 것에는 DateTime.UtcNow를 쓰세요. 일광 절약 시간이 시작하거나 끝날 때 건너뛰지 않고, 모든 서버에서 같은 순간을 뜻합니다. 로컬 시간으로는 사람에게 값을 보여 줄 때만 변환하세요.
코드 실행 시간을 재려면 DateTime.Now 두 값을 빼지 말고 System.Diagnostics.Stopwatch를 쓰세요. 해상도가 훨씬 높고 시계 조정의 영향을 받지 않습니다.
시간 더하기와 빼기
AddDays, AddHours, AddMinutes, AddSeconds, AddMonths, AddYears는 새 DateTime을 반환합니다. 음수를 넘기면 과거로 갑니다. DateTime은 불변이므로 결과를 대입해야 합니다:
출력:
2026-01-31
2026-02-03 09:00
2026-01-30 21:00
2026-02-28
2027-01-31
10:30
29
True
해당 날짜가 없으면 AddMonths는 그 달의 마지막 날로 맞춥니다. 1월 31일에 한 달을 더하면 3월 3일이 아니라 2월 28일(윤년이면 29일)입니다. 그래서 한 달을 두 번 더한 것과 두 달을 더한 것이 다른 날짜가 될 수 있습니다.
날짜 빼기: TimeSpan
한 DateTime에서 다른 DateTime을 빼면 TimeSpan이 나옵니다:
출력:
3.20:30:00
Days: 3, Hours: 20, Minutes: 30
TotalDays: 3.85
TotalHours: 92.5
TotalMinutes: 5550
Nights: 4
API에서 사람들이 가장 자주 틀리는 부분이 여기입니다. Days, Hours, Minutes, Seconds는 기간의 구성 요소입니다(3일, 20시간, 30분). TotalDays, TotalHours, TotalMinutes는 전체 기간을 한 단위로 나타낸 double입니다. "손님이 몇 시간 머물렀나?"는 Hours(20)가 아니라 TotalHours(92.5)입니다.
마지막 줄은 관련된 점을 보여 줍니다. 3.85일이 지났지만 손님은 4박을 했습니다. .Date 부분을 비교하면 달력상의 날수를 세며, 청구나 "며칠 남음" 표시에는 보통 이것이 필요합니다.
TimeSpan 값 만들기와 서식화
출력:
02:15:00
01:30:00
1.12:00:00
True
03:45:00
True
02:15
36h 0m
00:00:00
TimeSpan은 +, -, 비교, Duration()(절댓값), Negate()를 지원합니다. @"hh\:mm" 같은 사용자 지정 서식은 리터럴 문자 앞에 백슬래시가 필요하고, 여기서 hh는 시간 구성 요소(0~23)만 보여 주므로, 하루가 넘는 기간은 끝에서 두 번째 줄처럼 TotalHours로 텍스트를 만드세요.
날짜 비교
DateTime은 ==, !=, <, >, <=, >=와 CompareTo, DateTime.Compare를 지원합니다. 시간을 무시하고 날짜만 비교하려면 .Date 속성을 비교하세요:
출력:
True
True
1
True
2026-09-01
"이 타임스탬프가 9월 30일까지인가?"를 확인할 때는 위처럼 다음 날의 시작과 <로 비교하세요. check <= end라고 쓰면 end가 2026-09-30 00:00:00이므로 마지막 날 자정 이후가 모두 빠집니다.
비교는 Kind가 아니라 틱만 봅니다. 똑같이 출력되는 Local 값과 Utc 값은 서로 다른 순간인데도 같다고 판단됩니다. 저장하는 시간을 UTC로 유지해야 하는 또 하나의 이유입니다.
요일과 주의 시작
DayOfWeek는 Sunday(0)부터 Saturday(6)까지의 열거형입니다. 이를 계산하면 평일과 주의 경계를 찾을 수 있습니다:
출력:
Thursday
4
Weekend: False
Week starts 2026-09-21 (Monday)
Next Friday: 2026-09-25
2026-09-01 to 2026-09-30
DayOfWeek.ToString()이 출력하는 요일 이름은 항상 영어입니다. 현지화된 이름이 필요하면 "dddd"와 문화권으로 날짜를 서식화하세요.
문자열에서 날짜 파싱하기
입력 형식을 안다면 CultureInfo.InvariantCulture와 함께 ParseExact나 TryParseExact를 쓰세요. 서식 문자열은 서식화와 같은 코드를 씁니다:
출력:
2026-09-24 00:00
2026-09-24 18:05
'2026-02-28' -> Saturday, February 28
'2026-02-30' -> invalid
'28.02.2026' -> invalid
'' -> invalid
2026-02-28
2026-09-24 10:00 Utc
형식 없이 쓰는 DateTime.Parse(text)는 현재 문화권으로 추측을 시도합니다. "03/04/2026"은 미국 컴퓨터에서는 3월 4일, 영국 컴퓨터에서는 4월 3일이며, 노트북에서 파싱되던 날짜가 서버에서는 FormatException을 던질 수 있습니다. Parse는 현지 사용자가 입력한 값에만 쓰고, 파일, API, 데이터베이스에는 고정 문화권과 함께 ParseExact를 쓰세요. ParseExact는 텍스트가 맞지 않으면 FormatException을 던지고, TryParseExact는 대신 false를 반환합니다.
나이 계산하기
생년월일을 빼서 365로 나누면 생일과 윤년 근처에서 틀립니다. 연도를 비교한 뒤, 올해 생일이 아직 지나지 않았다면 보정하세요:
출력:
36
35
18
70 days to go
DateTimeOffset
DateTime은 모호한 Kind 플래그 말고는 어느 시간대인지 기록하지 않습니다. DateTimeOffset은 값과 함께 UTC 기준 오프셋을 저장하므로 항상 정확히 한 순간을 식별합니다:
출력:
2026-09-24 14:00 +02:00
2026-09-24 12:00
2026-09-24 12:30
00:30:00
21:00 +09:00
주문이 들어온 시각, 메시지를 보낸 시각 같은 타임스탬프에는 DateTimeOffset(또는 UTC DateTime 값)을 쓰세요. 데이터베이스와 JSON 직렬 변환기가 잘 처리합니다. 일광 절약 규칙이 있는 이름 붙은 시간대 사이의 변환에는 TimeZoneInfo.ConvertTime을 쓰세요. 이전 .NET 버전에서는 운영체제마다 시간대 ID가 다르며(Linux에서는 "Europe/Paris", Windows에서는 "Romance Standard Time"), .NET 6 이상은 둘 다 받습니다.
DateOnly와 TimeOnly(.NET 6 이상)
많은 값이 시간 없는 날짜(생일, 마감일)이거나 날짜 없는 시간(영업시간)입니다. .NET 6은 이를 위한 두 타입을 추가했습니다:
// .NET 6 and later
DateOnly birthday = new DateOnly(1990, 9, 24);
DateOnly due = DateOnly.FromDateTime(DateTime.Today).AddDays(14);
int daysLeft = due.DayNumber - DateOnly.FromDateTime(DateTime.Today).DayNumber;
TimeOnly opens = new TimeOnly(9, 0);
TimeOnly closes = new TimeOnly(17, 30);
bool isOpen = TimeOnly.FromDateTime(DateTime.Now).IsBetween(opens, closes);
이 타입들은 엉뚱한 시간이나 시간대가 날짜를 하루 밀어 버리는 종류의 버그를 없애 줍니다. 예전 코드와 .NET Framework나 Unity를 대상으로 하는 코드는 시간을 자정으로 둔 DateTime을 씁니다.
흔한 실수
AddDays의 결과 버리기.DateTime은 불변이므로 반환값을 대입하세요.TotalHours대신Hours쓰기. 구성 요소와 전체 기간의 차이입니다.DateTime.Now저장하기. UTC로 저장하고 표시할 때 변환하세요.- 출력이 컴퓨터의 문화권에 따라 달라지는 로그, 파일, 테스트에서 서식 없이
ToString()호출하기. - 기계가 만든 데이터를
DateTime.Parse로 파싱하기.ParseExact와 고정 문화권을 쓰세요. - 서식 문자열에서
mm과MM혼동하기(분과 월). DateTime 서식을 참고하세요.
자주 묻는 질문
DateTime.Now와 DateTime.UtcNow의 차이는 무엇인가요?
DateTime.Now는 컴퓨터의 로컬 시간대 기준 현재 시간이고 Kind가 Local입니다. DateTime.UtcNow는 UTC 기준 현재 시간이고 Kind가 Utc이며, 시간대 변환을 건너뛰므로 더 빠릅니다. 타임스탬프는 UTC로 저장하고 비교하며, 표시할 때만 로컬 시간으로 변환하세요.
C#에서 두 날짜의 차이는 어떻게 구하나요?
빼면 됩니다: TimeSpan gap = end - start;. 그런 다음 전체 기간을 double로 얻으려면 gap.TotalDays, gap.TotalHours, gap.TotalMinutes를, 온전한 날수 부분만 원하면 gap.Days를 읽으세요. 달력상의 월이나 연은 달마다 길이가 달라서 기본 제공 속성이 없으므로, 연도와 월 필드를 직접 비교하세요.
TimeSpan.Hours와 TotalHours의 차이는 무엇인가요?
Hours는 온전한 일수를 뺀 뒤의 시간 구성 요소로 0부터 23까지입니다. TotalHours는 전체 기간을 시간 단위로 나타낸 double입니다. 1일 3시간인 기간이라면 Hours는 3, TotalHours는 27입니다. TotalHours를 써야 할 곳에 Hours를 쓰는 것은 아주 흔한 버그입니다.
C#에서 날짜 문자열은 어떻게 파싱하나요?
형식을 안다면 DateTime.ParseExact(text, "yyyy-MM-dd", CultureInfo.InvariantCulture)를 쓰거나, 잘못된 입력에 FormatException 대신 false를 받으려면 DateTime.TryParseExact를 쓰세요. DateTime.Parse는 현재 문화권으로 형식을 추측하므로 03/04/2026이 미국에서는 3월 4일, 영국에서는 4월 3일이 됩니다.
AddDays가 DateTime을 바꾸지 않는 이유는 무엇인가요?
DateTime은 불변 값 형식입니다. AddDays, AddHours 등의 메서드는 원본을 그대로 두고 새 DateTime을 반환하므로 결과를 대입해야 합니다: due = due.AddDays(7);.
언제 DateTime 대신 DateTimeOffset을 써야 하나요?
주문이 들어온 시각이나 로그 항목이 기록된 시각처럼 정확한 순간을 식별해야 하는 타임스탬프에는 DateTimeOffset을 쓰세요. 데이터가 서버와 시간대 사이를 오간다면 특히 그렇습니다. 값과 함께 UTC 기준 오프셋을 저장합니다. UTC만 쓰는 타임스탬프와 시간대가 의미 없는 날짜에는 DateTime으로 충분합니다.