R의 Date는 분장을 한 일수 카운트입니다
문자열을 진짜 날짜로 바꾸려면 as.Date()를, 오늘 날짜를 얻으려면 Sys.Date()를 씁니다. 두 가지 뒤에는 단순한 트릭이 있습니다: R의 Date 클래스는 그저 숫자 - 1970년 1월 1일 이후의 일수 - 이고, 달력 날짜처럼 출력되도록 분장을 하고 있을 뿐입니다. unclass()로 그 분장을 벗길 수 있습니다:
저 20672가 원시 일수 카운트이며, 이 페이지의 나머지 모든 것을 가능하게 하는 값입니다: 비교, 뺄셈, 수열이 모두 밑바닥에서는 정수 연산일 뿐입니다. 분장은 그것을 쓸 만하게 만들어 줍니다 - 같은 숫자가 날짜처럼 출력되고, 날짜로 서식이 지정되며, 날짜 축 위에 그려집니다.
as.Date()는 ISO 배치인 "YYYY-MM-DD"를 도움 없이 기꺼이 파싱합니다. 파일에 날짜를 그런 방식으로 저장해야 하는 여러 이유 중 하나죠. 일찍 들여야 할 습관 하나: 파싱에 실패하면 오류가 아니라 조용히 NA를 반환하므로, 새로운 무언가를 파싱한 뒤에는 항상 결과를 훑어보세요.
날짜처럼 보이기만 하는 문자열은 여전히 그냥 문자열입니다: "2026-08-07" < "2026-11-01"은 ISO 순서가 알파벳 순서와 일치하기 때문에 우연히 올바르게 비교되지만, "07/08/2026"은 엉뚱하게 정렬됩니다. 먼저 변환하고 나서 비교하세요.
format =으로 다른 배치 파싱하기
세상은 ISO 날짜로 쓰지 않습니다. 나머지 모든 경우에 as.Date()는 format = 인자를 받습니다: % 코드로 만든, 들어오는 문자열을 설명하는 레시피죠.
셋 다 같은 날로 파싱됩니다. 레시피는 구분자를 포함해 문자열과 정확히 일치해야 합니다: "%d/%m/%Y"는 "07-08-2026"을 파싱하지 못합니다. 실제로 쓰게 될 코드들입니다:
| 코드 | 의미 | 예시 |
|---|---|---|
%Y | 네 자리 연도 | 2026 |
%y | 두 자리 연도 | 26 |
%m | 월 번호 | 08 |
%d | 일 | 07 |
%b | 축약된 월 이름 | Aug |
%B | 전체 월 이름 | August |
%a | 축약된 요일 | Fri |
%A | 전체 요일 | Friday |
%H | 시 (00-23) | 14 |
%M | 분 | 30 |
%S | 초 | 05 |
전형적인 매복은 "07/08/2026" 그 자체입니다: 세계 대부분에서는 일/월/연이고 미국에서는 월/일/연인데, R은 여러분의 파일이 어느 쪽을 뜻하는지 추측할 수 없습니다. 더 나쁜 것은 잘못된 추측도 종종 "동작한다"는 점입니다 - 두 해석 모두 유효한 날짜니까요 - 어느 달의 13일이 등장해 NA로 파싱될 때까지는요(13월은 없습니다). 레시피를 쓰기 전에 데이터의 관례를 파악하세요.
출력용 날짜 서식 지정
format()은 as.Date()의 거울상입니다: 같은 % 코드를 반대 방향으로 - Date를 넣으면 문자열이 나옵니다.
보고서 제목, 라벨, 파일 이름에 이것을 쓰세요 - format(Sys.Date(), "%Y-%m-%d")는 시간순으로 정렬되는 이름을 만들어 줍니다. 알아 둘 만한 두 가지: %d는 0으로 채우고("August 07"), %B/%A는 시스템 언어 설정에 맞는 이름을 만듭니다 - 독일어로 설정된 세션은 "Friday" 대신 "Freitag"을 출력합니다. 서식 지정은 사람을 위한 것이니 스크립트의 가장자리에 두고, 내부에서는 날짜를 Date로 남겨 두세요.
날짜 연산과 수열
Date가 일수 카운트이므로 연산은 기대한 대로 동작합니다. 두 날짜를 빼면 difftime 객체가 나옵니다:
이 블록에서 가져갈 습관이 셋 있습니다. 첫째, difftime으로 계산하기 전에 as.numeric()으로 감싸세요 - difftime은 단위 속성을 갖고 있어 나중 계산을 놀라게 할 수 있습니다. 둘째, 단위가 중요할 때는 R이 고르는 대로 받아들이지 말고 difftime(units = )으로 명시하세요. 셋째, 평범한 숫자를 더하는 것은 일수 를 더하는 것입니다 - base R에는 + 1 month가 없습니다. "한 달"이 고정된 일수가 아니기 때문이죠.
달력을 인식하는 단계 이동에는 "day", "week", "month", "quarter", "year"를 이해하는 seq()를 쓰세요:
월 단위 수열은 보고 기간과 축 눈금을 만드는 표준 도구입니다. 한 가지 특이점: 31일에 월 단위 수열을 시작하면 R은 31일이 없는 달을 지나며 실제 일수를 계속 세므로 "2월" 항목이 3월 초에 떨어집니다. 월 단위 수열은 1일에 고정하고 나머지는 거기서 유도하세요.
날짜의 구성 요소 추출하기
base R에는 편의 추출 함수 두 개와 일반적인 관용구 하나가 있습니다. weekdays()와 months()는 이름을 반환하고, 숫자가 필요하면 format()을 거쳐 왕복합니다:
format() 뒤에 as.integer()를 붙이는 방식은 돌아가는 것처럼 보이지만 base R의 표준 관용구이며 벡터화되어 있습니다 - 날짜 열 전체를 넘기면 연도 열 전체가 돌아옵니다. CSV 파일에서 날짜가 있는 데이터셋을 임포트한 뒤에 정확히 원하게 되는 동작입니다: 날짜 열을 as.Date()로 한 번 파싱하고, 그룹화를 위해 연도와 월 열을 유도하세요.
날짜만으로 부족할 때: POSIXct, 그리고 lubridate
Date에는 시각 개념이 없습니다. 데이터에 타임스탬프가 등장하는 순간 - 로그 항목, 센서 측정값, "14:32에 주문됨" - R의 날짜·시각 클래스인 POSIXct가 필요합니다: 일수 대신 1970년 이후의 초를 쓰고 시간대를 인식합니다.
모든 것이 그대로 옮겨집니다: 같은 % 코드(이제 %H, %M, %S도 포함)가 파싱과 format()에 동작하고, 뺄셈은 difftime을 주며, Sys.time()이 "지금"입니다. 새로 지는 부담은 시간대입니다 - 파싱할 때 tz =를 명시하세요. 그러지 않으면 서로 다른 시간대의 두 세션이 같은 문자열을 다른 순간으로 읽습니다. 그리고 "혹시 몰라서" 달력 데이터를 POSIXct로 저장하려는 유혹을 이기세요: 어떤 시간대의 자정으로 저장된 생일은 다른 시간대에서 전날로 출력될 수 있고, 이는 추적하기 정말로 괴로운 버그입니다. 온전한 날에는 Date, 순간에는 POSIXct입니다.
마지막으로, lubridate 패키지는 대부분의 tidyverse 코드가 위의 모든 것에 씌우는 더 친절한 얼굴입니다 - base R의 원리를 이해한 뒤에 도입할 가치가 있습니다:
library(lubridate)
ymd("2026-08-07") # order-based parsing: no format string
mdy("08/07/2026") # ...you just say which order the parts come in
dmy("7 August 2026")
floor_date(Sys.Date(), "month") # snap to the start of the period
ymd(), mdy(), dmy()는 형식 레시피를 "구성 요소가 어떤 순서인가"라는 간단한 진술로 대체하고, floor_date()는 "이 타임스탬프들을 월별로 묶어라"를 한 번의 호출로 해결합니다. lubridate는 아래에서 같은 Date/POSIXct 클래스를 타고 달립니다 - 다른 엔진이 아니라 더 나은 핸들인 셈이죠.
핵심 정리
Date는 날짜처럼 출력되도록 차려입은 1970-01-01 이후의 일수 카운트입니다.unclass()가 그 숫자를 보여 줍니다.as.Date("2026-08-07")은 ISO를 곧바로 파싱하고, 그 외에는%코드로 된format =레시피가 필요합니다 - 그리고 파싱 실패는 조용히NA를 반환합니다.format(date, "...")은 그 반대입니다: 같은 코드로 표시용 문자열을 만듭니다.- 뺄셈은 difftime을 줍니다 -
units =를 명시하고, 계산 전에as.numeric()을 쓰세요.+ n은 일수를 더하며, 월 단위에는seq(by = "month")를 사용합니다. weekdays(),months(), 그리고as.integer(format(...))관용구가 구성 요소를 벡터화된 방식으로 뽑아냅니다.- 온전한 날에는
Date, 타임스탬프에는 (명시적tz와 함께)POSIXct를 쓰고, lubridate가 둘 다 더 친절하게 만들어 줍니다.
다음 주제: R이 여러분에게 소리칠 때 할 일 - 오류 메시지를 읽고 체계적으로 디버깅하기.
자주 묻는 질문
R에서 문자열을 날짜로 어떻게 변환하나요?
as.Date()를 사용합니다. 문자열이 ISO 형식이면 그냥 됩니다: as.Date("2026-08-07"). 다른 배치라면 % 코드로 만든 format = 레시피가 필요합니다: as.Date("07/08/2026", format = "%d/%m/%Y"). 파싱에 실패하면 오류가 아니라 NA를 반환하므로 결과를 확인하세요.
R에서 오늘 날짜는 어떻게 얻나요?
Sys.Date()가 오늘을 Date 객체로 반환하고, Sys.time()은 현재 날짜·시각을 POSIXct로 반환합니다. 둘 다 컴퓨터의 시계와 시간대 설정에서 옵니다.
R에서 두 날짜의 차이는 어떻게 계산하나요?
빼면 됩니다: as.Date("2026-08-07") - as.Date("2026-01-01")은 218일이라는 difftime을 줍니다. 그 숫자를 계산에 쓰려면 as.numeric()으로 감싸고, R이 고르게 두는 대신 단위를 직접 정하려면 difftime(d1, d2, units = "weeks")를 호출하세요.
R에서 Date와 POSIXct의 차이는 무엇인가요?
Date는 온전한 날(내부적으로는 1970-01-01 이후의 일수)을 저장하며 시각이나 시간대를 전혀 모릅니다. POSIXct는 시간상의 한 순간(1970년 이후 초)을 저장하며 시간대를 인식합니다. 생일이나 마감일 같은 달력 데이터에는 Date를, 타임스탬프나 로그처럼 하루 중 시각이 중요할 때만 POSIXct를 쓰세요.