ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Python] Tip - 지역시간은 time이 아닌 datetime으로 표현
    언어/파이썬 & 장고 2017. 1. 7. 16:28

    협정 세계시(UTC)는 시간대에 의존하지 않는 표준 시간 표현입니다. UTC는 유닉스 기원 이후로 지나간 초로 시간을 표현하는 컴퓨터에서 잘 동작합니다. 하지만 사람에게는 잘 맞지 않습니다. 사람이 사용하는 시간은 현재 있는 위치를 기준으로 합니다. 사람들은 'UTC, 15:00 - 7시'가 아니라 '정오' 혹은 '오전 8시'라고 말합니다. 프로그램에서 시간을 처리해야 한다면 사람이 이해하기 쉽게 UTC와 지역 시간 사이에서 변환해야 합니다.

    파이썬은 두 가지 시간대 변환 방법을 제공합니다. 내장 모듈 time을 사용하는 이전 방법은 치명적인 오류가 일어날 가능성이 큽니다. 내장 모듈 datetime을 사용하는 새로운 방법은 커뮤니티에서 만든 pytz 패키지의 도움을 받아 훌륭하게 동작합니다.

    datetime이 최선의 선택이고 time을 사용하지 말아야 하는 이유를 완전히 이해할 때까지 time과 datetime을 사용하는 방법을 숙지해야 합니다.

    time모듈

    내장 모듈time의 localtime 함수는 유닉스 타임스탬프(UTC)를 호스트 컴퓨터의 시간대와 일치하는 지역시간으로 변환합니다.

    from time import localtime, strftime
    
    now = 1407694710
    local_tuple = localtime(now)
    time_format = '%Y-%m-%d %H:%M:%S'
    time_str = strftime(time_format, local_tuple)
    print(time_str)
    
    # 결과
    # 2014-08-11 03-18-30


    때로는 지역 시간으로 사용자 입력을 받아서 UTC 시간으로 변환하는 것처럼 반대로 처리해야 하는 경우도 있습니다. 이럴 때는 strptime 함수로 시간 문자열을 파싱한 후에 mktime으로 지역 시간을 유닉스 타임스탬프로 변환하면 됩니다. 

    from time import localtime, strftime, mktime, strptime
    
    now = 1407694710
    local_tuple = localtime(now)
    time_format = '%Y-%m-%d %H:%M:%S'
    time_str = strftime(time_format, local_tuple)
    time_tuple = strptime(time_str, time_format)
    utc_now = mktime(time_tuple)
    print(utc_now)
    
    # 결과
    # 1407694710.0


    한 시간대의 지역 시간을 다른 시간대의 지역 시간으로 변환하려면 어떻게 해야 할까요? 예를 들어 샌프란시스코에서 뉴욕으로 이동하는 비행기를 타고 뉴욕에 도착한 후 샌프란시스코의 시간을 알고 싶다고 가정합니다.

    time, localtime, strptime 함수의 반환 값을 직접 조작해서 시간대를 변환하는 건 좋지 못한 생각입니다. 시간대는 지역 규칙에 따라 모든 시간을 변경합니다. 이 과정은 직접 처리하기엔 너무 복잡하며, 특히 전 세계 모든 도시의 비행기의 출발, 도착 시각을 처리한다면 더욱 복잡해집니다.

    많은 운영체제에서 시간대 변경을 자동으로 관리하는 설정 파일을 갖추고 있습니다. 파이썬에서는 time 모듈을 이용해 이러한 시간대를 사용할 수 있습니다. 예를 들어 다음은 태평양 연안 표준시의 샌프란시스코 시간대에서의 출발 시각을 파싱하는 코드입니다.

    from time import strftime, strptime
    
    time_format = '%Y-%m-%d %H:%M:%S'
    parse_format = '%Y-%m-%d %H:%M:%S %Z'
    depart_sfo = '2014-05-01 15:45:16 PDT'
    time_tuple = strptime(depart_sfo, parse_format)
    time_str = strftime(time_format, time_tuple)
    print(time_str)
    
    # 결과 -- 샌프란시스코에 위치한 사용자만 아래와 같이 정상적으로 동작
    # 2014-05-01 15:45:16


    PDT가 strptime 함수와 동작함을 확인했다면 컴퓨터에 알려진 다른 시간대들도 제대로 동작할 것이라고 가정할 지도 모릅니다. 하지만 다른 시간대를 사용하는 위치에서는 에러가 발생합니다.

    문제는 플랫폼에 의존적인 time 모듈의 특성입니다. 실제 동작은 내부의 C 함수가 호스트 운영체제와 어떻게 동작하느냐에 따라 결정됩니다. 이와 같은 동작 때문에 파이썬의 time 모듈의 기능을 신뢰하기 어렵습니다. time 모듈은 여러 지역 시간에 대해 일관성 있게 올바로 동작하지는 못합니다. 따라서 이런 목적으로는 time 모듈을 사용하지 말아야합니다. time을 사용해야 한다면 UTC와 호스트 컴퓨터의 지역 시간을 변환하는 목적으로만 사용해야 합니다. 다른 형태의 변환에는 datetime 모듈을 새용해야 합니다.

    datetime 모듈

    파이썬에서 시간을 표현하는 두 번째 방법은 내장 모듈 datetime의 datetime클래스를 사용하는 것입니다. time 모듈과 마찬가지로 datetime은 UTC에서의 현재 시각을 지역 시간으로 변경하는 데 사용할 수 있습니다.

    다음은 현재 시각을 UTC로 얻어와서 지역시간으로 변경하는 코드입니다.

    from datetime import datetime, timezone
    
    now = datetime(2014, 8, 10, 18, 18, 30)
    
    now_utc = now.replace(tzinfo=timezone.utc)
    now_local = now_utc.astimezone()
    print(now_local)
    
    # 결과
    # 2014-08-11 03:18:30+09:00


    datetime 모듈로도 지역 시간을 다시 UTC의 유닉스 타임스탬프로 쉽게 변경할 수도 있습니다.

    from datetime import datetime
    from time import mktime
    
    
    time_format = '%Y-%m-%d %H:%M:%S'
    time_str = '2014-08-10 11:18:30'
    now = datetime.strptime(time_str, time_format)
    time_tuple = now.timetuple()
    utc_now = mktime(time_tuple)
    print(utc_now)
    
    # 결과
    # 1407637110.0


    datetime 모듈은 time모듈과 달리 한 지역 시간을 다른 지역시간으로 신뢰성 있게 변경합니다. 하지만 tzinfo 클래스와 관련 메서드를 이용한 시간대 변환 기능만 제공합니다. 빠진 부분은 UTC이외의 시간대 정의입니다.

    이러한 허점은 pytz 모듈로 해결하고 있습니다. pytz는 필요한 모든 시간대에 대한 정의를 담은 전체 데이터베이스를 포함합니다.

    pytz를 효과적으로 사용하려면 항상 지역 시간을 UTC로 먼저 변경해야 합니다. 그러고 나서 UTC 값에 필요한 datetime연산(오프셋 지정 등)을 수행합니다. 그런 다음 마지막 단계로 지역 시간으로 변환합니다.

    예를 들어 다음은 NYC 도착 시각을 UTC datetime으로 변환하는 코드입니다.

    이런 호출 중 일부가 중복으로 보일 수 있지만 pytz를 사용할 때는 모두 필요한 호출입니다.

    from datetime import datetime
    import pytz
    
    time_format = '%Y-%m-%d %H:%M:%S'
    
    arrival_nyc = '2014-05-01 23:33:24'
    nyc_dt_naive = datetime.strptime(arrival_nyc, time_format)
    eastern = pytz.timezone('US/Eastern')
    nyc_dt = eastern.localize(nyc_dt_naive)
    utc_dt = pytz.utc.normalize(nyc_dt.astimezone(pytz.utc))
    print(utc_dt)
    
    # 결과
    # 2014-05-02 03:33:24+00:00


    UTC datetime을 얻었으니 샌프란시스코 지역 시간으로 변환해보겠습니다.

    from datetime import datetime
    import pytz
    
    time_format = '%Y-%m-%d %H:%M:%S'
    
    arrival_nyc = '2014-05-01 23:33:24'
    nyc_dt_naive = datetime.strptime(arrival_nyc, time_format)
    eastern = pytz.timezone('US/Eastern')
    nyc_dt = eastern.localize(nyc_dt_naive)
    utc_dt = pytz.utc.normalize(nyc_dt.astimezone(pytz.utc))
    
    pacific = pytz.timezone('US/Pacific')
    sf_dt = pacific.normalize(utc_dt.astimezone(pacific))
    print(sf_dt)
    
    # 결과
    # 2014-05-01 20:33:24-07:00
    
    


    datetime과 pytz를 이용하면 이런 변환이 호스트 컴퓨터에서 구동하는 운영체제와 상관없이 모든 환경에서 동일하게 동작합니다.

    요약

    서로 다른 시간대를 변환하는 데는 time 모듈을 사용하지 않기

    pytz모듈과 내장 모듈 datetime으로 서로 다른 시간대 사이에서 시간을 신뢰성 있게 변환

    항상 UTC로 시간을 표현하고 시간을 표시하기 전에 마지막 단계로 UTC 시간을 지역시간으로 변환


    댓글