날짜처리_01 date 명령어로 두 날짜를 비교하고 날짜차를 구하기

 
  • 출처 : 유닉스 리눅스 쉘스크립트 예제사전_한빛미디어

명령어: date, expr
키워드: 날짜, UNIX 시간, 에포크 초
사용처: 시간 문자열 둘을 비교해서 몇일 차이인지 계산하고 싶을 때


실행예제

$ ./date-epoch.sh
day1(2012/04/01 10:49:41): 1333244981
day2(2012/03/30 08:31:52): 1333063912
day interval:
2

스크립트

#!/bin/sh
 
# 비교할 두 날짜를 변수로 정의
day1="2012/04/01 10:49:41"  #----------------------- 1
day2="2012/03/30 08:31:52"  #----------------------- 1

# 날짜에서 epoch 초를 얻으려면 +%s 사용(리눅스)
# -d 옵션은 FreeBSD/Mac에서 사용 불가 
day1_epoch=$(date -d "$day1" '+%s')  #-------------- 2
day2_epoch=$(date -d "$day2" '+%s')  #-------------- 2

echo "day1($day1): $day1_epoch"  #------------------ 3
echo "day2($day2): $day2_epoch"  #------------------ 3

# 두 날짜의 epoch 초끼리 뺀 값을
# 하루 = 24기간 = 1440분 = 86400초로 나누면 날짜 계산 가능
echo "day interval: "  #---------------------------- 4
expr \( $day1_epoch - $day2_epoch \) / 86400  #----- 4
echo $day_interval  #------------------------------- 4

   

해설

이 스크립트는 문자열로 된 두 날자의 차를 유닉스 시간으로 변환 후 몇일 차이가 나는지 계산해서 셸 변수 day_interval에 대입합니다. 예를 들어 신청이로부터 5일 잇아 지난 사용자를 대상으로 어떤 메일을 보내는 프로그램에는 ‘day_interval이 5 이상이라면 메일을 보내도록 스크립트를 실행한다’ 같은 조건이 있을 수 있습니다.

유닉스 서버를 운용하다보면 다음과 같은 현재 날짜를 처리하는 일이 자주 있습니다.

  • 로그 파일명에서 오래된 파일 판정
  • 월별 처리 날짜 판정
  • 접수일시/해제일시 등록 등
  • 파일 타임스탬프 판단

이럴 때 유닉스는 일반적으로 ‘유닉스 시간’이라는 값으로 날짜를 처리합니다. 이것은 UNIX 에포크(epoch)라고 부르는 1970년 1월 1일 0시 0분 0초부터 경과한 초를 나타내는 값으로 에포크 초라고도 부릅니다. 예를 들어, 2000년 1월 1일 0시 0분 0초는 유닉스 시간으로 946652400입니다.

시간을 컴퓨터에서 다룰 때면 년월일 같은 서식이 국가와 문화마다 달라서 문제가 생ㄱ비니다. 한국에서는 ‘2013년 12월 15일’ 이라고 쓰지만 영어권에서는 ‘Dec 15 2013’이라고 씁니다. 환경에 따라 날짜 처리를 재작성하면 불편합니다. 이때 유닉스 시간을 사용하면 나라와 문화권 구분 없이 동일한 표기가 가능합니다. 값도 단순한 정수값이므로 유닉스 환경에서 널리 사용됩니다.

예제에서는 1에서 비교할 두 날짜를 변수에 대입하고, 2에서 date 명령어 출력 형식을 ‘+%s’로 지정해서 해당 날짜의 유닉스 시간을 산출합니다. 이때 -d 옵션을 사용하는데 리눅스에서만 사용할 수 있습니다. FreeBSD나 Mac에서는 주의사항을 참조하기 바랍니다.

3에서 문자열 표기 날짜와 유닉스 시간 표기를 echo 명령어로 출력합니다. 유닉스 시간은 펄이나 루비 같은 스크립트 언어에서도 자주 사용하므로 이런 외부 스크립트와 연계할 때는 유닉스 시간을 사용하면 좋습니다.

4에서 day1과 day2의 날짜 차이를 계산합니다. 유닉스 시간은 단순히 초를 정수값으로 나타낸 것이므로 expr 명령어로 뺄셈만 하면 시간 차이를 계산할 수 있습니다. 이 값을 1일 = 24시간 = 1440분 = 86400초로 나누면 몇일 차이가 나는지 나옵니다.

   

주의사항

  • 이 예제에서 day2가 미래의 날짜면 음수값이 표시됩니다. 따라서 만약 절대값으로 표시하고 싶다면 어느 쪽이 미래인지(어느 쪽 유닉스 시간이 큰지) 판단해서 큰 쪽에서 작은 쪽을 빼야 합니다.
    day1(2012/03/30 08:31:52): 1333063912
    day2(2012/04/01 10:49:41): 1333244981
    day interval:
    -2
    
  • FreeBSD나 Mac 같은 BSD 계열 유닉스 date 명령어와 리눅스 date 명령어는 옵션에 큰 차이가 있습니다. 스크립트 2에서 사용하는 -d 옵션은 리눅스 전용입니다. 따라서 FreeBSD나 Mac에서는 날짜 설정이 아니라 날짜 표시를 하는 -j 옵션과 포맷 지정 -f 옵션으로 2부분을 수정해야 합니다.
    # 날짜에서 epoch 초를 얻기 위해 +%s 사용(BSD/Mac)
    day1_epoch=$(date -j -f "%Y/%m%d %H:%M:%S" "$day1" '+%s')
    day2_epoch=$(date -j -f "%Y/%m%d %H:%M:%S" "$day2" '+%s')
    
  • 유닉스 시간은 다루기 편하므로 시각을 다루는 데이터베이스에서도 자주 사용합니다. MySQL은 유닉스 시간에서 날짜 문자열을 변환하는 FROM_UNIXTIME()이라는 함수가 표준으로 사용됩니다.
    mysql> SELETE FROM_UNIXTIME(1333063912);
    +---------------------------+
    | FROM_UNIXTIME(1333063912) |
    +---------------------------+
    | 2012-03-30 08:31:52       |
    +---------------------------+