Python

『Google Calendarの繰り返し』の勤怠をPythonに取り込む(出力側改修)

こんにちは Tomoです。

今回は『Google Calendarの繰り返し』の勤怠をPythonに取り込みますの第三弾です。

今回は表計算ソフトへの書き込みについて記載します。

事前準備

前回の続きとなります

以下の内容を確認してください。


勤怠クラス作成

今回イベントデータを表計算ソフトに書き込みます。ただし、繰り返しデータは一つのイベント鹿保持していないため最初に出勤した日付の勤怠を格納するクラスを用意したいと思います。

そのあと表計算ソフトへの書き込みを作成たいと思います。

    
target_month_start = datetime.date(2020, 1, 1)
target_month_end = datetime.date(2020, 1, 31)

WEEKRY_EN_LIST = ['MO','TH','TU','WE','FR','ST','SN']

class CalendarAttendanceClass():

    def ___init___(self):
        self.date = none
        self.stat_date_time = none
        self.end_date_time  = none

    

ポイントは以下の通りです。

  • 出力範囲を決める
  • 週を変換するlistを作る
  • 勤怠クラスを作る

出力範囲を決める

繰り返しは終了時間をもっていないため、永遠に出力されます。

これを避けるために、出力する日程を変数で保持します。

※今後は、外部から年月を渡して出力することも考慮しています。

週を変換するlistを作る

カレンダーから取得した週の内容はアルファベット2文字です。これに対し、datetime型は数値のためマッピング用に用意しています。

['MO','TH','TU','WE','FR','ST','SN']

[0,1,2,3,4,5,6]

上記のようにマッピングされます。(こちらはPythonの辞書を使うかもしれません)

※'ST','SN'は正しく確認できてないので代わるかもしれません。後日確認します。

勤怠クラスを作る

勤怠を格納するクラスを用意します。

これは、繰り返しのイベントから出勤した日を算出して格納したものになります。

勤怠の年月日、開始日時、終了日時を保持します。

そのあと表計算ソフトへの書き込みを作成たいと思います。

表計算ソフトに書き込む

書き込み部分を記載します。

    

def write_attendance(cal_ate_list):
    """
    勤怠データを出力します.
    """

    # カレンダー勤怠クラスをlistに格納する為に初期化
    calendar_attendance = []

    # イベントの数分処理を繰りす
    for cd in cal_ate_list:

        # タイトルが勤怠の場合に処理をする
        if cd.summary in '勤怠':

            if cd.repeat:
                # 繰り返し予定の場合はこのルートを通る

                # 出力範囲の日数を繰り返す
                # 例)2020年1月1日から2020年1月31日まで1日づつ処理を繰り返して勤怠用のクラスに格納する
                for count_date in range((target_month_end - target_month_start).days + 1):

                    # ターゲット日(繰り返しのカレント日付)
                    target_date = target_month_start + datetime.timedelta(count_date)

                    # イベントの開始日 <= ターゲット日 
                    # 繰り返しの場合ターゲット日以前に開始日があ場合はすべて出力する(例外あり)
                    if cd.stat_date_time.date() <= target_date:

                        # 週の繰り返しであること
                        if cd.freq is not None and cd.freq in 'WEEKLY':

                            # 出勤しない日か判定するフラグ(True:出勤/False/休み)
                            ex_no_flg = True

                            # 出勤しない日を格納するインスタンスの存在をチェックし存在する場合以下を処理
                            if hasattr(cd, 'exdate'):

                                # 出勤しない日はlistで保持されるため繰り返す。
                                # このデータが多いと処理が遅くなる
                                for exdate in cd.exdate:

                                    # 出勤しない日 == ターゲット日 の場合
                                    # カレンダー勤怠のインスタンスに書き込まないように
                                    # 出勤しない日か判定するフラグを無効にする
                                    if exdate.date() == target_date:
                                        ex_no_flg = False

                            # 出勤日
                            if ex_no_flg:

                                if hasattr(cd, 'until'):
                                    # 繰り返しの期限が設定されているか

                                    # 繰り返し期限日 >= ターゲット日 (期限日以前の時は出力する)
                                    if cd.until.date() >= target_date:

                                        # 勤怠を出力する曜日か判定する
                                        if WEEKRY_EN_LIST[target_date.weekday()] in cd.byday:

                                            #  カレンダー勤怠クラスのインスタンスを生成
                                            cac = CalendarAttendanceClass()

                                            # 対象日をインスタンス変数に格納
                                            cac.date = target_date

                                            # 開始日時をインスタンス変数に格納
                                            cac.stat_date_time = cd.stat_date_time

                                            # 終了日時をインスタンス変数に格納
                                            cac.end_date_time = cd.end_date_time

                                            # カレンダー勤怠クラスのインスタンスをlistに格納
                                            calendar_attendance.append(cac)

                                else:
                                    # 繰り返しの期限が設定されていないため出力
                                    # 勤怠を出力する曜日か判定する
                                    if WEEKRY_EN_LIST[target_date.weekday()] in cd.byday:

                                        #  カレンダー勤怠クラスのインスタンスを生成
                                        cac = CalendarAttendanceClass()

                                        # 対象日をインスタンス変数に格納
                                        cac.date = target_date

                                        # 開始日時をインスタンス変数に格納
                                        cac.stat_date_time = cd.stat_date_time

                                        # 終了日時をインスタンス変数に格納
                                        cac.end_date_time = cd.end_date_time

                                        # カレンダー勤怠クラスのインスタンスをlistに格納
                                        calendar_attendance.append(cac)

            else:
                # 繰り返し予定以外の場合はこのルートを通る

                # 出力対象開始日 <= イベントクラスの開始日 <= 出力対象終了日
                # 例) 2020年1月1日 <= 2020年1月5日 <= 2020年1月31日 出力する
                # 例) 2020年2月1日 <= 2020年2月5日 <= 2020年2月31日 出力しない
                if target_month_start <= cd.stat_date_time.date() <= target_month_end:

                    #  カレンダー勤怠クラスのインスタンスを生成
                    cac = CalendarAttendanceClass()

                    # 対象日をインスタンス変数に格納
                    cac.date = target_date

                    # 開始日時をインスタンス変数に格納
                    cac.stat_date_time = cd.stat_date_time

                    # 終了日時をインスタンス変数に格納
                    cac.end_date_time = cd.end_date_time

                    # カレンダー勤怠クラスのインスタンスをlistに格納
                    calendar_attendance.append(cac)

    """
    ここから表計算に書き込みを行う
    """

    # 表計算ワークブック作成
    work_book = openpyxl.Workbook()

    # 表計算ワークシートをアクティブ
    work_sheet = work_book.active

    # 出力範囲の日数を繰り返す
    # 例)2020年1月1日から2020年1月31日まで1日づつ処理を繰り返して表計算のセルに書き込む
    for count_date in range((target_month_end - target_month_start).days + 1):

        # ターゲット日(繰り返しのカレント日付)
        target_date = target_month_start + datetime.timedelta(count_date)

        # 勤怠表の日付を出力する(日付だけを出力する)
        work_sheet.cell(count_date + 1, 1).value = target_date.strftime(FORMAT_DATE)

        # カレンダー勤怠クラス(出勤日を探すために繰り返す)
        for cal_ate in calendar_attendance:

            # ターゲット日と出勤日が一致し場合 出勤情報をセルに格納する
            if cal_ate.date == target_date:

                # 開始時間
                work_sheet.cell(count_date + 1, 2).value = cal_ate.stat_date_time.strftime(FORMAT_HM)

                # 終了時間
                work_sheet.cell(count_date + 1, 3).value = cal_ate.end_date_time.strftime(FORMAT_HM)

                # 作業時間(昼休憩1時間を引く)
                work_sheet.cell(count_date + 1, 4).value = cal_ate.end_date_time - 
                    cal_ate.stat_date_time - datetime.timedelta(hours=1)

    # 表計算ソフトに書き込み
    work_book.save(ATTENDANCE_FILE_PATH)

    

書き込み部分を記載します。説明はソースコードに記載してますのでここでは省略します。

最適化をおこなっていないため、かなりネストしたソースコードとなっています。

勤怠クラスを作成してる部分と、表計算ソフトへの書き込み部分の2ブロックに分かれていることがポイントです。

いずれ処理を分けたいと思います。(最初の構成が、読み込みと書き込みだったのであえて一緒にしています。)

とりあえず動くコードで載せました。最適化できたらベット投稿します。

まとめ

最期は突貫ですが、出力側の改修を行いました。

とりあえず今回である程度の部分はできたと思います。

ソースコードの最適化や、テストが不十分なので今後書いていきたいと思います。

「PythonでGoogle Calendarからデータを取得して、表計算ソフトに勤怠表を出力する」のコーディングは終わります。

次回は、未定ですが。テスト方法か、Googleカレンダーから交通費作成のいずれかを投稿したいと思います。

今回作成したコードは別途こちらに記載します。

ソースコード

コメント

0 件のコメント:

コメントを投稿

コメントをお待ちしています。