파이썬으로 코딩을 하다 보면 날짜, 시간에 관련 처리를 할 일이 많다. 이때 사용하게 되는것이 datetime 모듈이다. 시간을 처리하는 다른 모듈은 time 모듈이 있는데, time 모듈은 좀 더 근본적으로 시간에 관한 여러 가지 연산을 지원하고, datetime 은 기본적인 연산들은 지원하지만 주로 시간이나 날짜를 사용자에게 보여지는 형태로 포매팅하는데 중점을 둔 모듈이라고 한다. Datetime 모듈의 하위 클래스는 datetime.date datetime.time datetime.datetime datetime.timedelta datetime.tzinfo datetime.timezone 이 있다. 시간대 적용은 pytz 모듈로 하는것이 편하므로 이 중 tzinfo 와 timezone 은 생략하고 나머지 모듈에 대해서 정리해 본다. 더 자세한 내용은 공식 문서 참조. #1. datetime.date 이 클래스의 객체는 년월일 정보를 담고 있는 객체이다. 특정한 날짜의 객체를 만들려면 년, 월, 일을 전달해주면 되고, 오늘 날짜를 얻으려면 today() 를 이용한다. today() 에서는 현재 작업중인 시스템의 로컬 날짜가 반환되게 된다. date 객체에서 년, 월, 일 을 추출하려면 객체의 year, month, day 속성을 가져오면 된다. 와 같이 한다. 이때 반환되는 값은 int 타입이다. date.weekday() 는 요일 정보를 숫자로 반환해준다. 월요일이 0이고 순서대로 올라가 일요일이 6이다. date.isoweekday() 도 같은 기능인데, 차이점은 월요일이 1이고 일요일이 7이다. 년월일 정보가 YYYY-MM-DD 식으로 포매팅된 것을 ISO 포맷이라고 하는데 이런 string을 date 객체로 변환하려면 과 같이 하면 된다. 이때 월/일 숫자가 한자리수인 경우 앞에 0 이 붙어있지 않으면 제대로 처리가 안된다. (즉 2020-01-01 은 되지만 2020-1-1 은 처리가 안됨) 반대로 날짜 객체를 ISO 포맷의 문자열로 반환하려면 와 같이 할 수 있다. date.replace()를 이용하면 객체의 년월일 정보를 바꿀수 있다.
date.strftime() 메서드를 이용해 객체를 다양한 방법으로 문자열로 변환할 수 있다. strftime() 포매팅 관련 옵션은 포스트 하단 참조. #2. datetime.time 이 클래스의 객체는 특정 날짜와 무관한 시간 정보를 담고 있는 객체이다. 특정 시간의 객체를 생성하려면 인자를 직접 전달해주면 된다. 인자를 따로 전달하지 않으면 디폴트 값이 전달된다. hour는 0~23, minute은 0~59, second는 0~59, microsecond는 0~999,999 까지의 정수 값이 허용된다. fold는 서머타임 등 물리적으로 같은 시간에 대해 2가지 다른 시간이 표시될때 조정해주는 값으로 0 또는 1이 사용되는데, 보통은 기본값 0으로 두면 되는듯하다. tzinfo는 시간대 정보를 전달해 준다. 시간대는 별도의 pytz 모듈을 이용해서 지정해주면 편하다. pytz는 따로 설치를 해주어야 한다. pytz에서 지원하는 모든 시간대 정보는 로 확인할 수 있다. 파이썬 날짜/시간 관련 개체는 크게 naive와 aware 객체로 구분할수 있다. 간단히 말하면 시간대 정보를 담고 있으면 aware, 시간대 정보가 담겨있지 않으면 naive 객체이다. 그런데 naive 객체는 시간대 정보가 없어 혼란을 초래할 수 있으므로 가능하면 모든 객체를 시간대를 지정해 aware 객체로 만들어 주는것이 좋다. 그리고 특별한 경우가 아니면 모든 시간대는 UTC 로 통일하고, 특정 지역 사용자에게 보여질때 해당 시간대로 변환해서 보여주는것이 좋다고 한다. 어떤 time 객체의 시, 분, 초, 마이크로초 및 시간대 정보는 각 속성을 입력하면 확인할 수 있다. 여기서 나머지는 int type으로 숫자를 반환하고, tzinfo는 pytz.timezone 객체를 반환한다. 만약 시간대의 이름을 문자열로 얻고싶다면 tzname() 메서드를 호출하면 된다. date 객체에서와 마찬가지로 time.replace()를 이용하면 time 객체의 시간 정보를 바꿀 수 있다. time.isoformat() 메서드는 시간 정보를 ISO 포맷의 문자열로 출력해준다. 다만 날짜 데이터와 달리 시간 데이터의 ISO 포맷은 읽기에 불편해 실제 사용할 일이 많지 않을것같다. time.strftime() 은 date에서와 마찬가지로 다양한 옵션으로 사용자에게 읽기 편한 문자열 출력을 제공한다. 옵션은 역시 포스트 하단의 표 참조. #3. datetime.datetime 이 클래스의 객체는 날짜와 시간 정보를 모두 담고 있는 객체이다. 객체를 생성하려면 으로 생성하면 된다. 생성된 객체의 년월일, 시분초 등 정보는 위에서와 같은 방법으로 확인할 수 있다. UTC 기준으로 현재 시간을 담은 객체를 생성하려면 아래와 같이 한다. 현재 시각을 생성하는 메서드는 datetime.now() datetime.today() datetime.utcnow() 가 있는데, 아래의 2가지는 naive datetime 객체를 생성하므로 가능하면 아래 2가지보다 now()를 사용하는것이 권장되고, now()를 쓸 때 시간대 정보를 전달해서 aware 객체를 생성하는 것이 좋다. date와 time 객체가 따로 존재한다면 datetime.combine() 을 이용해서 결합해줄 수 있다. 이때 별도로 시간대 정보를 전달해줄 수 있다. 또 datetime 객체에서 날짜 정보를 따로 객체로 만들려면 date()을 이용한다. 시간 객체는 time() 혹은 timetz() 이용하면 되는데, 후자는 시간대 정보를 포함하고 있다. date나 time 객체에서와 동일한 방법으로 datetime.replace() 를 이용하면 날짜와 시간 정보를 수정할 수 있다. datetime.weekday()와 datetime.isoweekday()는 date 객체에서와 동일하다. datetime.strptime() 을 이용하면 strftime() 에서 사용하는 포매팅 옵션을 이용해서 datetime 객체를 만들어줄 수 있다. date나 time 과 동일하게 datetime.strftime() 을 이용해서 다양한 포맷으로 출력할 수 있다. 옵션은 포스트 하단 참조, #4. datetime.timedelta 이 클래스의 객체는 두 날짜 혹은 시간의 차이를 나타내는 객체이다. 객체를 생성하려면 days, seconds, microseconds, milliseconds, minutes, hours, weeks 인자를 전달해주면 된다. 디폴트값은 0 이다. 실제 객체에 저장되는것은 days, seconds와 microseconds 이고, 나머지 인자들은 내부적으로 계산이 이루어져 변환된다. timedelta 개체끼리는 사칙연산과 크기 비교, 절대값 산출 등 기본적인 수학적 처리가 제공된다. 실제로는 timedelta 에 인자를 직접 전달하기보다는 두 datetime 객체의 차이를 구하는데 이용될 것이다. datetime 객체의 차이를 구하면 자동으로 timedelta 객체가 반환된다. datetime 객체끼리 더하는 연산은 지원되지 않아 TypeError 가 발생한다. 위의 예처럼 과거 날짜에서 현재 날짜를 빼는 연산도 가능하다. 그러나 과거 날짜에서 현재 날짜를 빼는것이 논리적으로 어떤 의미인지 명확하지 않고 계산도 복잡해지므로, 항상 현재에 더 가까운 날짜에서 오래된 날짜를 빼는것이 좋을 것같다. datetime 객체에 timedelta 객체를 더하거나 빼서 특정 시간 이후나 이전의 시간을 구하는것도 가능하다. 이상으로 datetime 모듈 관련 주로 많이 쓰게 되는 내용들을 정리해 보았다. 아래는 strftime() 포매팅 관련 옵션. %a 현재 로케일에 따른 요일 이름 약자 Sun, Mon, …, Sat (en_US); So, Mo, …, Sa (de_DE) %A 현재 로케일에 따른 요일 이름 Sunday, Monday, …, Saturday (en_US); Sonntag, Montag, …, Samstag (de_DE) %w 10진수로 표현된 요일 번호 (일요일이 0, 토요일이 6임) 0, 1, …, 6 %d 10진수로 표현된 날짜 (한자리수인 경우 0이 앞에 붙음) 01, 02, …, 31 %b 현재 로케일에 따른 월 이름 약자 Jan, Feb, …, Dec (en_US); Jan, Feb, …, Dez (de_DE) %B 현재 로케일에 따른 월 이름 January, February, …, December (en_US); Januar, Februar, …, Dezember (de_DE) %m 10진수로 표현된 월 (한자리수인 경우 0이 앞에 붙음) 01, 02, …, 12 %y 앞 2자리수룰 제외하고 10진수로 표현된 년도 (한자리수인 경우 0이 앞에 붙음) 00, 01, …, 99 %Y 10진수로 표현된 년도 0001, 0002, …, 2013, 2014, …, 9998, 9999 %H 10진수로 표현된 시간 (24시간제) 00, 01, …, 23 %I 10진수로 표현된 시간 (12시간제) 01, 02, …, 12 %p 현재 로케일에 따른 오전, 오후 표시 AM, PM (en_US); am, pm (de_DE) %M 10진수로 표현된 분 (한자리수인 경우 0이 앞에 붙음) 00, 01, …, 59 %S 00, 01, …, 59 %f 10진수로 표현된 마이크로초 (자리수에 따라 0이 앞에 붙음) 000000, 000001, …, 999999 %Z 시간대 (시간대 정보가 없는 naive 객체인 경우 None). (empty), UTC, EST, CST %j 10진수로 표현된 년중 날짜 (1월1일이 001 임) 001, 002, …, 366 %U 10진수로 표현된 년중 주수 (일요일을 한 주의 첫날로 정함. 처음으로 일요일이 포함된 주가 01주, 일요일이 포함되지 않은 날짜들이 속한 그 전주는 00주임) 00, 01, …, 53 %W 10진수로 표현된 년중 주수 (월요일을 한 주의 첫날로 정함. 처음으로 일요일이 포함된 주가 01주, 월요일이 포함되지 않은 날짜들이 속한 그 전주는 00주임) 00, 01, …, 53 %c 현재 로케일 설정에 따라 요일과 년월일, 시간을 출력 Tue Aug 16 21:30:00 1988 (en_US); Di 16 Aug 21:30:00 1988 (de_DE) %x 현재 로케일 설정에 따라 년월일을 출력 08/16/88 (None); 08/16/1988 (en_US); 16.08.1988 (de_DE) %X 현재 로케일 설정에 따라 시간을 출력 21:30:00 (en_US); 21:30:00 (de_DE)