Slackに時差変換botを導入 - スタンプが押されたらスレッドに時差変換されたメッセージを返信する（AWS Lambdaで処理を実装）

# 初めに
我々AIdeaは5人中2人のメンバーが海外におり、9月からは5人中4人のメンバーがヨーロッパの各地に住む予定である。このチームで活動している中で最もネックなのが日程調整である。日本時間で日程を提案すると、ヨーロッパ時間に変換するのがめんどくさいかつあっているか不安になる。VICE VERSA

時差変換をする際のめんどくささを解消するためにslackのbotを導入したので記事にする。

# 最終的なアウトプット
12:30と書かれているメッセージにCET（Central European Time）というスタンプが押されると04:30と変換しスレッドでメッセージが送られるようなもの。日本時間への変換はJSTというスタンプを押してできる。

スレッド内でのメッセージたち（これはサマータイムCESTで行われている。）
![スクリーンショット 2024-07-19 1.43.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3788759/ac03bc83-2758-34fa-8e8f-da812e3a2ac6.png)

# 本記事の内容
以下の手順で進めていった。
1. AWSのLambdaを使って時差変換できるようにする
1. SlackにAPIを通せるようにする
1. チャンネルに追加してテスト

自分たちで実装したところはコードを書いているが、コピペでできた部分に関しては参考文献を載せている。載せているものはとってもいい参考文献でした。

### 1. AWSのLambdaを使って時差変換できるようにする
12:00や12：00のような:や：の両端に二桁の数字がある時にその数字に対して処理を行うようにする。
2:00などの一桁の数字が絡んでくる場合12:00も含まれてしまい、めんどくさいことになるので、今回は2:00と入力したいときは02:00と入力するようにメンバーに頼んでいる。

どのように時差変換を実装しているかというと、
cestという名前のreactionが押された場合にはJSTからCESTへの変換であると判断し、inputテキスト内の時間から7時間引かれるように関数を組んでいる。jstという名前のreactionが押された場合にはCET or CESTからJSTへの変換であると判断し7 or 8時間足すようにしている。


サマータイムが関連しているのでスタンプが押されたタイミングがサマータイムかどうかでcetかcestを判断するようにしている。
実際の日程がサマータイムかどうか判断するには何月何日などの情報が必要になる。しかし日程調整をする際は23日12:00~のような日にちだけに省略することがほとんどだと思うので、注意してとしか言えない。

以下のようなコードでlambdaを組み
テストとしては↓を使った。
```json
{
  "input_text": "これが10:00です。これが10：00です。これがaa：00です。",
  "reaction": "CEST"
  "event_ts": "1689763200"
}
```
以下コード
```python
def lambda_handler(event, context):
    input_text = event["input_text"]
        
    if not input_text:
        return {'statusCode': 400, 'body': 'Failed to get the message text'}

    reaction = event["reaction"]
    reaction_timestamp = event["event_ts"]

    if reaction == "cest":
        converted_text = convert_all_times(input_text, -7)  # JSTからCESTへの変換（-7時間）
        converted_text = "from JST to CEST \n" + converted_text
    elif reaction == "cet":
        converted_text = convert_all_times(input_text, -8)  # JSTからCETへの変換（-8時間）
        converted_text = "from JST to CET \n" + converted_text
    elif reaction == "jst":
        if is_summer_time(reaction_timestamp, 'Europe/Zurich'):
            converted_text = convert_all_times(input_text, 7)  # CESTからJSTへの変換（+7時間）
            converted_text = "from CEST to JST \n" + converted_text
        else:
            converted_text = convert_all_times(input_text, 8)  # CETからJSTへの変換（+8時間）
            converted_text = "from CET to JST \n" + converted_text
    else:
        return {'statusCode': 400, 'body': 'Unsupported reaction'}
        
    return {
        'statusCode': 200,
        'body': converted_text
    }
```
```python
def convert_all_times(text, time_difference):
    # 時間のパターン（コロンで区切られた2桁の数字）を探す正規表現
    time_pattern = re.compile(r'(\d{2}):(\d{2})')
    time_pattern_2 = re.compile(r'(\d{2})：(\d{2})')

    # 時間を探し、見つかったら時差変換を行う
    def replace_time(match):
        hour, minute = int(match.group(1)), int(match.group(2))
        # 元の時間をdatetimeオブジェクトとして作成
        original_time = datetime(year=1901, month=1, day=1, hour=hour, minute=minute)
        # 時差を加算
        new_time = original_time + timedelta(hours=time_difference)
        
        
        if new_time.day == 31:
            return str(new_time.strftime('%H:%M')) + "\t(The Day Before)"
        elif new_time.day == 2:
            return str(new_time.strftime('%H:%M')) + "\t(The Next Day)"
        else:
            return new_time.strftime('%H:%M')

    # テキスト内の全ての時間表記を変換
    text2 = time_pattern.sub(replace_time, text)
    text3 = time_pattern_2.sub(replace_time, text2)
    return text3
```
```python
def is_summer_time(timestamp, timezone_str):
    tz = pytz.timezone(timezone_str)
    dt = datetime.fromtimestamp(float(timestamp), tz)
    return dt.dst() != timedelta(0)
```

日付周辺の日時提案では日付が変わることがあるので時間の後に（翌日）や（前日）などをつけて注意を促すようにしている。

### 2. SlackにAPIを通せるようにする
https://qiita.com/tat_tt/items/e10bd5d9aee897f0b8b6

https://qiita.com/fuku_pg/items/f5ae2a7437135fcb258c

この辺りを参考にするとできる。
Slack で API を使うために API gateway のエンドポイントを検証する必要がある。そこで"challenge"というインプットを与え、その中の値をそのまま返すだけの関数を作る必要がある。（[参考: URL検証プロセス](https://qiita.com/fuku_pg/items/f5ae2a7437135fcb258c#url%E3%81%AE%E6%A4%9C%E8%A8%BC%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9)）
一度検証が終わると、その後は自由にエンドポイントを使うことができる。

### 3. アプリをチャンネルに追加してテスト
https://note.com/michi_dev/n/n9674ebd3e3f8

こちらのコードを大いに参考にさせていただき実装した。
コードはほとんどコピペで動くくらいいい記事なのでここからコピペしたらいいと思う。
入力出力の値の型等を確認してコピペすればすぐ動く。
僕自身もコピペで行って少し入力出力を調整したらエラーも起きずに実装できたので多分簡単にできるはず。逆にエラーでず実装できて不安になったくらいにはうまくいった。

# 終わりに
時差変換のところだけ自分たちでコードを書く必要があったが、そのほかは先人たちが残してくれた記事でうまく実装することができた。本記事の流れで実装を行うと自由自在に処理を実行する Slack bot が作れると思う。

# 参考文献

https://qiita.com/tat_tt/items/e10bd5d9aee897f0b8b6

https://qiita.com/fuku_pg/items/f5ae2a7437135fcb258c

https://note.com/michi_dev/n/n9674ebd3e3f8

# 余談
最近知ったがSlackのバージョン履歴のコメントがなかなか面白い。こうゆうユーモアあるアップデートの詳細が書けるエンジニアになりたいなと思った。

![スクリーンショット 2024-07-19 15.16.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3788759/c8cdc22a-8614-c291-3e3f-de68ba0f40ea.png)