【COBOL】日付・時刻の扱い方完全ガイド|CURRENT-DATE・日付算術・月末日計算・年齢計算・バリデーション

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の戻り値の構造
*  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'
FUNCTION CURRENT-DATEの基本的な使い方
       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.
GROUPアイテムへの直接MOVEが最もシンプル
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桁年の問題があります。

ACCEPT FROM DATE/TIME/DAYの各形式
       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 FROM DATEの2桁年問題(Y2K)
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つの日付の差を計算するには、日付を通算整数に変換してから算術演算し、結果を日付に戻す手順を踏みます。

INTEGER-OF-DATEとDATE-OF-INTEGERの仕組み
*  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.
2つの日付の差(経過日数)を計算する
       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を使います。

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文と部分参照を組み合わせて実装します。

8桁数値日付からフォーマット文字列への変換
       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.
yyyymmdd形式と6桁形式の相互変換
       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日の前日」として計算するのが最もシンプルで確実な方法です。

月末日の計算(翌月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-DATEDATE-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かで有効/無効を判定します。業務要件に応じてエラーコードをログに記録しておくと、後で入力不備の原因を調査しやすくなります。

月末日を28/30/31と決め打ちしない
2月はうるう年で29日になり、4・6・9・11月は30日です。月ごとに末日が異なるため、固定値を使うとうるう年に誤動作します。対策: 必ずINTEGER-OF-DATE/DATE-OF-INTEGERを使った「翌月1日の前日」方式で計算します。このミスは4年に1度しか再現しないため、テストで見逃されやすい典型的なバグです。

よくある質問

QCOBOLにはDATE型やTIMESTAMP型のデータ型はありますか?
ACOBOLには日付専用のデータ型はありません。日付はPIC 9(8)(YYYYMMDD形式)やPIC X(8)として文字型・数値型で管理します。データベース連携(DB2・Oracle等)では埋め込みSQL(EXEC SQL)を通じてDATE型・TIMESTAMP型を扱えますが、COBOL自体の変数としては数値型・文字型で保持し、SQL処理時に変換します。
Qユリウス通日(FROM DAY)はどんな場面で使いますか?
Aユリウス通日(YYYYDDD)は「1年の何日目か」を表す形式です。主にJCL(ジョブ制御言語)やファイル名に日付を埋め込むバッチ処理で使われます。例えば2026年4月14日(2026年の104日目)はYYYYDDD形式で2026104になります。業務処理での日付計算にはYYYYMMDD形式の方が一般的で、ユリウス通日は特定の用途に限られます。
Q和暦(令和・平成)への変換はどうやって行いますか?
A標準COBOLには和暦変換の組み込み関数はないため、自前で変換ロジックを実装します。基本的なアプローチは、西暦年から各元号の開始年(昭和25年=1950・平成1年=1989・令和1年=2019)を引いて元号内の年数を求めます。元号の切り替え日(4月1日や5月1日)も考慮が必要で、月日まで含めた比較が必要です。多くの場合、和暦変換は共通サブプログラムとして切り出して管理します。
QFUNCTION CURRENT-DATEのタイムゾーン情報は何に使いますか?
Aタイムゾーンオフセット(17〜21桁目)は、サーバーのローカル時刻をUTC(協定世界時)に変換するときに使います。日本のサーバーであれば通常+0900(JST、UTC+9)が返ります。タイムゾーンが0(UTCサーバー)の場合は17桁目が「0」になります。グローバル対応システムや複数タイムゾーンを跨ぐバッチ処理では、タイムゾーン情報を使ってUTC基準に正規化した上で処理します。
Q過去日付や未来日付の比較はどのようにやりますか?
AYYYYMMDD形式の8桁数値はそのまま比較演算子(IF/EVALUATE)で大小比較できます。例えば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文完全ガイドも参考にしてください。