Skip to content

Instantly share code, notes, and snippets.

@yoshida-mediba
Last active January 7, 2016 08:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yoshida-mediba/b684c06ef7d6a13784b1 to your computer and use it in GitHub Desktop.
Save yoshida-mediba/b684c06ef7d6a13784b1 to your computer and use it in GitHub Desktop.
コードコンテスト用 空き予定検索

コードコンテスト用 空き予定検索

コンセプト

  • 可能な限り短時間で完成させる
  • GoogleCalenderの複数の予定が読み込める
  • 分刻みのタイムテーブルを作成して予定を埋めていく事で空き時間の計算をする

依存ライブラリ

  • gdate (coreutils)
  • sqlite3

実行方法

$ sh SearchSchedule.sh [calender] [datetime] [min]

実行例

  1. h-yoshidaさんの15日以降の60分

    $ sh SearchSchedule.sh 'h-yoshida@mediba.jp' '2015-12-15 00:00:00' 60
    
  2. yu-yamashitaさんとh-yoshidaさんの15日以降の120分

    $ sh SearchSchedule.sh 'h-yoshida@mediba.jp|yu-yamashita@mediba.jp' '2015-12-15 00:00:00' 120
    

実行結果

2015-12-15 11:30:00〜2015-12-15 13:29:00 予定なし
2015-12-15 14:30:00〜2015-12-15 16:29:00 予定なし
2015-12-15 16:30:00〜2015-12-15 18:29:00 予定なし
2015-12-16 11:00:00〜2015-12-16 12:59:00 予定なし
2015-12-16 13:00:00〜2015-12-16 14:59:00 予定なし

注意

  • 指定時間から1週間分のみ
  • DB構築にはげしく時間がかかるので待ってください
  • GoogleCalenderの共有設定を一般公開にしてください
#!/bin/bash
# -*- coding:utf-8-unix; -*-
#
# sqlite3でがんばる
# 分単位の時刻表DBを作成し、空き時間を計算する
#
for cmd in gdate sqlite3; do
if ! hash ${cmd} 2>/dev/null; then
echo >&2 "${cmd}がインストールされていません"
exit 1
fi
done
calenders=$(echo $1 | tr '|' ' ')
datetime=$(gdate --date="${2}" +"%s")
min=$3
# 予定をインポートしてくる
holy=$(curl -sS "https://www.google.com/calendar/ical/ja.japanese%23holiday%40group.v.calendar.google.com/public/full")
cals=""
for calender in ${calenders}; do
ical=$(curl -sS "https://calendar.google.com/calendar/ical/${calender}/public/basic.ics")
if [[ -n $(echo $ical | fgrep 'フィード処理エラー') ]]; then
echo >&2 'GoogleCalenderの共有設定を変更してください'
exit 1
fi
cals="${cals}\n${ical}"
done
start=($(echo "${cals}" | fgrep 'DTSTART:' | awk -F':|\r' '{print $2}'))
end=($(echo "${cals}" | fgrep 'DTEND:' | awk -F':|\r' '{print $2}'))
if [ ${#start[@]} -ne ${#end[@]} ]; then
echo >&2 'そういうical形式もあるのか'
exit 1
fi
# 1週間以内の予定をおさえる
limit=$((60 * 24 * 7))
# まずは分単位のDBを作成する
rm -f /tmp/schedule.db
echo 'create schedule table'
echo 'CREATE TABLE schedule (date DATETIME PRIMARY KEY, busy BOOLEAN);' | sqlite3 /tmp/schedule.db
rm -f /tmp/init.sql
while [ $limit -gt 0 ]; do
busy=0
# gdateコマンド重いからまとめた
date=($(gdate --date "@${datetime}" +'%H %w %Y%m%d'))
hour=${date[0]}
week=${date[1]}
date=${date[2]}
# 21時〜10時は予定ありにしよう
if [ $hour -lt 10 -o $hour -gt 20 ]; then
busy=1
fi
# 土日も予定あり
if [ $week -eq 0 -o $week -eq 6 ]; then
busy=1
fi
# 休日も予定あり
if [[ -n $(echo "${holy}" | fgrep "DTSTART;VALUE=DATE:${date}") ]]; then
busy=1
fi
echo "INSERT INTO schedule VALUES (${datetime}, ${busy});" >> /tmp/init.sql
datetime=$(expr ${datetime} + 60)
limit=$(expr ${limit} - 1)
if [ $(expr $limit % 1440) -eq 0 ]; then
echo "create initial data (${date})"
fi
done
echo 'insert initial data'
cat /tmp/init.sql | sqlite3 /tmp/schedule.db
# DBの予定を埋めてく
rm -f /tmp/update.sql
for i in ${!start[@]}; do
startdate=$(echo ${start[$i]} | sed -e 's/\([0-9]\{4\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)T\([0-9]\{2\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)Z/\1-\2-\3 \4:\5 +000/g')
enddate=$(echo ${end[$i]} | sed -e 's/\([0-9]\{4\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)T\([0-9]\{2\}\)\([0-9]\{2\}\)\([0-9]\{2\}\)Z/\1-\2-\3 \4:\5 +000/g')
startdate=$(gdate --date="${startdate}" +"%s")
enddate=$(($(gdate --date="${enddate}" +"%s") - 60))
echo "UPDATE schedule SET busy = 1 WHERE \`date\` BETWEEN '${startdate}' AND '${enddate}';" >> /tmp/update.sql
done
echo 'update schedule'
cat /tmp/update.sql | sqlite3 /tmp/schedule.db
# 空き予定検索
suggest=$(sqlite3 /tmp/schedule.db "SELECT date FROM schedule WHERE busy = 0 ORDER BY \`date\` LIMIT 1;")
out=0
while [ -n "$suggest" -a $out -lt 5 ]; do
# sqlite3はbooleanのsumが上手くいかないみたい
schedule=$(sqlite3 /tmp/schedule.db "SELECT datetime(date, 'unixepoch', 'localtime'), busy FROM schedule WHERE \`date\` >= ${suggest} ORDER BY \`date\` LIMIT ${min};")
if [[ -n $(echo "${schedule}" | fgrep '|1') ]]; then
enddate=$(echo "${schedule}" | fgrep '|1' | awk -F'|' '{print $1}' | tail -n 1)
suggest=$(($(gdate --date="${enddate}" +"%s") + 60))
else
startdate=$(echo "${schedule}" | awk -F'|' '{print $1}' | head -n 1)
enddate=$(echo "${schedule}" | awk -F'|' '{print $1}' | tail -n 1)
echo "${startdate}〜${enddate} 予定なし"
suggest=$(($(gdate --date="${enddate}" +"%s") + 60))
((out ++))
fi
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment