COBOLには日付・時刻を取得・操作するための組み込み関数が充実しています。FUNCTION CURRENT-DATE(現在日時の取得)・ACCEPT FROM DATE/TIME/DAY(旧方式)・INTEGER-OF-DATE / DATE-OF-INTEGER(日付算術)・TEST-DATE-YYYYMMDD(日付検証)を使いこなすことで、経過日数の計算・月末日の特定・バッチ処理の基準日管理など業務でよく使う処理が実装できます。
この記事ではCOBOLの日付・時刻機能を体系的に解説します。各関数の戻り値の構造から、年齢計算・月次バッチ処理の実践パターンまで網羅します。
- FUNCTION CURRENT-DATEの戻り値の構造(21文字)と年月日時分秒・タイムゾーンの取り出し方
- ACCEPT FROM DATE/TIME/DAYによる旧方式の日時取得と2桁年問題
- INTEGER-OF-DATE・DATE-OF-INTEGERを使った日付の加減算・経過日数の計算
- TEST-DATE-YYYYMMDDによる日付バリデーション
- 年齢計算・月末日計算・月次バッチ処理の実践パターン
COBOLの日付・時刻関連機能 全体像
COBOLには日付・時刻を扱う方法として「組み込み関数(FUNCTION)」と「ACCEPT FROM句」の2系統があります。現代のCOBOLではFUNCTION系が主流です。
| 機能 | 動作 | COBOL標準 | 用途 |
|---|---|---|---|
| FUNCTION CURRENT-DATE | 現在の日付・時刻・タイムゾーンを取得。21文字の文字列を返す | COBOL 85(ISO 1989:1985)以降 | 現在日時の取得(推奨) |
| ACCEPT WS-DATE FROM DATE | 現在日付をYYMMDD形式(6桁)で取得 | COBOL 74以降 | 旧方式。2桁年問題に注意 |
| ACCEPT WS-DATE FROM DATE YYYYMMDD | 現在日付をYYYYMMDD形式(8桁)で取得 | COBOL 2002以降 | 旧方式の4桁年版 |
| ACCEPT WS-TIME FROM TIME | 現在時刻をHHMMSSCC形式(8桁)で取得 | COBOL 74以降 | 旧方式での時刻取得 |
| ACCEPT WS-DAY FROM DAY | 現在日付をYYDDD形式(ユリウス通日)で取得 | COBOL 74以降 | ユリウス日付形式 |
| FUNCTION INTEGER-OF-DATE | YYYYMMDD形式の日付を整数(通算日数)に変換 | COBOL 85以降 | 日付の加減算・差分計算 |
| FUNCTION DATE-OF-INTEGER | 整数(通算日数)をYYYYMMDD形式に変換 | COBOL 85以降 | 計算後の日付復元 |
| FUNCTION INTEGER-OF-DAY | YYYYDDD形式の日付を整数に変換 | COBOL 85以降 | ユリウス日付の加減算 |
| FUNCTION DAY-OF-INTEGER | 整数をYYYYDDD形式に変換 | COBOL 85以降 | ユリウス日付の復元 |
| FUNCTION TEST-DATE-YYYYMMDD | YYYYMMDD形式の日付が有効かチェック。0=有効 | COBOL 2002以降 | 日付バリデーション |
| FUNCTION TEST-DAY-YYYYDDD | YYYYDDD形式の日付が有効かチェック。0=有効 | COBOL 2002以降 | ユリウス日付のバリデーション |
FUNCTION CURRENT-DATE(現在日時の取得)
現在の日付・時刻を取得する最も確実な方法です。戻り値は21文字の文字列で、日付・時刻・タイムゾーンオフセットが含まれます。
* FUNCTION CURRENT-DATE の戻り値(21文字) * * 桁位置 内容 例 * 1- 4 年(YYYY) 2026 * 5- 6 月(MM) 04 * 7- 8 日(DD) 14 * 9-10 時(HH) 09 * 11-12 分(MM) 30 * 13-14 秒(SS) 45 * 15-16 百分の1秒(CC) 12 * 17 タイムゾーン符号 +(+/-/0) * 18-19 タイムゾーン時 09 * 20-21 タイムゾーン分 00 * * 日本標準時(JST, UTC+9)の例: '20260414093045121+0900'
WORKING-STORAGE SECTION.
* 21文字のバッファに受け取る
01 WS-CURRENT-DATE-TIME PIC X(21).
* 各フィールドに分解して受け取る方法(GROUPアイテム)
01 WS-DATETIME.
05 WS-YEAR PIC 9(4). *> 年(YYYY)
05 WS-MONTH PIC 9(2). *> 月
05 WS-DAY PIC 9(2). *> 日
05 WS-HOUR PIC 9(2). *> 時
05 WS-MINUTE PIC 9(2). *> 分
05 WS-SECOND PIC 9(2). *> 秒
05 WS-HUNDREDTHS PIC 9(2). *> 百分の1秒
05 WS-TZ-SIGN PIC X(1). *> タイムゾーン符号(+/-/0)
05 WS-TZ-HOURS PIC 9(2). *> タイムゾーン時差(時)
05 WS-TZ-MINUTES PIC 9(2). *> タイムゾーン時差(分)
PROCEDURE DIVISION.
*--- 方法1: 21文字のバッファに受け取り、部分参照で取り出す ---
MOVE FUNCTION CURRENT-DATE TO WS-CURRENT-DATE-TIME
DISPLAY '年 : ' WS-CURRENT-DATE-TIME(1:4)
DISPLAY '月 : ' WS-CURRENT-DATE-TIME(5:2)
DISPLAY '日 : ' WS-CURRENT-DATE-TIME(7:2)
DISPLAY '時 : ' WS-CURRENT-DATE-TIME(9:2)
DISPLAY '分 : ' WS-CURRENT-DATE-TIME(11:2)
DISPLAY '秒 : ' WS-CURRENT-DATE-TIME(13:2)
DISPLAY 'TZ : ' WS-CURRENT-DATE-TIME(17:1)
WS-CURRENT-DATE-TIME(18:2) ':00'
*--- 方法2: GROUPアイテムに受け取り、フィールド名でアクセス ---
MOVE FUNCTION CURRENT-DATE TO WS-DATETIME
DISPLAY '日付: ' WS-YEAR '/' WS-MONTH '/' WS-DAY
DISPLAY '時刻: ' WS-HOUR ':' WS-MINUTE ':' WS-SECOND
STOP RUN.
21文字のグループ項目(01レベルのGROUP)に
MOVE FUNCTION CURRENT-DATE TO WS-DATETIMEと書くと、各05レベルのフィールドに自動的に分解されます。部分参照(WS-DATETIME(1:4))よりも名前でアクセスできるため、コードが読みやすくなります。ACCEPT FROM DATE/TIME/DAY(旧方式)
ACCEPT文にFROM DATE/FROM TIME/FROM DAYを指定する旧来の方式です。COBOL 74から使えるため古いシステムでも動作しますが、2桁年の問題があります。
WORKING-STORAGE SECTION.
01 WS-DATE-6 PIC 9(6). *> YYMMDD(6桁)
01 WS-DATE-8 PIC 9(8). *> YYYYMMDD(8桁)
01 WS-TIME-8 PIC 9(8). *> HHMMSSCC(8桁)
01 WS-DAY-5 PIC 9(5). *> YYDDD ユリウス通日(5桁)
01 WS-DAY-7 PIC 9(7). *> YYYYDDD ユリウス通日(7桁)
PROCEDURE DIVISION.
*--- 旧方式: 2桁年 YYMMDD(Y2K問題あり・非推奨)---
ACCEPT WS-DATE-6 FROM DATE
DISPLAY '6桁日付: ' WS-DATE-6 *> 例: 260414(2026年4月14日)
*--- 推奨: 4桁年 YYYYMMDD(COBOL 2002以降)---
ACCEPT WS-DATE-8 FROM DATE YYYYMMDD
DISPLAY '8桁日付: ' WS-DATE-8 *> 例: 20260414
*--- 時刻(HHMMSSCC: 時・分・秒・百分の1秒)---
ACCEPT WS-TIME-8 FROM TIME
DISPLAY '時刻8桁: ' WS-TIME-8 *> 例: 09304512(09:30:45.12)
*--- ユリウス通日 2桁年(非推奨)---
ACCEPT WS-DAY-5 FROM DAY
DISPLAY 'ユリウス5桁: ' WS-DAY-5 *> 例: 26104(2026年の104日目)
*--- ユリウス通日 4桁年(推奨)---
ACCEPT WS-DAY-7 FROM DAY YYYYDDD
DISPLAY 'ユリウス7桁: ' WS-DAY-7 *> 例: 2026104
STOP RUN.
| 構文 | 桁数 | 形式 | 備考 |
|---|---|---|---|
| FROM DATE | 6桁 | YYMMDD | 2桁年。2000年以降のプログラムでは使用禁止推奨 |
| FROM DATE YYYYMMDD | 8桁 | YYYYMMDD | 4桁年。現代の標準(COBOL 2002以降) |
| FROM TIME | 8桁 | HHMMSSCC | 時・分・秒・百分の1秒。4桁年問題なし |
| FROM DAY | 5桁 | YYDDD | 2桁年のユリウス通日。非推奨 |
| FROM DAY YYYYDDD | 7桁 | YYYYDDD | 4桁年のユリウス通日(COBOL 2002以降) |
ACCEPT WS-DATE FROM DATEは2桁の年(YY)を返します。2000年以降は26など2桁になるため、「2026年か1926年かが区別できない」問題が発生します。新規コーディングでは必ずFROM DATE YYYYMMDD(4桁年)を使いましょう。旧来のシステムで2桁年が使われている場合は、現在年をFUNCTION CURRENT-DATEで取得して世紀を補完するロジックが必要です。日付の加減算(INTEGER-OF-DATE・DATE-OF-INTEGER)
COBOLで日付を加減算したり2つの日付の差を計算するには、日付を通算整数に変換してから算術演算し、結果を日付に戻す手順を踏みます。
* FUNCTION INTEGER-OF-DATE(YYYYMMDD) → 整数
* 1601年1月1日からの通算日数を返す(1601-01-01 = 1)
* 例: INTEGER-OF-DATE(20260414) → 155,000前後の値
*
* FUNCTION DATE-OF-INTEGER(整数) → YYYYMMDD
* 通算日数をYYYYMMDD形式に変換して返す
* 例: DATE-OF-INTEGER(155000) → 20260119 前後の日付
WORKING-STORAGE SECTION.
01 WS-DATE-8 PIC 9(8).
01 WS-INT-DATE PIC 9(9).
01 WS-RESULT-INT PIC 9(9).
01 WS-RESULT-DATE PIC 9(8).
PROCEDURE DIVISION.
*> 現在日付を取得
ACCEPT WS-DATE-8 FROM DATE YYYYMMDD
*> YYYYMMDD → 通算整数
COMPUTE WS-INT-DATE =
FUNCTION INTEGER-OF-DATE(WS-DATE-8)
*> 30日後の日付を計算
COMPUTE WS-RESULT-INT = WS-INT-DATE + 30
*> 通算整数 → YYYYMMDD
COMPUTE WS-RESULT-DATE =
FUNCTION DATE-OF-INTEGER(WS-RESULT-INT)
DISPLAY '今日 : ' WS-DATE-8
DISPLAY '30日後 : ' WS-RESULT-DATE
STOP RUN.
WORKING-STORAGE SECTION.
01 WS-START-DATE PIC 9(8) VALUE 20260101. *> 契約開始日
01 WS-END-DATE PIC 9(8) VALUE 20261231. *> 契約終了日
01 WS-TODAY PIC 9(8).
01 WS-ELAPSED-DAYS PIC S9(9) COMP.
01 WS-REMAINING-DAYS PIC S9(9) COMP.
01 WS-INT-START PIC 9(9).
01 WS-INT-END PIC 9(9).
01 WS-INT-TODAY PIC 9(9).
PROCEDURE DIVISION.
ACCEPT WS-TODAY FROM DATE YYYYMMDD
COMPUTE WS-INT-START =
FUNCTION INTEGER-OF-DATE(WS-START-DATE)
COMPUTE WS-INT-END =
FUNCTION INTEGER-OF-DATE(WS-END-DATE)
COMPUTE WS-INT-TODAY =
FUNCTION INTEGER-OF-DATE(WS-TODAY)
*> 経過日数(開始日から今日まで)
COMPUTE WS-ELAPSED-DAYS =
WS-INT-TODAY - WS-INT-START
*> 残り日数(今日から終了日まで)
COMPUTE WS-REMAINING-DAYS =
WS-INT-END - WS-INT-TODAY
DISPLAY '経過日数: ' WS-ELAPSED-DAYS '日'
DISPLAY '残り日数: ' WS-REMAINING-DAYS '日'
IF WS-REMAINING-DAYS < 0
DISPLAY '契約期限が切れています'
ELSE IF WS-REMAINING-DAYS <= 30
DISPLAY '契約期限まで残り30日以内です'
END-IF
STOP RUN.
| 関数 | 動作 | 備考 |
|---|---|---|
| FUNCTION INTEGER-OF-DATE(date8) | YYYYMMDD形式の8桁日付 → 通算整数(1601-01-01からの日数) | 1601-01-01 = 1 |
| FUNCTION DATE-OF-INTEGER(n) | 通算整数 → YYYYMMDD形式の8桁日付 | 0以下を渡すとエラー |
| FUNCTION INTEGER-OF-DAY(date7) | YYYYDDD形式(ユリウス通日)→ 通算整数 | INTEGER-OF-DATEと同じ基点 |
| FUNCTION DAY-OF-INTEGER(n) | 通算整数 → YYYYDDD形式(ユリウス通日) |
日付のバリデーション(TEST-DATE-YYYYMMDD)
ユーザー入力やファイルから取り込んだ日付が有効かどうか確認するにはFUNCTION TEST-DATE-YYYYMMDDを使います。
* FUNCTION TEST-DATE-YYYYMMDD(date8)
* 引数: 8桁数値(YYYYMMDD形式)
* 戻り値: 0 = 有効な日付
* 1 = 日付形式が不正(月が0または13以上など)
*
* FUNCTION TEST-DAY-YYYYDDD(date7)
* 引数: 7桁数値(YYYYDDD形式)
* 戻り値: 0 = 有効 / 非0 = 不正
WORKING-STORAGE SECTION.
01 WS-INPUT-DATE PIC 9(8).
01 WS-DATE-CHECK PIC 9(4).
01 WS-ERR-MSG PIC X(80).
PROCEDURE DIVISION.
*--- ケース1: 有効な日付 ---
MOVE 20260229 TO WS-INPUT-DATE *> 2026年はうるう年ではない
PERFORM VALIDATE-DATE
*--- ケース2: 正常な日付 ---
MOVE 20260414 TO WS-INPUT-DATE
PERFORM VALIDATE-DATE
*--- ケース3: 月が不正 ---
MOVE 20261301 TO WS-INPUT-DATE *> 13月は存在しない
PERFORM VALIDATE-DATE
STOP RUN.
VALIDATE-DATE.
COMPUTE WS-DATE-CHECK =
FUNCTION TEST-DATE-YYYYMMDD(WS-INPUT-DATE)
IF WS-DATE-CHECK = 0
DISPLAY WS-INPUT-DATE ': 有効な日付です'
ELSE
DISPLAY WS-INPUT-DATE ': 無効な日付(コード=' WS-DATE-CHECK ')'
END-IF.
WORKING-STORAGE SECTION.
01 WS-RAW-DATE PIC X(8). *> 入力文字列(ファイルから)
01 WS-NUM-DATE PIC 9(8).
01 WS-VALID-FLAG PIC X(1) VALUE 'N'.
88 DATE-IS-VALID VALUE 'Y'.
PROCEDURE DIVISION.
MOVE '20260414' TO WS-RAW-DATE
PERFORM CHECK-DATE-INPUT
IF DATE-IS-VALID
DISPLAY '有効: ' WS-NUM-DATE
ELSE
DISPLAY '無効な日付入力: ' WS-RAW-DATE
END-IF
STOP RUN.
CHECK-DATE-INPUT.
MOVE 'N' TO WS-VALID-FLAG
*--- ① 8桁であることを確認 ---
IF FUNCTION LENGTH(FUNCTION TRIM(WS-RAW-DATE)) NOT = 8
EXIT PARAGRAPH
END-IF
*--- ② 全桁が数字であることを確認 ---
IF WS-RAW-DATE NOT NUMERIC
EXIT PARAGRAPH
END-IF
MOVE WS-RAW-DATE TO WS-NUM-DATE
*--- ③ 日付として有効かチェック ---
IF FUNCTION TEST-DATE-YYYYMMDD(WS-NUM-DATE) NOT = 0
EXIT PARAGRAPH
END-IF
MOVE 'Y' TO WS-VALID-FLAG.
日付のフォーマット変換
ファイルやDB、画面表示で必要な日付フォーマットに変換する方法です。STRING文と部分参照を組み合わせて実装します。
WORKING-STORAGE SECTION.
01 WS-DATE-8 PIC 9(8).
* 各形式の出力用変数
01 WS-FMT-SLASH PIC X(10). *> YYYY/MM/DD
01 WS-FMT-HYPHEN PIC X(10). *> YYYY-MM-DD
01 WS-FMT-JP PIC X(14). *> YYYY年MM月DD日
01 WS-FMT-6 PIC X(6). *> YYYYMM(年月のみ)
01 WS-DATE-EDIT PIC 9(4)/9(2)/9(2). *> 編集項目を使う方法
* 分解用ワーク変数
01 WS-DATE-PARTS.
05 WS-D-YEAR PIC X(4).
05 WS-D-MONTH PIC X(2).
05 WS-D-DAY PIC X(2).
PROCEDURE DIVISION.
ACCEPT WS-DATE-8 FROM DATE YYYYMMDD
*--- 文字列への変換: まず文字型に移動して部分参照 ---
MOVE WS-DATE-8 TO WS-DATE-PARTS *> グループに転記で自動分解
*--- YYYY/MM/DD 形式 ---
STRING WS-D-YEAR DELIMITED BY SIZE
'/' DELIMITED BY SIZE
WS-D-MONTH DELIMITED BY SIZE
'/' DELIMITED BY SIZE
WS-D-DAY DELIMITED BY SIZE
INTO WS-FMT-SLASH
DISPLAY 'スラッシュ区切り : ' WS-FMT-SLASH *> 2026/04/14
*--- YYYY-MM-DD 形式 ---
STRING WS-D-YEAR DELIMITED BY SIZE
'-' DELIMITED BY SIZE
WS-D-MONTH DELIMITED BY SIZE
'-' DELIMITED BY SIZE
WS-D-DAY DELIMITED BY SIZE
INTO WS-FMT-HYPHEN
DISPLAY 'ハイフン区切り : ' WS-FMT-HYPHEN *> 2026-04-14
*--- YYYY年MM月DD日 形式(DISPLAY文字コードが日本語対応の場合)---
STRING WS-D-YEAR DELIMITED BY SIZE
'年' DELIMITED BY SIZE
WS-D-MONTH DELIMITED BY SIZE
'月' DELIMITED BY SIZE
WS-D-DAY DELIMITED BY SIZE
'日' DELIMITED BY SIZE
INTO WS-FMT-JP
DISPLAY '日本語形式 : ' WS-FMT-JP *> 2026年04月14日
*--- 編集項目を使った方法 ---
MOVE WS-DATE-8 TO WS-DATE-EDIT
DISPLAY '編集項目形式 : ' WS-DATE-EDIT *> 2026/04/14
STOP RUN.
WORKING-STORAGE SECTION.
01 WS-DATE-8 PIC 9(8). *> YYYYMMDD
01 WS-DATE-6 PIC 9(6). *> YYYYMM(年月のみ)
01 WS-DATE-YM PIC X(6). *> 文字型 YYYYMM
01 WS-PREV-MONTH-DATE PIC 9(8). *> 前月同日
01 WS-INT-WORK PIC 9(9).
PROCEDURE DIVISION.
ACCEPT WS-DATE-8 FROM DATE YYYYMMDD
*--- YYYYMMDD → YYYYMM(日を切り捨て)---
MOVE WS-DATE-8(1:6) TO WS-DATE-YM *> 文字部分参照
DISPLAY '年月(文字): ' WS-DATE-YM
*--- YYYYMM → YYYYMM01(月初日)---
* 年月に01を足してYYYYMMDD化
STRING WS-DATE-YM DELIMITED BY SIZE
'01' DELIMITED BY SIZE
INTO WS-DATE-8
*--- 月初日の前日 = 前月末日 ---
COMPUTE WS-INT-WORK =
FUNCTION INTEGER-OF-DATE(WS-DATE-8) - 1
COMPUTE WS-PREV-MONTH-DATE =
FUNCTION DATE-OF-INTEGER(WS-INT-WORK)
DISPLAY '前月末日: ' WS-PREV-MONTH-DATE
STOP RUN.
実践パターン
年齢計算
生年月日から現在の年齢を計算します。誕生日を迎えているかどうかの判定が重要です。
WORKING-STORAGE SECTION.
01 WS-BIRTHDATE PIC 9(8) VALUE 19901225. *> 生年月日
01 WS-TODAY PIC 9(8).
01 WS-AGE PIC 9(3).
* 比較用フィールドに分解
01 WS-TODAY-PARTS.
05 WS-TODAY-YEAR PIC 9(4).
05 WS-TODAY-MD PIC 9(4). *> 月日を4桁で比較
01 WS-BIRTH-PARTS.
05 WS-BIRTH-YEAR PIC 9(4).
05 WS-BIRTH-MD PIC 9(4). *> 誕生月日を4桁で比較
PROCEDURE DIVISION.
ACCEPT WS-TODAY FROM DATE YYYYMMDD
MOVE WS-TODAY TO WS-TODAY-PARTS
MOVE WS-BIRTHDATE TO WS-BIRTH-PARTS
*--- 年齢の基本計算(年の差)---
COMPUTE WS-AGE = WS-TODAY-YEAR - WS-BIRTH-YEAR
*--- 誕生日を今年まだ迎えていない場合は1を引く ---
IF WS-TODAY-MD < WS-BIRTH-MD
SUBTRACT 1 FROM WS-AGE
END-IF
DISPLAY '生年月日: ' WS-BIRTHDATE
DISPLAY '今日 : ' WS-TODAY
DISPLAY '年齢 : ' WS-AGE '歳'
STOP RUN.
月末日の計算
月末日は月によって28・29・30・31日と異なります。「翌月1日の前日」として計算するのが最もシンプルで確実な方法です。
WORKING-STORAGE SECTION.
01 WS-TARGET-DATE PIC 9(8) VALUE 20260229. *> 対象日付
01 WS-TARGET-YM PIC 9(6).
01 WS-TARGET-YEAR PIC 9(4).
01 WS-TARGET-MONTH PIC 9(2).
01 WS-NEXT-MONTH PIC 9(2).
01 WS-NEXT-YEAR PIC 9(4).
01 WS-NEXT-MONTH-01 PIC 9(8). *> 翌月1日
01 WS-INT-WORK PIC 9(9).
01 WS-LAST-DAY PIC 9(8). *> 月末日
PROCEDURE DIVISION.
MOVE WS-TARGET-DATE TO WS-TARGET-YM
MOVE WS-TARGET-DATE(1:4) TO WS-TARGET-YEAR
MOVE WS-TARGET-DATE(5:2) TO WS-TARGET-MONTH
*--- 翌月の年月を計算 ---
IF WS-TARGET-MONTH = 12
COMPUTE WS-NEXT-YEAR = WS-TARGET-YEAR + 1
MOVE 1 TO WS-NEXT-MONTH
ELSE
MOVE WS-TARGET-YEAR TO WS-NEXT-YEAR
COMPUTE WS-NEXT-MONTH = WS-TARGET-MONTH + 1
END-IF
*--- 翌月1日をYYYYMMDD形式で組み立て ---
MOVE WS-NEXT-YEAR TO WS-NEXT-MONTH-01(1:4)
MOVE WS-NEXT-MONTH TO WS-NEXT-MONTH-01(5:2)
MOVE 1 TO WS-NEXT-MONTH-01(7:2)
*--- 翌月1日の前日 = 今月末日 ---
COMPUTE WS-INT-WORK =
FUNCTION INTEGER-OF-DATE(WS-NEXT-MONTH-01) - 1
COMPUTE WS-LAST-DAY =
FUNCTION DATE-OF-INTEGER(WS-INT-WORK)
DISPLAY '対象日付: ' WS-TARGET-DATE
DISPLAY '月末日 : ' WS-LAST-DAY
STOP RUN.
月次バッチ処理の基準日管理
月次バッチでは「処理基準日(前月末日)」を正確に求めることが重要です。実行日から前月末日・前月初日を自動計算するパターンです。
WORKING-STORAGE SECTION.
01 WS-TODAY PIC 9(8).
01 WS-TODAY-YEAR PIC 9(4).
01 WS-TODAY-MONTH PIC 9(2).
01 WS-PREV-MONTH PIC 9(2).
01 WS-PREV-YEAR PIC 9(4).
01 WS-INT-WORK PIC 9(9).
* 月次処理で使う基準日
01 WS-BASE-DATES.
05 WS-MONTH-END PIC 9(8). *> 前月末日(処理対象月の最終日)
05 WS-MONTH-START PIC 9(8). *> 前月初日(処理対象月の初日)
05 WS-TWO-AGO-END PIC 9(8). *> 2ヵ月前末日(比較用)
PROCEDURE DIVISION.
ACCEPT WS-TODAY FROM DATE YYYYMMDD
MOVE WS-TODAY(1:4) TO WS-TODAY-YEAR
MOVE WS-TODAY(5:2) TO WS-TODAY-MONTH
*--- 前月の年月を求める ---
IF WS-TODAY-MONTH = 1
COMPUTE WS-PREV-YEAR = WS-TODAY-YEAR - 1
MOVE 12 TO WS-PREV-MONTH
ELSE
MOVE WS-TODAY-YEAR TO WS-PREV-YEAR
COMPUTE WS-PREV-MONTH = WS-TODAY-MONTH - 1
END-IF
*--- 前月末日 = 今月1日の前日 ---
MOVE WS-TODAY-YEAR TO WS-MONTH-END(1:4)
MOVE WS-TODAY-MONTH TO WS-MONTH-END(5:2)
MOVE 1 TO WS-MONTH-END(7:2)
COMPUTE WS-INT-WORK =
FUNCTION INTEGER-OF-DATE(WS-MONTH-END) - 1
COMPUTE WS-MONTH-END =
FUNCTION DATE-OF-INTEGER(WS-INT-WORK)
*--- 前月初日 = 前月の1日 ---
MOVE WS-PREV-YEAR TO WS-MONTH-START(1:4)
MOVE WS-PREV-MONTH TO WS-MONTH-START(5:2)
MOVE 1 TO WS-MONTH-START(7:2)
DISPLAY '実行日 : ' WS-TODAY
DISPLAY '処理対象月初: ' WS-MONTH-START *> 例: 20260301
DISPLAY '処理対象月末: ' WS-MONTH-END *> 例: 20260331
*--- この基準日を使って処理期間内のレコードを抽出 ---
PERFORM PROCESS-MONTHLY-DATA
STOP RUN.
PROCESS-MONTHLY-DATA.
* WS-MONTH-START ≦ レコード日付 ≦ WS-MONTH-END
* の条件でファイルを読み込んで処理する
EXIT.
タイムスタンプ付きログ出力
バッチ処理のログにFUNCTION CURRENT-DATEで取得したタイムスタンプを付加するパターンです。
WORKING-STORAGE SECTION.
01 WS-TIMESTAMP PIC X(26). *> ログ用タイムスタンプ文字列
01 WS-DT.
05 WS-DT-YEAR PIC X(4).
05 WS-DT-MONTH PIC X(2).
05 WS-DT-DAY PIC X(2).
05 WS-DT-HOUR PIC X(2).
05 WS-DT-MIN PIC X(2).
05 WS-DT-SEC PIC X(2).
05 WS-DT-HUN PIC X(2).
05 FILLER PIC X(5). *> タイムゾーン部分(使わない)
01 WS-LOG-LINE PIC X(200).
PROCEDURE DIVISION.
PERFORM WRITE-LOG-LINE
USING 'INFO'
'バッチ処理を開始します'
PERFORM WRITE-LOG-LINE
USING 'DEBUG'
'ファイルのオープンに成功'
STOP RUN.
WRITE-LOG-LINE USING WS-LOG-LEVEL WS-LOG-MSG.
*--- タイムスタンプを取得して組み立て ---
MOVE FUNCTION CURRENT-DATE TO WS-DT
STRING WS-DT-YEAR DELIMITED BY SIZE
'-' DELIMITED BY SIZE
WS-DT-MONTH DELIMITED BY SIZE
'-' DELIMITED BY SIZE
WS-DT-DAY DELIMITED BY SIZE
' ' DELIMITED BY SIZE
WS-DT-HOUR DELIMITED BY SIZE
':' DELIMITED BY SIZE
WS-DT-MIN DELIMITED BY SIZE
':' DELIMITED BY SIZE
WS-DT-SEC DELIMITED BY SIZE
INTO WS-TIMESTAMP
*--- ログ行を組み立てて出力 ---
STRING '[' DELIMITED BY SIZE
WS-TIMESTAMP DELIMITED BY SPACE
'] [' DELIMITED BY SIZE
WS-LOG-LEVEL DELIMITED BY SPACE
'] ' DELIMITED BY SIZE
WS-LOG-MSG DELIMITED BY SIZE
INTO WS-LOG-LINE
DISPLAY WS-LOG-LINE.
よくある落とし穴と対策
FUNCTION CURRENT-TIMEという関数は存在しない
COBOLの標準関数にCURRENT-TIMEはありません。使うとコンパイルエラーになります。時刻情報はFUNCTION CURRENT-DATEの9〜14桁目(時・分・秒)に含まれています。
対策: FUNCTION CURRENT-DATEを使い、必要な桁を部分参照またはグループアイテムで取り出します。
ACCEPT FROM DATEで2桁年を使い続ける
2026年は「26」と返るため、世紀の判定ができず1926年と区別がつきません。旧システムのコードをそのまま流用しているケースで起きがちです。
対策: 必ずACCEPT WS-DATE FROM DATE YYYYMMDDで4桁年を取得します。コンパイラが対応していない古い環境ではFUNCTION CURRENT-DATEの1〜8桁目で代替できます。
INTEGER-OF-DATEに6桁日付を渡す
INTEGER-OF-DATE・DATE-OF-INTEGERはYYYYMMDD(8桁)形式の数値を想定しています。6桁(YYMMDD)を渡すと内部的に誤った日付として解釈され、計算結果がおかしくなります。
対策: 計算前にACCEPT FROM DATE YYYYMMDDで8桁を取得するか、FUNCTION CURRENT-DATEから1〜8桁目を取り出してから渡します。
TEST-DATE-YYYYMMDDの戻り値を確認せず使う
TEST-DATE-YYYYMMDDは0なら有効・非0なら無効という判定に使います。エラーコードの詳細を確認しないままバリデーション処理を進めると、どの入力が不正だったかが追えなくなります。
対策: 最低でも0か非0かで有効/無効を判定します。業務要件に応じてエラーコードをログに記録しておくと、後で入力不備の原因を調査しやすくなります。
2月はうるう年で29日になり、4・6・9・11月は30日です。月ごとに末日が異なるため、固定値を使うとうるう年に誤動作します。対策: 必ず
INTEGER-OF-DATE/DATE-OF-INTEGERを使った「翌月1日の前日」方式で計算します。このミスは4年に1度しか再現しないため、テストで見逃されやすい典型的なバグです。よくある質問
IF WS-DATE1 > WS-DATE2はWS-DATE1がWS-DATE2より未来の日付かどうかを正しく判定します。年が先頭にあるYYYYMMDD形式は文字列・数値いずれとして比較しても大小順序が日付順と一致するため、INTEGER-OF-DATEに変換しなくても比較だけなら直接判定できます。経過日数や日付の加減算が必要な場合はINTEGER-OF-DATE関数を使います。まとめ
COBOLの日付・時刻処理の核心は「取得・算術・検証・フォーマット」の4操作です。
| 操作 | 使う機能 | ポイント |
|---|---|---|
| 取得 | FUNCTION CURRENT-DATE | 21文字(年月日時分秒+TZ)。現代の推奨方法 |
| 取得(旧) | ACCEPT FROM DATE YYYYMMDD | 8桁YYYYMMDD。COBOL 2002以降。旧システムとの互換に使用 |
| 加減算 | INTEGER-OF-DATE / DATE-OF-INTEGER | 通算整数に変換して計算し日付に戻す |
| 検証 | FUNCTION TEST-DATE-YYYYMMDD | 0=有効。入力バリデーションの必須処理 |
| 変換 | STRING + 部分参照 | YYYY/MM/DD・YYYY年MM月DD日などへフォーマット |
| 月末日 | INTEGER-OF-DATE(翌月1日 – 1日) | 月の末日を確実に求める唯一の正解 |
特にFUNCTION CURRENT-TIMEという関数は存在しない点に注意してください。時刻はFUNCTION CURRENT-DATEの9〜14桁目に含まれています。日付の文字列操作にはSTRING/UNSTRING/INSPECTが役立ちます。詳細は文字列操作完全ガイドをご覧ください。日付バリデーションでのIF文パターンについてはIF文完全ガイドも参考にしてください。