notebook

都内でWEB系エンジニアやってます。

GCPのWorkflowsで日付をフォーマットした値を生成する

この記事はGoogle Cloud Platform Advent Calendar 2021のカレンダー | Advent Calendar 2021 - Qiita6日目の記事です

qiita.com

GCPのWorkflowsでtime.format, time.parseが使えるようになった

今まではWorkflowsから何かAPIへ対してリクエストを送る際に日時系(昨日、今日など)のパラメータがある場合

たとえば昨日の日付を2021-12-05,20211205といったような形式の文字列にして送るということができなかった(色々計算すれば可能なはずだがかなり面倒)

time.formatが追加されたことによってISO 8601の形式で日付の文字列を取得できるようになったため少し手を加えれば上記のようなフォーマットにも変換できる

個人的にないと困るなーと思っていたのでさっそく試してみた

  • リリースノート

Release notes  |  Workflows  |  Google Cloud

cloud.google.com

  • time.format

Function: time.format  |  Workflows  |  Google Cloud

cloud.google.com

APIへのリクエストパラメータ

レポートなどの日々行われる自動化された処理では特定のAPIに対して「昨日の日付でパラメータを送る」や「月初の日付から昨日までのパラメータを送る」など相対的な日付を指定してリクエストを送ることがよくある

冒頭でも触れたがWorkflowsでは今までこういうリクエストを行いたい場合、日付のフォーマットが行えなかったので次のような手順を踏んでいた

  • リクエストパラメータ生成用のcloud functionを作成
  • 作成したfunctionにリクエストし、レスポンスからYYYY-MM-DD形式の値を取得
  • 本来リクエストしたいAPIにパラメータとして渡す

しかし今回time.formatが追加されたことでこの辺の処理をWorkflows内で完結できる

サンプルで試してみる

  • now.workflow.yml
main:
  steps:
    - assign_value:
        assign:
          - now: ${time.format(sys.now())}
          - today: ${text.split(time.format(sys.now()), "T")[0]}
          - yesterady: ${text.split(time.format(sys.now() - 86400), "T")[0]}
    - return_value:
        return: ${"now:" + now + ", today:" + today + ", yesterday:" + yesterady}

サンプルの実行結果は次のようになる

$ gcloud workflows deploy now --source=now.workflow.yml
$ gcloud workflows run now
argument: 'null'
endTime: '2021-12-06T04:25:01.176120362Z'
result: '"now:2021-12-06T13:25:01.172231+09:00, today:2021-12-06, yesterday:2021-12-05"'
startTime: '2021-12-06T04:25:01.153131110Z'
state: SUCCEEDED
  • today

Tで分割して最初の文字列を取得する

  • yesterday

sys.now()で取得したunixtimeから1日分(86400)の秒数を引きフォーマット、todayと同様Tで分割して前半の文字列を取得

結局計算自体は秒での計算になるが今日や昨日といった相対的な日付指定でパラメータを渡したいというパターンには対応できるようになった

一応次のように月初の日付を生成することも可能

${text.split(time.format(sys.now() - int(text.split(text.split(time.format(sys.now(), "Asia/Tokyo"), "T")[0], "-")[2]) * 86400, "Asia/Tokyo"), "T")[0]}

ここまでするなら…という感じも否めないができるにはできる

もう少し色々試してみる

  • now.workflow.yml
main:
  steps:
    - assign_value:
        assign:
          - now: ${time.format(sys.now(), "Asia/Tokyo")}
          - today: ${text.split(time.format(sys.now(), "Asia/Tokyo"), "T")[0]}
          - today_yyyymmdd: ${text.replace_all(today, "-", "")}
          - yesterady: ${text.split(time.format(sys.now() - 86400, "Asia/Tokyo"), "T")[0]}
          - seven_days_ago: ${text.split(time.format(sys.now() - 7 * 86400, "Asia/Tokyo"), "T")[0]}
          - first_day_of_month: ${text.split(time.format(sys.now() - int(text.split(today, "-")[2]) * 86400, "Asia/Tokyo"), "T")[0]}
    - return_value:
        return: ${"now:" + now + ", today:" + today + ", yesterday:" + yesterady + ", 7days ago:" + seven_days_ago + ", first day of month:" + first_day_of_month}
$ gcloud workflows run now
argument: 'null'
endTime: '2021-12-06T04:51:38.213392423Z'
result: '"now:2021-12-06T13:51:38.186738+09:00, today:2021-12-06, yesterday:2021-12-05, 7days ago:2021-11-29, first day of month:2021-12-01"'
startTime: '2021-12-06T04:51:38.168999802Z'
state: SUCCEEDED
  • seven_days_ago

7日間分の数値をsys.nowから引いてtime.formatでフォーマットして日付部分を取得

  • first_day_of_month
    • today2021-12-06から日付部分を抜き出す→06
    • intで数値化→6
    • 1日分の秒数を掛ける→518400
    • sys.nowから518400を引いた値をtime.formatで変換する
    • 日付部分を取り出す→2021-12-01

ある程度の日付操作は行えることがわかった

まとめ

  • Workflowsにtime.format関数が追加された
  • いくつかの関数を組み合わせることで昨日、○日前、月初などの日付文字列をYYYY-MM-DDなどの形式で生成することが可能になった

既存でこのような使い方をしているfunctionsを置き換えていこうと思う