티스토리 툴바


나는 매일 업무일지를 적는다. 시간까지 표시할 정도로 자세히 적는 것은 아니지만, 그날 한 일을 대략적으로 적어두면 내가 한 일에 대한 정리도 되고, 진행상황도 대략 알 수 있다. 주간보고를 할 때도 이 업무일지를 요약하면 된다. 각 주별로 파일을 따로 만들어 정리하며 양식은 다음과 같은 식이다.
업무일지 (2008-11-24 ~ 2008-11-29)

2008-11-24 (월)
  1. 한일 1
  2. 한일 2
    • 어쩌구 저쩌구
    • 어쩌구 저쩌구
  3. 회의 (w/ OOO, OOO, OOO)
    • 어쩌구 저쩌구

2008-11-25 (화)

2008-11-26 (수)

2008-11-27 (목)

2008-11-28 (금)

이렇게 계속 적다보니, 주말마다 다음주에 입력할 업무일지 양식을 만들어야 하는데 이게 날짜를 넣는 것이 여간 귀찮은 것이 아니었다. 그래서 간단하게 날짜 부분을 생성해주는 프로그램을 만들면 어떨까 생각했다. 처음에는 SQL로 작성하는 게 좋겠다는 생각이 들었다. Oracle에서라면 간단히 할 수 있었겠지만 회사에서 Oracle을 사용하는 것이 아니라 이거 하나 구하기 위해 내 PC에서 Oracle을 띄운다는 것은 너무 거하게 느껴졌다. 우리 회사에서 사용하는 MySQL을 사용해 만들어보려 했지만 아직 MySQL의 SQL에는 충분히 익숙하지 않아 쉽게 만들기 어렵겠다는 생각이 들었다.
그렇다면... 이런 간단한 프로그램을 만들때 좋은 Python을 사용해보기로 했다. 아직 Python에 충분히 익숙하지는 않지만, 지금 팀에서 사용하는 주 개발 언어가 Python이라 공부도 할겸 해서...
작성해보니 그리 복잡하지는 않았다. 프로그램을 실행한 날짜에 따라 그 다음주 업무일지 양식을 만들어준다. 프로그램을 월요일에 실행시키면 그날부터 시작하는 업무일지 양식을 만들며, 프로그램을 화요일~일요일에 돌리면 그 다음 월요일부터 시작하는 업무일지 양식을 만든다. 프로그램이 인쇄한 결과를 복사해 내가 업무정리에 사용하는 Google Docs에 붙여넣기하면 된다.
# -*- encoding: utf8 -*-
# gererates weekly report header

import datetime

def printWeeklyReportFormat(d):
    weekday = ['(월)','(화)','(수)','(목)','(금)']
    print "업무일지 (%s ~ %s)n" % (d, d+datetime.timedelta(days=4))
    oneday = datetime.timedelta(days=1)
    for i in range(5):
        print "%s %s\n" % (d, weekday[d.weekday()])
        d += oneday

if __name__ == '__main__':
    d = datetime.date.today()
    if d.weekday()<>0:
        d += datetime.timedelta(days=7-d.weekday())
    printWeeklyReportFormat(d)
이 프로그램을 만들면서 Python에서 날짜 연산을 처음 해봤다. 아직 익숙하지 않아 인터넷 문서와 Python 참조 매뉴얼을 봐가며 만들었는데, 이 코드가 충분히 Python스런 코드인지는 알 수 없다.

내친 김에 Java로도 짜보기로 했다. Python과 같은 스크립트 언어로 프로그램을 작성하는 것이 Java로 작성하는 것보다 훨씬 쉽고 코드도 짧아진다고 하는 말을 많이 들었는데, 실제로 얼마나 차이가 날지 직접 확인해보고 싶었다.
import java.text.*;
import java.util.*;

public class WeeklyReportFormat {
	public static void print(Calendar c) {
		DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd");
		String d1 = df1.format(c.getTime());
		
		StringBuffer buf = new StringBuffer();
		buf.append("업무일지 (%s ~ %s)\n\n");
		
		DateFormat df2 = new SimpleDateFormat("yyyy-MM-dd (E)");
		for(int i=0; i<5; i++) {
			buf.append(df2.format(c.getTime())+"\n\n\n");
			c.add(Calendar.DATE, 1);
		}
		c.add(Calendar.DATE, -1);
		String d2 = df1.format(c.getTime());
		System.out.printf(buf.toString(), d1, d2);
	}
	
	public static void main(String[] args) {
		Calendar cal = Calendar.getInstance();
		int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
		if(dayOfWeek!=Calendar.MONDAY) { // Calendar.Monday == 2
			cal.add(Calendar.DATE, (9-dayOfWeek)%7);
		}
		print(cal);
	}
}
코드 길이가 15줄(주석 및 주석 바로 아래 빈줄 빼면)에서 30줄로 2배 늘어났다 중괄호('}')만 있는 줄(5줄)을 제외하면 15줄과 25줄이니 Java 코드가 Python 코드에 비해 1.7배 정도 길다. 이정도면 Java보다 Python이 낫다고 할만 한 것 같다. 그리고 Java 코드를 작성하며 짜증났던 것이 있다. 바로 Calendar 클래스였는데, Calendar는 가변객체(mutable object)이기 때문에 add() 메서드를 호출하면 Calendar 객체의 속성이 변해버린다. 이것이 짜증났던 이유는 업무일지의 제목에 그 주의 첫 날과 마지막 날을 표시하는데, Calendar 객체를 하나로 할 경우에는 날짜를 4일 더했다가 다시 빼야 하는 상황이 발생하기 때문이다. 그렇게 작성한 코드는 영 마음에 들지 않았다. Calendar 객체를 복사(clone)해서 문제를 해결해보려고 했지만 그렇게 나온 코드 역시 허접했다. 그래서 마지막으로 생각해낸 것이 위 코드다. 먼저 첫 날을 문자열로 변환해 기억해둔 다음 날짜를 죽 StringBuffer에 넣은 후 이걸 String으로 변환한 것과 첫 날, 마지막 날을 printf()의 인수로 넘기는 것이다. 이렇게 해서 Calendar 객체를 두개 만든다거나 또는 날짜를 더했다 뺐다 하는 작업을 하지 않고 문제를 해결했다. 그러나 날짜 포매팅을 위해 DateFormat 객체를 두 개 생성한 것은 여전히 마음에 들지 않는다.

여기까지 하고나니 SQL로도 만들고 싶은 생각이 들었다. 다음은 Oracle 10g에서 실행 가능한 SQL이다. 역시 SQL을 실행시키는 날에 따라 위에서 작성한 프로그램과 동일한 결과를 출력한다. 다만, 각 날짜 중간에 빈칸을 넣어주지는 않는다.
with a as (select sysdate + mod(9 - to_char(sysdate,'D'),7) d from dual)
select '업무일지 ('||to_char(d, 'YYYY-MM-DD')
    ||' ~ '||to_char(d+4, 'YYYY-MM-DD')||')'
from a
union all
select to_char(d+level-1, 'YYYY-MM-DD (DY)') 
from a 
connect by level <= 5;
select문 안에 chr(10)을 여러 개 붙이면 콘솔에서 실행시켰을 때 원하는 만큼 빈칸이 들어가게 할 수 있겠지만, Orange나 Toad 같은 도구로 DB에 접속해 SQL을 실행시킨다면 결과 그리드에 표시되는 모양이 별로 안좋을 듯 하다. 물론 그걸 다시 복사&붙여넣기한다면 원하는 결과를 얻을 수 있을 것 같기는 하다(테스트해보지는 않음). 
역시 SQL... 같은 문제를 겨우 7줄만으로 해결했다.
저작자 표시 비영리 변경 금지
Posted by ntalbs