Fly to the sky & Return

파이썬으로 엑셀 다루기.......2 엑셀로 달력을 만들어보자.. 본문

프로그래밍/파이썬

파이썬으로 엑셀 다루기.......2 엑셀로 달력을 만들어보자..

낼은어떻게 2017. 12. 28. 09:31
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

파이썬을 이용해서  엑셀을 컨트롤 해보기로 하겠습니다

달력만들기를 통해  각각의 Cell과 Range 그리고 Offset 등을 적용해보도록 하겠습니다.

1
2
3
4
5
import win32com.client
import time
import datetime
from datetime import timedelta
from dateutil.relativedelta import relativedelta
cs


일단  몇가지를 import 합니다

파이썬에서 엑셀을 컨트롤 하는 방법이 여러가지가 있긴 하지만  개인적으로 생각으로는  COM를 이용하는 방법이 가장 VBA와 유사한 환경이라고 생각을 하는 터라 이번에도 COM을 이용해서 엑셀을 컨트롤 하겠습니다.


1. COM을 이용하기 위해서  win32com.client를 import 합니다

2. 달력이니만큼 시간관련 time을 import하고

5번 월단위의 날짜계산을 위해 relativedelta  를 import 합니다.


여기까지가 준비과정입니다.


1
2
3
4
5
6
excel = win32com.client.Dispatch("Excel.Application")
excel.Visible = True
wb = excel.Workbooks.Add()
ws = wb.Worksheets("Sheet1")
ws.Cells(1,1).Value = "hello world"
 
cs

엑셀을 실시간으로 컨트롤 하기 위해 필요한 코드들입니다.   

에러없이 작동하는지 확인하기 위해 5번 코드를 넣어 출력시켜봅니다.

참고로  특정 Cell을 지정하는 방식에는  Cells()와  Range()를 다 사용할수 있습니다.


1
2
3
4
5
6
7
8
ws.Range("a2:g2").Font.Size = 12
ws.Range("a2:g2").ColumnWidth = 11
ws.Range("a2:g2").VerticalAlignment = 2 #center
ws.Range("a2:g2").HorizontalAlignment = 3 # center
ws.Range("a2:g2").Orientation = 0
ws.Range("a2:g2").Font.Size = 12
ws.Range("a2:g2").Font.Bold = True
ws.Range("a2:g2").RowHeight = 20
cs

일요일 부터 토요일까지의 제목이 들어가는 부분에 대한 Range()입니다.

VBA상에서는 With ~ END 코드를 이용해서 좀더 줄일수 있는데 파이썬에서는 그런코드를 찾지 못해서 그냥 저렇게 나열하였습니다.

VBA상에서 alignment와 관련된 인자값들은  다음과 같이 할수 있는데

1
2
HorizontalAlignment = xlCenter
VerticalAlignment = xlCenter
cs

COM을 이용한 엑셀컨트롤에서는 에러가 납니다.
그래서.. 3번 4번 코드와 같으  숫자를 이용해서  정렬값을 나타내야 합니다.,

그럼 본격적으로 달력만들기에 들어겠습니다.

1.  해당월의 마지막 날을 구하는 코드

   특정한 달의 마지막 날을 구하는 코드는 쉽게 만들수도 있지만 어찌보면 어려울 수도 있습니다.
제가 사용하는 방법은 정말 단순한 방법이긴 합니다만 매우 유용한 방법이라 할수 있습니다.
바로 특정한 달의  그 다음달 1일에서 하루 전날을 구하는 것입니다. 
이런 코드를이용하면 시스템 자체에서 가지고있는 달력을 통해 윤년 등등을 전혀 고려하지 않고 필요한 것을 구할수가 있는 것이지요.
코드는 아래와 같습니다


1
2
3
4
5
6
7
8
def getLastDayOfMonth(year,month):
  input_day = datetime.date(year,month,1)
  timegap = timedelta(days=1)
  timegap_month = relativedelta(months=1)
  dDay = input_day + timegap_month - timegap
  lastDayOfMonth = dDay.day
  return lastDayOfMonth
 
1cs

만들고자 하는 달력의  해당월을 입력받아 날짜형식으로 지정을 합니다

날짜 차이를 계산하는 함수 timedelta값을 지정해주고

월별 차이를 계산하는 함수 relativedelta 값을 지정해줍니다


그리고  계산을 합니다.        해당월에서  한달을 더하고  그날에서 하루를 빼는  그럼  해당월의 마지막 날이  return되는 것이지요


2.  요일 제목 찍기

1
2
3
4
5
my_list = ["일요일""월요일","화요일","수요일","목요일","금요일","토요일"]
my_list2 = ["a","b","c","d","e","f","g"]
my_list_len = len(my_list)
for i in range(0, my_list_len):
    ws.Range(my_list2[i]+"2").Value = my_list[i]
cs

list 함수와 for 문  그리고 엑셀의 Range()를 이용해서  일~ 토요일까지 제목을 찍어줍니다.


3.  달력이 들어갈 Cell 구성

통상적으로 달력은  42칸이 있으면 만들수 있습니다.    42칸의 Cell들에 대한 속성을 편집합니다.

1
2
3
4
5
ws.Range("a3:g8").HorizontalAlignment = 2 #left   4 -> right
ws.Range("a3:g8").VerticalAlignment = 2
ws.Range("a3:g8").Font.Size = 18
ws.Range("a3:g8").Font.Bold = True
ws.Range("a3:g8").RowHeight = 21
cs

4. 시작하는 날의 요일을 파악하기

1
wkNum = (datetime.date(year_date,month_date,1)).weekday()
cs
엑셀에서는  일요일이 0부터 시작하지만  파이썬에서는 월요일이 0부터 시작합니다.


5. 날짜 채우기
달력에 맞게 요일별로 날짜를 채워야 합니다.
엑셀에 있는 Range()함수의 특성을 이용해서 아주 쉽게  날짜를 채울수가 있습니다.

1
2
3
for i in range(wkNum+1,day_date+1+wkNum):
    ws.Range("a3:g8")[i].Value = i - wkNum
    
cs

엑셀의 Range()함수를 이용하면  각 Cell에 인덱스가 생성됩니다.

시작하는 요일이 월요일이라면  wkNum = 0 이겠지만  Cell index상에서는 1의 위치에 가야합니다.

그래서  wkNum +1 이 필요합니다.   그리고 끝나는 Cell은  해당월의 마지막 날인데 

파이썬 for문의 range 은 그 숫자전까지이므로  마지막 날의 숫자 + 1 해야 마지막 날이 출력됩니다.


여기서 문제가 발생합니다. 달력표시는 일요일 부터지만  파이썬은 월요일 값이 0  이므로   시작일이 일요일인경우 첫칸이 완전히 비워져 버립니다. 

그래서 일요일인 경우 그러한 경우가 발생하지 않도록 다음과 같은 코드를 추가해줍니다.

1
2
3
4
# 일요일인 경우 첫번째 셀부터 시작할수 있도록...
if wkNum == 6:
    wkNum = -1
 
cs


다음은 전체 코드입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# -*- coding: utf-8 -*-
"""
Created on Fri Dec 22 14:14:19 2017
@author: morrow_macbook
"""
 
import win32com.client
import time
import datetime
from datetime import timedelta
from dateutil.relativedelta import relativedelta
 
excel = win32com.client.Dispatch("Excel.Application")
excel.Visible = True
wb = excel.Workbooks.Add()
ws = wb.Worksheets("Sheet1")
ws.Cells(1,1).Value = "hello world"
 
 
ws.Range("a2:g2").Font.Size = 12
ws.Range("a2:g2").ColumnWidth = 11
ws.Range("a2:g2").VerticalAlignment = 2 #center
ws.Range("a2:g2").HorizontalAlignment = 3 # center
ws.Range("a2:g2").Orientation = 0
ws.Range("a2:g2").Font.Size = 12
ws.Range("a2:g2").Font.Bold = True
ws.Range("a2:g2").RowHeight = 20
 
# 마지막 날이 몇일인지 찾는 함수
def getLastDayOfMonth(year,month):
  input_day = datetime.date(year,month,1)
  timegap = timedelta(days=1)
  timegap_month = relativedelta(months=1)
  dDay = input_day + timegap_month - timegap
  lastDayOfMonth = dDay.day
  return lastDayOfMonth
 
'''  첫번째 날이 무슨 요일인지 찾는 함수
def get_WeekDay(year,month, day):
    dayString = ["월","화","수","목","금","토","일"]
    return dayString[datetime.date(year,month,day).weekday()]
'''
 
year_date = 2018
month_date = 4
day_date = getLastDayOfMonth(year_date, month_date)
 
ws.Cells(1,2).Value = str(year_date)+"년 " + str(month_date)+"월"
 
my_list = ["일요일""월요일","화요일","수요일","목요일","금요일","토요일"]
my_list2 = ["a","b","c","d","e","f","g"]
my_list_len = len(my_list)
for i in range(0, my_list_len):
    ws.Range(my_list2[i]+"2").Value = my_list[i]
 
wkNum = (datetime.date(year_date,month_date,1)).weekday() #월요일 0  .. 일요일 6
 
ws.Range("a3:g8").HorizontalAlignment = 2 #left   4 -> right
ws.Range("a3:g8").VerticalAlignment = 2
ws.Range("a3:g8").Font.Size = 18
ws.Range("a3:g8").Font.Bold = True
ws.Range("a3:g8").RowHeight = 21
 
# 일요일인 경우 첫번째 셀부터 시작할수 있도록...
if wkNum == 6:
    wkNum = -1
 
for i in range(wkNum+1,day_date+1+wkNum):
    ws.Range("a3:g8")[i].Value = i - wkNum
   
cs


결과는 다음과 같이 나타납니다.