TT Lab
はじめる
学ぶ 学習パス コース

銀行現場の言葉

決済日を計算するエンジンをつくる

TT Labで続きを見る

目標

受付の瞬間とカレンダー上の日付を切り分け、休業日カレンダーと締め時刻で決済日を計算するエンジンを作ります。相手機関の標準時と、1987・1988年のソウルのサマータイム期間まで正しく扱い、誤って付けられた決済日を、元帳を上書きせずに全件再計算します。

なぜ重要なのか

瞬間は1つですが、その瞬間が何日なのかは標準時を決めて初めて答えが出ます。銀行ではここに締め時刻と営業日カレンダーがさらに加わり、お金が実際にやり取りされる日付は、保存された事実ではなくルールの出力物になります。この計算がコードの複数の場所に散らばると、「昨日の取引」の定義がシステムごとに変わり、そのずれは障害には見えないので、清算の突合まで生き残ります。 休業日と締め時刻は毎年変わるので、コードではなくデータに置きます。そのため、このラボのエンジンは、カレンダーと設定を--dbで受け取ったSQLiteから読みます。 採点ツールは、書かれた文言を信用しません。自分で作った休業日カレンダーと締め時刻を入れた一時DBを渡してエンジンを実行し、判定を自分で計算した値と突き合わせます。答えを埋め込んだエンジンは通過できません。

ステップ

  1. /root/bizday/gen_bizday.pyを作成して実行し、/root/bizday/txn.dbを作ってください。送金受付300件、移行取引48件、休業日6日、設定3行が入ります。
  2. UTC日付とKST日付が分かれる取引を/root/bizday/kst_shift.csvに、3つの数字を/root/bizday/bucket.txtに書いてください。
  3. /root/bizday/bizday.pyにis-bizday、next-bizday、add-bizdaysを実装してください。カレンダーは--dbのholidayテーブルから読みます。
  4. bizday.pyにvalue-dateを追加してください。締め時刻と標準時は、sys_paramから読みます。
  5. bizday.pyにlocalizeを追加し、ソウルとロンドンで日付が分かれる取引を/root/bizday/counterparty.csvに書いてください。
  6. 移行取引48件を、ローカル時刻とオフセットまで含めて/root/bizday/legacy_offsets.csvに書き、3つの数字を/root/bizday/dst_seoul.txtに書いてください。
  7. 元帳のvalue_dateを上書きせず、txn.dbにvalue_dateテーブルを作って300件を再計算し、変わる取引だけを/root/bizday/redate.csvに書いてください。
  8. 再計算した決済日ごとの集計を/root/bizday/valuedate_summary.csvに、レポートを/root/bizday/bizday_report.mdに書いてください。

参考

受付元帳のスナップショットを作る

/root/bizday/gen_bizday.pyを作成して実行し、/root/bizday/txn.dbを作ってください。送金受付300件、移行取引48件、休業日6日、設定3行が入ります。

テーブルは4つです。txnのreceived_utcは2026-06-29T01:02:03Zの形で、value_dateは今の基幹系のルールどおり、received_utcの先頭10文字をそのまま使います。そのルールが間違っていることが、このラボの出発点です。

瞬間とカレンダー上の日付を切り分ける

UTC日付とKST日付が異なる取引を、/root/bizday/kst_shift.csvにtxn_id,received_utc,utc_date,kst_dateのヘッダー行とともに書き、/root/bizday/bucket.txtにshift_count=、utc_days=、kst_days=を書いてください。

datetime.fromisoformatで瞬間を読み、astimezone(ZoneInfo("Asia/Seoul"))で移したあとに.date()を取ります。順序を変えてはいけません。utc_daysとkst_daysは、それぞれバケット化したときに出る、異なる日付の数です。

営業日カレンダーをエンジンに移す

/root/bizday/bizday.pyにis-bizday、next-bizday、add-bizdaysを実装してください。休業日は--dbで受け取ったDBのholidayテーブルから読みます。

週末はweekday() >= 5で、休業日はテーブルから来ます。reasonはbizday・weekend・holidayの3つのうちの1つです。採点ツールは、学習者のDBとは異なる休業日を入れた一時DBを渡して実行するので、カレンダーをコードに埋め込むと不合格になります。

締め時刻のあとのリクエストを翌営業日に送る

bizday.pyにvalue-dateを追加してください。標準時と締め時刻はsys_paramから読み、締め時刻以上なら1日足したうえで、営業日に送ってください。

締め時刻の比較は、ローカル時刻に移したあとで行います。UTC時刻の文字列と比較すると、サマータイムがあった区間で1時間ずつずれます。境界は>=です。ちょうどの時刻に入ったリクエストは、翌日に回ります。採点ツールは、締め時刻を実行のたびに別の値で選びます。

相手機関のカレンダーに移す

bizday.pyにlocalizeを追加し、ソウルとロンドンで日付が分かれる取引を、/root/bizday/counterparty.csvにtxn_id,received_utc,seoul_date,london_dateのヘッダー行とともに書いてください。

utc_offsetは、+09:00のように、符号と2桁の時・分で書きます。localは、オフセットが付いたRFC 3339文字列でなければなりません。オフセットを外すと、その文字列はもう瞬間ではありません。ロンドンは夏はUTC+1です。

1987年の夏の1時間を見つけ出す

移行取引48件を、/root/bizday/legacy_offsets.csvにtxn_id,received_utc,seoul_local,utc_offsetで書き、/root/bizday/dst_seoul.txtにkdt_rows=、kst_rows=、date_shift_rows=を書いてください。

Asia/Seoulは今はUTC+9ですが、1987・1988年の夏にはサマータイムがありました。zoneinfoはその事実を知っているので、自分で計算せず、尋ねてください。date_shift_rowsは、KST日付がUTC日付と異なる移行取引の数です。

決済日を、元帳を上書きせずに再計算する

txn.dbにvalue_date(txn_id, value_date)テーブルを作って300件の決済日を再計算して入れ、古い決済日と異なる取引だけを/root/bizday/redate.csvにtxn_id,received_utc,old_value_date,new_value_dateで書いてください。txn.value_dateには手を触れないでください。

ルールを再実装せず、bizday.pyをモジュールとして読み込んで使ってください(sys.pathに/root/bizdayを入れてimport)。元帳が記録した古い決済日を消すと、どのルールで付けた値だったかがわからなくなります。再計算の結果は、新しいテーブルに入れます。

集計とレポートにまとめる

再計算した決済日ごとの件数と金額を、/root/bizday/valuedate_summary.csvにvalue_date,txn_count,amount_sumで昇順に書き、/root/bizday/bizday_report.mdに## 무엇이 틀렸나、## 결제일을 어떻게 계산하나、## 상대방 표준시、## 과거 서머타임、## 재발 방지の5つの節を書いてください(見出しは韓国語で、順に「何が間違っていたか」「決済日をどう計算するか」「相手側の標準時」「過去のサマータイム」「再発防止」という意味です)。

集計は、value_dateテーブルとtxnを結合すれば出ます。レポートには、変わった件数、締め時刻、どの標準時で計算するか、相手機関の標準時、1987・1988年のオフセットを、数字と名前で書いてください。休業日にかかる日付が集計から抜けていることも、確認する価値があります。