R에서 날짜와 시간

2020-07-20

날짜와 시간

R에서 날짜와 시간 : 처음으로 살펴보기

우리는 다음과 같은 문자열을 보면 어떤 생각을 하나요?

“2020-12-25 00:00:01 KST”

KST가 조금 걸리지만, 2020년 12월 25일 1초를 생각할 것입니다. 문자열 임에도 위의 표현을 보고 시간을 떠올리는 것은 당연할 것입니다.(날짜와 시간을 표현하는 국제 표준은 ISO 86011로 이를 따르는 문자열을 사용했으며 해당 표준에 시간대를 표시하는 문자열이 들어가 있어서 우리나라 표준시임을 알리는 KST를 뒤에 붙혔습니다.)

R에서 날짜와 시간은 기본적으로 문자로 표현할 수 있습니다.

하지만, 아직은 컴퓨터의 입장에서는 단지 문자열일 뿐 날짜형의 자료는 아닙니다.

이제 R에서 주어진 데이터가 날짜와 시간을 나타내는 것임을 알 수 있도록 해봅시다.

날짜와 시간은 R에서 서로 다른 유형으로 저장됩니다.

날짜만을 나타낼 때는 Date 클래스로 저장되며, 함수 as.Date()로 문자열로 작성한 날짜를 Date 클래스로 변환합니다.

d1 <- as.Date("1970-01-01")
class( d1 )
## [1] "Date"
d1
## [1] "1970-01-01"

시간은 POSIXct와 POSIXlt 클래스로 저장되며 각각 as.POSIXct(), as.POSIXlt() 함수를 이용해서 작성합니다.

R 함수 Sys.time()은 현재 시간을 반환하는 함수로 시간 정보를 반환합니다.

t1 <- Sys.time()
t1
## [1] "2020-07-29 21:34:13 KST"

시간을 이야기하면서 조금 어려운 용어인 POSIX이 등장했습니다. POSIX은 Portable Operating System Interface의 약자로 IEEE가 제정한 유닉스 계열의 운영체제가 사용하는 API 규격으로 서로 다른 운영체제들간의 호환성을 높이는 표준으로 작동합니다.2 이와 같은 표준은 서로 다른 운영체제라도 지원을 한다면 다른 운영체제로의 전환이 쉽게 이뤄져 그 사용성을 높힐 수 있습니다.

날짜와 시간은 아주 다양한 컴퓨터들에서 사용하고 서로간의 약속으로 만일 그 값들이 서로 다르다면 큰 혼란이 생길것입니다. 그래서 많은 프로그래밍 환경에서는 날짜와 시간을 저장하는 표준을 따르게 하여 이런 혼란을 예방합니다. POSIX에서 제안하는 시간 정보 저장 유형은 단일 문자열로 저장하는 ct(Continuous Time)과 날짜와 시간을 구성하는 ‘년/월/일 시:분:초’ 등을 개별 리스트로 저장하는 lt(List Time) 두 가지가 있습니다.

위의 예에서 t1의 값 2020-07-29 21:34:13이 POSIXct 형태의 시간 표현입니다. 이 값은 다음과 같이 숫자로 변경해서 살펴보면 1970년 1월 1일 00:00:00을 기준으로 초단위로 1씩 증가하는 값입니다. (이를 UNIX 시간(time)이라고 하며 32비트를 그 크기로 하여 2038년 1월 19일 그 값이 종료됩니다.3)

t1
## [1] "2020-07-29 21:34:13 KST"
class( t1 )
## [1] "POSIXct" "POSIXt"
as.numeric( t1 )
## [1] 1596026054

POSIXlt 형태의 시간을 살펴봅시다.

  • 현재 시간을 POSIXlt로 변환한 후 객체 유형을 출력해 보면 POSIXlt 이다.
  • attributes() 함수를 이용하여 속성들을 출력해 보면, names, class, tzone 의 세 개의 속성을 갖고 있다.
  • POSIXlt는 list 로 Vector로 변환하여 시간 정보를 그 요소에 따라 구분한 것을 확인할 수 있습니다. (names 속성이 있는 list를 해체하면, 이름이 있는 Vector가 됩니다)

POSIXlt가 필요한 이유는 각 국가별로 년월일 표시를 일월년, 월일년 등 다양하게 하므로 하나의 시간을 나타내는 문자보다는 이와같이 시간을 구성하는 각 구성요소를 별도로 저장하여 각 국가에 맞게 출력하는 것이 타당하기 때문입니다.

time.list <- as.POSIXlt( t1 )
class( time.list )
## [1] "POSIXlt" "POSIXt"
attributes( time.list )
## $names
##  [1] "sec"    "min"    "hour"   "mday"   "mon"    "year"   "wday"   "yday"  
##  [9] "isdst"  "zone"   "gmtoff"
## 
## $class
## [1] "POSIXlt" "POSIXt" 
## 
## $tzone
## [1] ""    "KST" "KDT"
unlist( time.list )
##                sec                min               hour               mday 
## "13.9482669830322"               "34"               "21"               "29" 
##                mon               year               wday               yday 
##                "6"              "120"                "3"              "210" 
##              isdst               zone             gmtoff 
##                "0"              "KST"            "32400"

위의 정보에 특이한 몇가지를 보겠습니다.

  • mday
    각 월의 일
  • zone
    전 세계의 시간대를 구분하는 timezone으로 본 문서에서 다루지 않고 어느 지역의 기준 시간인지를 표현하는 정도로만 밝히겠습니다.
  • isdst
    일광절약시간 적용여부. 즉, Summer Time 적용여부입니다.
  • wday
    요일을 나타내는 것으로 일요일이 0 이고 토요일이 6입니다.
  • yday
    1년중 날 수. 즉, 1년중 몇 번째 날인지를 표현하며 1월 1일이 0입니다.
  • gmtoff
    자오선을 중심으로 양수 값을 가질 경우 오른쪽에 위치한 지역으로 초단위입니다(알 수 없을 경우 0). 영국 런던을 기점으로 웰링턴을 종점으로 하는 시간의 평균시(GMT, Greenwich Mean Time)는 1884년 국제 자오선 회의에서 시작한 세계 시간 표시 규격으로 경도가 15도 차이가 날때 시간이 1시간 차이가 난다는 시차에 대한 표준입니다. gmtoff는 GMT를 중심으로 몇 초를 더하고 빼서 각 지역의 시간을 정하는 것입니다. (우리나라의 경우 GMT +9시간으로 gmtoff로는 32400 : 9시간은 32400초)

이후 POSIXct, POSIXlt를 함께 이야기할때 POSIXt 라고 부르겠습니다.

임의의 문자열로 부터 시간 정보 추출하기

각 국가별로 그들의 문화에 따라 날짜를 나타내는 것이 다릅니다. 또한 “2020년 1월 1일”, “2020-01-01”, “2020/01/01”과 같이 동일한 날짜에 대해 년월일 구분기호를 달리하는 경우도 많습니다. 이럴경우 어떻게 날짜 정보를 제대로 가져올지 알아봅시다.

우선 기존에 저장되어 있는 날짜 표현은 문자라고 가정하겠습니다. 다음은 2020년 1월 3일에 대한 서로 다른 표현입니다.

dt1 <- "2020년 01월 03일 13:00:11"
dt2 <- "01/03/2020"
dt3 <- "2020 01 03"

strptime() 은 R의 기본 함수로 문자로 저장된 날짜와 시간을 POSIXlt 클래스로 변환하는 함수입니다.

strptime() 의 인수 format은 날짜와 시간이 저장된 형태를 나타내는 문자열로 날짜와 시간을 구성하는 요소들을 표현하는 알파벳을 기호 %와 함께 나타냅니다. 아래의 목록은 자주 사용하는 년월일 시분초에 대한 것입니다.4

형식 설명
%Y 네 자릿수 년도
%m 두 자릿수 월
%d 두 자릿수 일
%w 요일(0-6, 일요일이 0)
%H 두 자릿수 시간(00-23)
%M 두 자릿수 분 (00-59)
%S 두 자릿수 초

위에 있는 날짜 시간 문자열을 POSIXt로 변환해 보겠습니다. 기존 문자열의 년월일 시분초를 구분하는 문자열과 위치를 위의 형식에 맞춥니다.

dt1
## [1] "2020년 01월 03일 13:00:11"
sdt1 <- strptime(dt1, format="%Y년 %m월 %d일 %H:%M:%S")
class(sdt1)
## [1] "POSIXlt" "POSIXt"
sdt1
## [1] "2020-01-03 13:00:11 KST"
strptime(dt2, format="%m/%d/%Y")
## [1] "2020-01-03 KST"
strptime(dt3, format="%Y %m %d")
## [1] "2020-01-03 KST"

R에서 날짜와 시간 : 차이 계산

날짜간의 차이를 구하는 것은 생각보다 어려운 면이 있습니다. 한 달이 모두 동일한 일수를 갖지 않고 윤년이 있으면 2월의 일수도 변하는 등 현재 사용하는 날짜 표현이 일정하지 않기 때문입니다. 이를 위해 날짜간의 차이를 구하는 것 역시 조금 다르게 R에서는 저장합니다.

다음의 코드를 봅시다.

우선 날짜입니다.

  • t2에는 2020년 12월 25일을 Date 클래스로 변환한 값이 있습니다.
  • t3에는 2019년 6월 30일을 Date 클래스로 변환한 값이 있습니다.
  • 두 개의 서로 다른 Date 클래스는 빼기 연산자 ‘-’로 계산할 수 있습니다. 이를 구하고 변수 diff 에 저장합니다.
  • 날짜의 차이를 위한 클래스는 difftime 입니다.
  • 이를 출력해서 살펴보면, 일자(days)를 기준으로 며칠의 차이가 나는지 보여주고 있습니다.
t2 <- as.Date("2020-12-25")
t3 <- as.Date("2019-06-30")

diff <- t2 - t3
class( diff )
## [1] "difftime"
diff
## Time difference of 544 days

다음을 살펴보면, 시간에 대해서도 마찬가지임을 확인할 수 있습니다.

t4 <- as.POSIXct("2020-12-25 00:00:00")
t5 <- as.POSIXlt("2019-06-30 12:00:00")

t4 - t5
## Time difference of 543.5 days

만일 다음과 같이 difftime() 함수를 사용한다면, 차이 기준을 일수가 아닌 다양한 형태로 구할 수 있으며, difftime 클래스는 as.difftime()으로 생성할 수 있습니다.

  • difftime() 함수는 units 인수를 통해 초, 분, 시간, 일(days), 주로 그 차이를 보여줍니다. (애석하게도 월, 년은 없습니다.)

  • as.difftime()을 사용할 때 units 인수를 이용하여 주어진 값의 단위를 알려주어 사용합니다. (units 인수를 사용하지 않을시에는 에러가 발생합니다.)

difftime(t4, t5, units="secs")
## Time difference of 46958400 secs
difftime(t4, t5, units="mins")
## Time difference of 782640 mins
difftime(t4, t5, units="hours")
## Time difference of 13044 hours
difftime(t4, t5, units="weeks")
## Time difference of 77.64286 weeks
as.difftime(30, units="hours")
## Time difference of 30 hours
as.difftime(30)
## Error in as.difftime(30): need explicit units for numeric conversion

두 시간의 차이에 대한 비교가 가능하여 다음과 같이 일주일 이내 여부 등을 구할 수 있습니다. 비교를 위한 두 항 모두 difftime 클래스여야 하지만 한쪽의 항이 difftime 클래스이면 다른 쪽 항이 일반 숫자여도 비교가 가능합니다.

t6 <- as.Date("2020-01-01")
t7 <- as.Date("2020-01-09")

ifelse( difftime(t7, t6, units="weeks") >= as.difftime(1, units="weeks"), "1주 이상 차이가 납니다.", "1주 이내입니다.")
## [1] "1주 이상 차이가 납니다."
ifelse( difftime(t7, t6, units="weeks") >= 1, "1주 이상 차이가 납니다.", "1주 이내입니다.")
## [1] "1주 이상 차이가 납니다."

패키지 lubridate

RStudio 팀에서 날짜와 시간을 위해 배포하는 패키지 lubridate는 날짜와 시간과 관련한 다양한 함수를 제공하고 있어 보다 편리하게 사용할 수 있도록 도와주고 있습니다. (참고 : lubridate Cheatsheet)

lubridate 는 tidyverse와 함께 설치되지 않으므로 install.packages("lubridate")와 같이 설치할 수 있으며, devtools패키지의 함수 install_github()를 이용하여 devtools::install_github("tidyverse/lubridate")와 같이 설치할 수 있습니다. (원활한 사용을 위해 library(lubridate)를 실행합니다.)

library(tidyverse)
## -- Attaching packages ---------------------------------------------- tidyverse 1.3.0 --
## √ ggplot2 3.3.2     √ purrr   0.3.4
## √ tibble  3.0.1     √ dplyr   1.0.0
## √ tidyr   1.1.0     √ stringr 1.4.0
## √ readr   1.3.1     √ forcats 0.5.0
## -- Conflicts ------------------------------------------------- tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()
# install.packages("lubridate")
# devtools::install_github("tidyverse/lubridate")
library(lubridate)
## 
## 다음의 패키지를 부착합니다: 'lubridate'
## The following objects are masked from 'package:base':
## 
##     date, intersect, setdiff, union

날짜와 시간 자료 다루기

날짜 구하기

문자열로 저장된 날짜 정보를 읽어와 현재 Date 클래스 혹은 POSIXct 클래스로 변환하는 함수를 제공합니다.

함수명은 년도를 위해 y, 월(달)을 위해 m, 날짜를 위해 d을 이용하여 다음과 같은 함수를 제공하고 있습니다.

함수명 함수사용 출력
ymd() ymd(“2020-01-03”) 2020-01-01
mdy() mdy(“01-03-2020”) 2020-01-03
dmy() dmy(“03-01-2020”) 2020-01-03

날짜와 시간 구하기

ymd_hms(), ymd_hm() 등의 함수를 이용하여 시간 정보를 출력합니다.

  • ymd_hms()는 시분초까지, ymd_hm()은 시분까지의 정보를 출력합니다.
  • 시간대를 설정하기 위해서는 인수 tz를 사용하거나 with_tz() 함수를 이용하여 시간대를 지정합니다. (OlsonNames() 함수는 시간대 문자열을 출력해 줍니다.)
lt1 <- ymd_hms("2020-12-25 12:00:01")
class(lt1)
## [1] "POSIXct" "POSIXt"
lt1
## [1] "2020-12-25 12:00:01 UTC"
with_tz(lt1, "Asia/Seoul")
## [1] "2020-12-25 21:00:01 KST"
OlsonNames()[c(1:4, (length(OlsonNames())-4):length(OlsonNames())  )]
## [1] "Africa/Abidjan"     "Africa/Accra"       "Africa/Addis_Ababa"
## [4] "Africa/Algiers"     "US/Samoa"           "UTC"               
## [7] "W-SU"               "WET"                "Zulu"

시간정보의 각 요소 구하기

lubridate는 함수 year(), month(), mday(), hour(), minute(), second() 들을 이용하여 년도, 월, 일, 시, 분, 초를 각각 추출해 줍니다.

year(lt1)
## [1] 2020
month(lt1)
## [1] 12
mday(lt1)
## [1] 25
hour(lt1)
## [1] 12
minute(lt1)
## [1] 0
second(lt1)
## [1] 1

그 외 날짜 관련하여 요일과 일년중 년수는 각각 다음과 같이 wday(), yday() 함수를 이용합니다. wday()의 경우 인수 label을 이용하여 문자열로 해당 요일을 출력할 수 있습니다. (label 인수는 앞서 월을 구하는 함수 month()에서도 사용할 수 있습니다.)

wday(lt1)
## [1] 6
wday(lt1, label=TRUE)
## [1] 금
## Levels: 일 < 월 < 화 < 수 < 목 < 금 < 토
yday(lt1)
## [1] 360

이렇게 어떤 한 시점을 표현하는 것을 lubridate에서는 instant라고 하며, is.instant() 를 통해 instant여부를 확인할 수 있습니다. 이는 다음에 알아볼 시간 간격과 구분되는 자료의 형태입니다.

시간 간격

lubridate에서는 두 시점간의 간격에 대해 다음의 세가지 클래스를 지원합니다. R의 기본함수에서도 구할 수 있으나, 다음 중 intervals에 대해 조금 더 알아봅시다.

  • durations
    두 시점간의 정확한 초수 차이 (절대시간)
  • periods
    일상 생활에서 사용하는 개월, 주, 년 등의 기간 (상대시간)
  • intervals
    시작과 끝 시간 정보를 저장하고 있어 다양한 활용 가능하며, durations와 periods로 변환 가능

Durations

두 시간간의 차이를 나타내는 초로 나타내는 클래스

w2002 <- today() - ymd(20020531)
class( w2002 )
## [1] "difftime"
d.w2002 <- as.duration( w2002 )
class( d.w2002 )
## [1] "Duration"
## attr(,"package")
## [1] "lubridate"
str( d.w2002 )
## Formal class 'Duration' [package "lubridate"] with 1 slot
##   ..@ .Data: num 5.73e+08
d.w2002
## [1] "573177600s (~18.16 years)"
d.w2002@.Data
## [1] 573177600

주어진 값별로 얼마만큼의 duration을 갖는지 구하는 함수로 다음과 같이 dxxx() 계열의 함수로 주어진 시간 단위별 초수를 구해줍니다.

dseconds(10)
## [1] "10s"
class( dseconds(10) )
## [1] "Duration"
## attr(,"package")
## [1] "lubridate"
dminutes(10)
## [1] "600s (~10 minutes)"
dhours( c(6, 12, 18, 24) )
## [1] "21600s (~6 hours)"  "43200s (~12 hours)" "64800s (~18 hours)"
## [4] "86400s (~1 days)"
ddays( c(1, 7) )
## [1] "86400s (~1 days)"   "604800s (~1 weeks)"
dweeks( 4 )
## [1] "2419200s (~4 weeks)"
dyears( 1 )
## [1] "31557600s (~1 years)"

또한 +와 *을 이용한 계산을 수행할 수 있습니다.

2 * dweeks(1)
## [1] "1209600s (~2 weeks)"
dyears(1) + dweeks(26) + dhours(12)
## [1] "47325600s (~1.5 years)"

마지막으로 특정일을 기준으로 +와 -연산자를 이용한 계산을 수행할 수 있습니다.

today() # 오늘을 구하는 함수
## [1] "2020-07-29"
today() + ddays(1) # 내일
## [1] "2020-07-30"
today() - dyears(1) # 1년 전
## [1] "2019-07-29 18:00:00 UTC"

Periods

periods는 사람들에게 조금 더 친숙한 방법으로 lubridate에서는 duration 앞에 d가 붙는 것을 뺀 함수를 사용합니다. (뒤에 s가 붙는 것에 유의)

seconds(10)
## [1] "10S"
class( seconds(10) )
## [1] "Period"
## attr(,"package")
## [1] "lubridate"
minutes(10)
## [1] "10M 0S"
hours( c(6, 12, 18, 24) )
## [1] "6H 0M 0S"  "12H 0M 0S" "18H 0M 0S" "24H 0M 0S"
days( c(1, 7) )
## [1] "1d 0H 0M 0S" "7d 0H 0M 0S"
weeks( 4 )
## [1] "28d 0H 0M 0S"
months( today() )
## [1] "7월"
years( 1 )
## [1] "1y 0m 0d 0H 0M 0S"

Intervals

이제 조금 더 막강한 intervals에 대해 알아봅시다. 먼저 다음과 같이 숙박업소의 고객별 투숙정보가 있다고 생각해 봅시다.5

customerID <- c("202001-23", "202001-25")
check_in <- c("2020-01-21 13:42:32", "2020-01-24 19:13:09")
check_out <- c("2020-01-25 10:18:14", "2020-01-26 08:42:51")

customers <- data.frame(customerID, check_in, check_out, stringsAsFactors = FALSE)

cust_working <- customers %>%
  mutate(check_in = ymd_hms(check_in)) %>%
  mutate(check_out = ymd_hms(check_out)) %>%
  as_tibble()

cust_working
## # A tibble: 2 x 3
##   customerID check_in            check_out          
##   <chr>      <dttm>              <dttm>             
## 1 202001-23  2020-01-21 13:42:32 2020-01-25 10:18:14
## 2 202001-25  2020-01-24 19:13:09 2020-01-26 08:42:51

각 투숙객별 투숙기간을 확인해 봅시다. 투숙기간은 체크아웃 날짜와 체크인 날짜사이의 기간으로 lubridate에서는 함수 interval()과 연산자 %--%을 통해 interval 객체를 만듭니다.

cust_working %>%
  mutate(stay_itv = interval(check_in, check_out)) %>% 
  select(customerID, stay_itv)
## # A tibble: 2 x 2
##   customerID stay_itv                                        
##   <chr>      <Interval>                                      
## 1 202001-23  2020-01-21 13:42:32 UTC--2020-01-25 10:18:14 UTC
## 2 202001-25  2020-01-24 19:13:09 UTC--2020-01-26 08:42:51 UTC
cust_working %>%
  mutate(stay_itv = check_in %--% check_out) %>% 
  select(customerID, stay_itv)
## # A tibble: 2 x 2
##   customerID stay_itv                                        
##   <chr>      <Interval>                                      
## 1 202001-23  2020-01-21 13:42:32 UTC--2020-01-25 10:18:14 UTC
## 2 202001-25  2020-01-24 19:13:09 UTC--2020-01-26 08:42:51 UTC

두가지 방법으로 interval을 생성해 보았습니다. 결과를 보시면 시작과 종료 시점이 안에 있는 것을 확인할 수 있을 것입니다. 이들을 어떻게 사용하는지 확인해 봅시다.

우선 위에서 새롭게 만든 열을 데이터로 저장합시다.

cust_working %>%
  mutate(stay_itv = interval(check_in, check_out)) %>% 
  select(customerID, stay_itv) -> cust_working

시작일과 종료일을 출력해 봅시다.

int_start(cust_working$stay_itv)
## [1] "2020-01-21 13:42:32 UTC" "2020-01-24 19:13:09 UTC"
int_end(cust_working$stay_itv)
## [1] "2020-01-25 10:18:14 UTC" "2020-01-26 08:42:51 UTC"
  • int_start()
    interval 객체의 시작시점을 알려줍니다.
  • int_end()
    interval 객체의 종료시점을 알려줍니다.

다음으로 두 interval 간의 계산을 해 봅시다.

int_overlaps(cust_working$stay_itv[1], cust_working$stay_itv[2])
## [1] TRUE
setdiff(cust_working$stay_itv[1], cust_working$stay_itv[2])
## [1] 2020-01-21 13:42:32 UTC--2020-01-24 19:13:09 UTC
intersect(cust_working$stay_itv[1], cust_working$stay_itv[2])
## [1] 2020-01-24 19:13:09 UTC--2020-01-25 10:18:14 UTC
union(cust_working$stay_itv[1], cust_working$stay_itv[2])
## [1] 2020-01-21 13:42:32 UTC--2020-01-26 08:42:51 UTC
cust_working$stay_itv[1] %within% cust_working$stay_itv[2]
## [1] FALSE
  • int_overlaps()
    두 시점간에 겹치는 부분이 있으면 TRUE를 그렇지 않으면 FALSE를 반환
  • setdiff()
    먼저 전달되는 인수에서 뒤에 전달되는 인수의 기간(interval)을 뺀 나머지, 즉 순수 첫번째 인수만 존재하는 기간
  • intersect()
    두 기간이 겹치는 기간
  • union()
    두 기간의 합집한 기간
  • %within% 연산자
    연산자 좌측항(instant 혹은 interval)이 우측항(interval 객체)에 포함되면 TRUE, 없으면 FALSE 반환. 만일 우측항이 interval 객체로 구성된 리스트일 경우 우측에 전달하는 기간들 중 하나라도 좌측항이 포함되면 TRUE 반환

구한 기간에 대해 as.duration()as.period() 함수를 이용해 각각 durations와 periods로 변환하여 원하는 형태의 기간 값을 구할 수 있습니다.

as.duration(cust_working$stay_itv)
## [1] "333342s (~3.86 days)" "134982s (~1.56 days)"
as.period(cust_working$stay_itv)
## [1] "3d 20H 35M 42S" "1d 13H 29M 42S"

또한 interval 객체와 duration 객체를 이용한 계산이 가능합니다. 즉 위의 두 명의 고객들의 머문 일수를 확인하려면 다음과 같이 수행합니다.

cust_working$stay_itv / ddays(1)
## [1] 3.858125 1.562292

위의 결과로 첫번째 고객은 3.9 일을 머물렀음을 확인할 수 있습니다. 위에서 사용한 dweeks(), dyears() 등을 함께 사용해서 확인해 보시면 좋을 것입니다.

마지막으로 정확한 다음달을 구해봅시다. 다음의 코드를 살펴봅시다.

ymd("2020-12-25") + months(1)
## [1] "2021-01-25"

정확한 날짜와 시간계산을 위한 연산자 : %m+%, %m-%

lubridate에서 제공하는 연산자인 %m+%, %m-% 은 정확한 개월단위의 연산을 위해 사용합니다. 다음의 예를 살펴보면, 2020년 1월 31일은 1월달의 마지막 날로써, 한달 후를 구해본 결과로 + 연산자와 %m+% 연산자를 실시한 결과입니다.

today()
## [1] "2020-07-29"
ymd("2020-01-31") + months(1)
## [1] NA
ymd("2020-01-31") %m+% months(1)
## [1] "2020-02-29"

+ 연산자의 경우 아마 내부적으로 “2020-02-31”을 구했을 것이고, 실제 그러한 날짜는 없으므로 NA를 반환한 반면 %m+% 연산자는 이를 고려하여 2020년의 2월중 가장 큰 날인 29일을 반환하였습니다. 이와같이 각 달의 마지막날이 서로 상이한 것을 보완하기 위해 사용합니다. 또한, 일반적인 날짜의 경우(월에 상관없이 1일부터 28일) 두 연산자 모두 현재 날짜의 일을 그대로 가져와 구합니다.

today()
## [1] "2020-07-29"
ymd("2020-02-23") + months(1)
## [1] "2020-03-23"
ymd("2020-02-23") %m+% months(1)
## [1] "2020-03-23"

짧게나마 R에서 날짜와 시간을 다루는 것과 lubridate 패키지에 대해 알아보았습니다. 궁금한 것이 있으시면 댓글 혹은 메일 주세요(잘못 기술한 것에 대한 지적은 언제나 환영합니다!)


  1. 위키피디아 - ISO 8601

  2. 위키피디아 - POSIX

  3. 위키피디아 - 유닉스 시간

  4. R 도움말

  5. 고석범 저, R과 Knitr를 활용한 데이터 연동형 문서만들기 - 빅데이터 시대의 효율적인 자료 작성 가이드, 에이콘 (2014)

R - 기초DatelubridateR

정규표현식 - 첫번째

Excel로 저장된 주민등록 인구수를 R로 읽어 tidy 데이터로 변환하기