# 帳票設計書 10-strftime 日時フォーマット

## 概要

Time#strftimeによる日時の書式指定文字列への変換に関する帳票設計書である。`%Y`/`%m`/`%d`/`%H`/`%M`/`%S`等の書式指定子をサポートし、日時オブジェクトを指定形式の文字列に変換する。

### 本帳票の処理概要

本帳票は、mrubyのTime#strftimeメソッドによる日時フォーマット文字列の生成機能である。C標準ライブラリのstrftime関数をラップし、Rubyレベルの書式指定子による日時変換を提供する。フォーマット文字列内のNULバイトも保持される。

**業務上の目的・背景**：日時データを人間が読みやすい形式や、システム間でのデータ交換に適した形式に変換するための基盤機能である。ログのタイムスタンプ生成、レポートの日付表示、ファイル名への日時付与など、日時の文字列表現が必要なあらゆる場面で使用される。

**帳票の利用シーン**：Rubyコード内でTime#strftimeメソッドを呼び出す全ての場面で使用される。例: `Time.now.strftime("%Y-%m-%d %H:%M:%S")` で `"2023-12-25 10:30:45"` のような文字列を生成。

**主要な出力内容**：
1. フォーマット指定子に基づく日時文字列変換結果
2. 主要な指定子: %Y(年4桁), %m(月2桁), %d(日2桁), %H(時24時間制), %M(分), %S(秒)
3. その他のシステムstrftimeがサポートする全指定子
4. %%によるリテラル%出力

**帳票の出力タイミング**：Time#strftimeメソッドが呼び出された際に、フォーマット済み文字列を戻り値として返す。

**帳票の利用者**：mrubyアプリケーション開発者（全般）。

## 帳票種別

フォーマット出力（メモリ上の文字列として生成）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | Rubyコード | `time.strftime(format)` | Time#strftimeメソッド呼び出し |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | mruby String オブジェクト（メモリ上） |
| 用紙サイズ | N/A |
| 向き | N/A |
| ファイル名 | N/A（戻り値として返却） |
| 出力方法 | mrb_value（String型）として返却 |
| 文字コード | UTF-8 |

### PDF固有設定

N/A

### Excel固有設定

N/A

## 帳票レイアウト

### レイアウト概要

フォーマット文字列内の`%`で始まる指定子が、Timeオブジェクトの対応する日時要素に置換された結果文字列が生成される。

```
入力: Time.new(2023,12,25,10,30,45).strftime("%Y-%m-%d %H:%M:%S")
出力: "2023-12-25 10:30:45"
```

### ヘッダー部

N/A

### 明細部

#### 主要フォーマット指定子一覧

| No | 指定子 | 説明 | 表示例 |
|----|-------|------|-------|
| 1 | %Y | 年（4桁、世紀付き） | 2023 |
| 2 | %m | 月（01-12、ゼロ埋め） | 12 |
| 3 | %d | 日（01-31、ゼロ埋め） | 25 |
| 4 | %H | 時（00-23、24時間制） | 10 |
| 5 | %M | 分（00-59） | 30 |
| 6 | %S | 秒（00-60） | 45 |
| 7 | %% | リテラル% | % |

**注意**: 上記は主要な指定子のみ。実際にはシステムのstrftime(3)がサポートする全指定子（%A, %B, %a, %b, %c, %p, %Z等）が使用可能。

### フッター部

N/A

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| Timeオブジェクト | レシーバのTimeインスタンス | Yes |
| フォーマット文字列 | %指定子を含むString | Yes |

### ソート順

N/A

### 改ページ条件

N/A

## データベース参照仕様

### 参照テーブル一覧

本帳票はデータベースを参照しない。Timeオブジェクト内部のstruct tm構造体を参照する。

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| struct tm (C構造体) | 日時情報 | mrb_time_get_tm()で取得 |

### テーブル別参照項目詳細

#### struct tm

| 参照項目（フィールド名） | 帳票項目との対応 | 取得条件 | 備考 |
|-------------------|----------------|---------|------|
| tm_year | %Y（年） | 常時 | +1900で西暦に変換 |
| tm_mon | %m（月） | 常時 | +1で1-12に変換 |
| tm_mday | %d（日） | 常時 | 1-31 |
| tm_hour | %H（時） | 常時 | 0-23 |
| tm_min | %M（分） | 常時 | 0-59 |
| tm_sec | %S（秒） | 常時 | 0-60（閏秒含む） |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| セグメント長 | NULバイトまでの距離または残り長さ | なし | memchrで検索 |
| バッファサイズ | MAX_BUFFER_SIZE (4096) 固定 | なし | システムstrftimeの出力上限 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[Time#strftime呼び出し] --> B[フォーマット文字列取得 mrb_get_args]
    B --> C[struct tm取得 mrb_time_get_tm]
    C --> D[空文字列で結果初期化]
    D --> E{残りフォーマットあり?}
    E -->|Yes| F[NULバイト検索 memchr]
    F --> G{NULバイトあり?}
    G -->|Yes| H[NULまでのセグメント処理]
    G -->|No| I[残り全体をセグメント処理]
    H --> J[セグメントのNULL終端コピー作成]
    I --> J
    J --> K[strftime でフォーマット変換]
    K --> L[結果文字列に追記 mrb_str_cat]
    L --> M{NULバイトあり?}
    M -->|Yes| N[NULバイトを結果に追加]
    N --> O[ポインタ前進]
    O --> E
    M -->|No| P[ループ終了]
    E -->|No| P
    P --> Q[結果文字列を返却]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| 引数エラー | フォーマット文字列が渡されない | TypeError（mrb_get_args "s"） | String引数を渡す |
| MSVCプラットフォーム制約 | %-フラグ使用時（MSVC環境） | `strftime format flag '%-' not supported on this platform` | %#を使用 |
| バッファオーバーフロー | strftime出力が4096バイトを超える場合 | strftimeが0を返す | フォーマット文字列を短縮 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 1回の呼び出しで1文字列を生成 |
| 目標出力時間 | マイクロ秒単位 |
| 同時出力数上限 | N/A |

## セキュリティ考慮事項

- フォーマット文字列はユーザー入力をそのまま渡さないことを推奨
- MAX_BUFFER_SIZE(4096)の制限によりバッファオーバーフローは防止されている
- mrb_temp_allocを使用しているため、例外発生時のメモリリークが防止されている

## 備考

- フォーマット文字列内のNULバイト（\0）は保持される。memchrでNULを検出し、セグメント分割して処理する
- 実際のフォーマット変換はシステムのCライブラリstrftime(3)に委譲されるため、サポートされる指定子はプラットフォームに依存する
- MSVC環境では%-フラグ（ゼロ埋めなし）が未サポートのため、専用のエラーチェックが追加されている
- mrb_temp_allocを使用して一時バッファを確保しており、例外安全性を確保している
- MAX_BUFFER_SIZEは4096バイト固定

---

## コードリーディングガイド

本帳票を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | time.h | `include/mruby/time.h` | mruby Timeオブジェクトのデータ構造、mrb_time_get_tm関数宣言 |
| 1-2 | strftime.c | `mrbgems/mruby-strftime/src/strftime.c` | MAX_BUFFER_SIZE定数（15行目）: 4096 |

**読解のコツ**: この関数はシンプルなラッパーで、核心はC標準ライブラリのstrftime(3)への委譲にある。NULバイト処理のセグメント分割ロジックが唯一の複雑なポイント。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | strftime.c | `mrbgems/mruby-strftime/src/strftime.c` | `mrb_time_strftime`（42-105行目）: メイン処理関数 |
| 2-2 | strftime.c | `mrbgems/mruby-strftime/src/strftime.c` | `mrb_mruby_strftime_gem_init`（108-114行目）: gem初期化。Time#strftimeメソッド登録 |

**主要処理フロー**:
1. **47行目**: mrb_get_argsでフォーマット文字列を取得
2. **48行目**: mrb_time_get_tmでstruct tmを取得
3. **50行目**: 空のmruby Stringオブジェクトで結果を初期化
4. **55行目**: whileループでフォーマット文字列をNULバイトで分割処理
5. **56行目**: memchrでNULバイトを検索
6. **67-69行目**: セグメントをNULL終端のコピーに変換（mrb_temp_alloc使用）
7. **84-87行目**: strftime()でフォーマット変換
8. **90行目**: 結果文字列に追記
9. **94-97行目**: NULバイトがあれば結果に追加してポインタ前進

#### Step 3: gem登録を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | strftime.c | `mrbgems/mruby-strftime/src/strftime.c` | 113行目: `mrb_define_method_id(mrb, time_class, MRB_SYM(strftime), mrb_time_strftime, MRB_ARGS_REQ(1))` |

### プログラム呼び出し階層図

```
mrb_time_strftime() [strftime.c:42]
    │
    ├─ mrb_get_args("s") ← フォーマット文字列取得
    ├─ mrb_time_get_tm() ← struct tm取得
    ├─ mrb_str_new() ← 空結果文字列生成
    │
    └─ (NULバイト分割ループ)
           ├─ memchr() ← NULバイト検索
           ├─ mrb_temp_alloc() ← セグメントコピー確保
           ├─ strftime() ← C標準ライブラリの日時フォーマット
           └─ mrb_str_cat() ← 結果追記
```

### データフロー図

```
[入力]                       [処理]                         [出力]

Time オブジェクト ──▶ mrb_time_get_tm() ──▶ struct tm
フォーマット文字列 ──▶ NULバイト分割 ──▶ セグメント群

struct tm +          strftime()            mrb_value (String)
セグメント ─────▶ (C標準ライブラリ) ──────▶ フォーマット済み文字列
                     ↓
                  mrb_str_cat()
                     ↓
                  結果文字列に連結
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| strftime.c | `mrbgems/mruby-strftime/src/strftime.c` | ソース | Time#strftimeのコア実装 |
| time.h | `include/mruby/time.h` | ヘッダー | mruby Time関連定義、mrb_time_get_tm関数宣言 |
| string.h | `include/mruby/string.h` | ヘッダー | mruby String操作関数 |
| class.h | `include/mruby/class.h` | ヘッダー | mrb_class_get_id関数（Timeクラス取得用） |
