decentworks-date-support 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +81 -0
  3. data/LICENSE +1 -1
  4. data/README.md +245 -40
  5. data/lib/decentworks/date_support/configuration.rb +19 -18
  6. data/lib/decentworks/date_support/date.rb +4 -541
  7. data/lib/decentworks/date_support/date_extension.rb +761 -0
  8. data/lib/decentworks/date_support/date_time.rb +9 -0
  9. data/lib/decentworks/date_support/time.rb +7 -0
  10. data/lib/decentworks/date_support/time_extension.rb +742 -0
  11. data/lib/decentworks/date_support/time_with_zone.rb +12 -0
  12. data/lib/decentworks/date_support/version.rb +1 -1
  13. data/lib/decentworks/date_support.rb +5 -1
  14. data/lib/generators/decentworks/date_support/install/templates/decentworks_date_support.rb.tt +4 -6
  15. data/sig/decentworks/date_support/configuration.rbs +12 -3
  16. data/sig/decentworks/date_support/date.rbs +3 -167
  17. data/sig/decentworks/date_support/date_extension.rbs +244 -0
  18. data/sig/decentworks/date_support/date_time.rbs +4 -0
  19. data/sig/decentworks/date_support/time.rbs +4 -0
  20. data/sig/decentworks/date_support/time_extension.rbs +248 -0
  21. data/sig/decentworks/date_support/time_with_zone.rbs +21 -0
  22. data/sig/decentworks/date_support/version.rbs +5 -0
  23. metadata +14 -13
  24. data/.rspec +0 -3
  25. data/.rubocop.yml +0 -8
  26. data/.ruby-version +0 -1
  27. data/CODE_OF_CONDUCT.md +0 -132
  28. data/LICENSE.txt +0 -21
  29. data/Rakefile +0 -12
  30. data/Steepfile +0 -43
  31. data/lib/decentworks/active_support/time_with_zone_support.rb +0 -541
  32. data/rbs_collection.lock.yaml +0 -288
  33. data/rbs_collection.yaml +0 -41
  34. data/sig/decentworks/active_support/time_with_zone_support.rbs +0 -163
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ecd2667a864d2b7d807244bea27aa807fcb2f23f425766efef2544be928650ae
4
- data.tar.gz: 8f256c1fefaf7f66e8dd79b761f160d32c29dcee7b9bada4f4f02cb91e256657
3
+ metadata.gz: 9fd4d5c85f88dab4e48fc0615c6af875f4346639db3d4168a94d0567e734479c
4
+ data.tar.gz: 8c4ce5cff95105b88ef738bfb258353d93320e0f0caf8f7371c0e39974ce54f6
5
5
  SHA512:
6
- metadata.gz: a1b3b1e9af91fb7cb31cc3e1ff97352a411d8bf9bc086e60cebd318a2fcefb0763951c19248123392d69284399f207f8b7a3c9bcb3d3c0dc1d4031bd7c709ecf
7
- data.tar.gz: 873b03a25a370618596c948f8e061d6cfaf93d0cca9ff150b3bd07609c4121aff7e5edfdcc210604a346127d4c1dd27134feeb1af6ac074e11d82e69bf551d5b
6
+ metadata.gz: 1fbc8fdec0e128b4d27a94bc828570320a0660a09c9943a3a78f03c5666df94a5e21ff1227bf9384669160bbe11e9cb9c4baf3fc3e52d6150c65dcd6675c1ecf
7
+ data.tar.gz: 2e047a1b93c5fb78b41dfb771189743c26301988cce9665f4fe5e04ca28e1ea977dfc29d00cd2eda157cfa40f376b86a79469d8b4d9ab84cecef8c5dd2e84aa2
data/CHANGELOG.md CHANGED
@@ -1,3 +1,84 @@
1
+ # [0.2.0]
2
+
3
+ ## 拡張方式
4
+
5
+ - [refineを廃止する #11](https://github.com/SrDecentWorks/decentworks-date-support/issues/11)
6
+ - refinementsをやめ、対象クラスの再オープンと拡張モジュールのincludeによる拡張に変更(`using`の記述が不要)
7
+ - `::Date` … `Decentworks::DateSupport::DateExtension`
8
+ - `::Time` / `::DateTime` / `::ActiveSupport::TimeWithZone` … `Decentworks::DateSupport::TimeExtension`
9
+ - モジュール定義(`date_extension.rb` / `time_extension.rb`)と対象クラスへのinclude
10
+ (`date.rb` / `time.rb` / `date_time.rb` / `time_with_zone.rb`)にファイルを分割
11
+ - `whole_months_elapsed` は各モジュールの `ClassMethods` 経由で提供
12
+ (`expiration_date` は非公開クラスメソッド)
13
+
14
+ ## 破壊的変更
15
+
16
+ - 設定メソッドをリネーム
17
+ - `Configuration#beginning_of_first_quarter` / `=` → `first_quarter_month_name` / `=`
18
+ - `Configuration#beginning_of_first_quarter_month` → `first_quarter_month`
19
+ - `::Decentworks::DateSupport` 側の委譲メソッドも同様にリネーム
20
+ - `::Date#beginning_of_first_quarter`(期首の日付)と同名で戻り値が異なっていたことによる混同を解消するため
21
+ - 旧名は残していないため、初期化ファイル(`config.beginning_of_first_quarter =`)の修正が必要
22
+ - ActiveSupportの四半期メソッドを、設定を反映した値を返すよう上書き
23
+ - `quarter` / `beginning_of_quarter` / `end_of_quarter` / `all_quarter` は暦年基準ではなく
24
+ `first_quarter_month_name` の設定に従う
25
+ - `next_quarter` / `prev_quarter` は3ヶ月後・3ヶ月前の同日ではなく、次/前の四半期の期首を返す
26
+ - ActiveSupportが`alias`で定義している `at_beginning_of_quarter` / `at_end_of_quarter` /
27
+ `last_quarter` は本体の上書きに追従しないため、あわせてメソッド定義で上書き
28
+
29
+ ## 追加
30
+
31
+ - 現在の日付が属する四半期・上下期・年度を取得するメソッド
32
+ - `this_quarter_number` / `beginning_of_this_quarter` / `end_of_this_quarter` / `all_this_quarter`
33
+ - `this_half_number` / `beginning_of_this_half` / `end_of_this_half` / `all_this_half`
34
+ - `fiscal_year` / `beginning_of_fiscal_year` / `end_of_fiscal_year` / `all_fiscal_year`
35
+ - 次の期間・前の期間を取得するメソッド
36
+ - 四半期: `beginning_of_next_quarter` / `end_of_next_quarter` / `all_next_quarter` と `prev` 版
37
+ - 上下期: `beginning_of_next_half` / `end_of_next_half` / `all_next_half` と `prev` 版
38
+ - 年度: `next_fiscal_year` / `beginning_of_next_fiscal_year` / `end_of_next_fiscal_year` /
39
+ `all_next_fiscal_year` と `prev` 版
40
+ - `beginning_of_this_month` / `end_of_this_month`
41
+ - `all_this_month` のみ定義されており、`*_this_*` の命名に揃える方針と不整合だったため
42
+ - ActiveSupportの `beginning_of_month` / `end_of_month` と同じ値を返す
43
+
44
+ ## 修正
45
+
46
+ - 満経過月数(`whole_months_elapsed`)の月末・閏日・逆順の扱い
47
+ - 民法第140条(初日不算入)・第143条第2項に従い、応当日ではなく満了日で判定するよう変更
48
+ (`from`が月末日の場合、満了日も月の末日になる)
49
+ - `::Time` / `::DateTime` / `::ActiveSupport::TimeWithZone` 版は日付単位で判定し、時刻を考慮しない
50
+ - 別名メソッドを`alias_method`からメソッド定義に変更(本体メソッドの差し替えに追従)
51
+
52
+ ## 型定義・型検査
53
+
54
+ - Steepの設定を修正し、型検査が実際に機能する状態にした(`library "date"` / `library "activesupport"`)
55
+ - `TimeExtension` をgeneric module(`TimeExtension[T < TimeExtension[T]]`)として宣言
56
+ - 戻り値を `self` ではなく型引数 `T` で表す。`self` ではモジュール内部のレシーバ省略呼び出しが
57
+ モジュール自身の型に解決され `MethodBodyTypeMismatch` になるが、型引数であれば一致する
58
+ - 型引数の上限をモジュール自身にすることで、`T` の値に対してモジュール自身のメソッドと
59
+ 自己型(`_DateTimeCalculations[T]`)由来のメソッドの両方を呼べる
60
+ - `sig` の `include` は `TimeExtension[::Time]` のように具体的なクラスを渡す
61
+ - `DateExtension` は `::Date` にのみincludeするため、自己型に `_DateCalculations`(戻り値は `::Date`)を指定
62
+ - 結果として `# steep:ignore` は0件
63
+ - Railsジェネレータ(`lib/generators`)も型検査の対象に含めた
64
+ - gem_rbs_collection の railties は `Rails::Generators::Base#template` がブロック必須で
65
+ 正しいコードが型エラーになるため使わず、実際に使うメソッドだけを自前で宣言
66
+ - 第三者のクラスのスタブを配布物に含めないよう、`sig-external/` に置いて
67
+ Steepfileの `signature` に追加(gemに同梱するのは `sig/` のみ)
68
+
69
+ ## gemの配布
70
+
71
+ - 同梱するファイルの指定を除外方式からホワイトリスト方式に変更
72
+ - `lib/` `sig/` `exe/` と `README.md` `CHANGELOG.md` `LICENSE` のみを配布
73
+ - `.claude/` `.rubocop.yml` `.ruby-version` `.rspec` `Steepfile` `rbs_collection*.yaml`
74
+ `CODE_OF_CONDUCT.md` などの開発用ファイルが同梱されていたため
75
+ - 重複していたライセンスファイルを `LICENSE` に統一(`LICENSE.txt` を削除)
76
+ - 著作者表記が `yutaka.mizomoto` / `YutakaMizomoto` で不一致だったため、
77
+ gemspecの`authors`に合わせて `decentworks` に統一
78
+ - gemspecの`email`を設定(未設定だったため`gem build`で警告が出ていた)
79
+ - gemspecに`rubygems_mfa_required`を追加(gem pushに多要素認証を必須にする)
80
+ - 開発依存から`rspec-rails`を除外(`railties`のみに変更)
81
+
1
82
  # [0.1.1]
2
83
 
3
84
  - [四半期、上下期の開始日を設定できるようにする #1](https://github.com/SrDecentWorks/decentworks-date-support/issues/1)
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 yutaka.mizomoto
3
+ Copyright (c) 2026 decentworks
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,84 +1,118 @@
1
- # Decentworks::Date::Support - 日付機能拡張ライブラリ
1
+ # Decentworks::DateSupport - 日付機能拡張ライブラリ
2
2
 
3
- ## はじめに
4
-
5
- このgemは、個人開発用です。
6
- そのため、予告なく仕様の追加・変更・削除が行われます。
7
- もちろん、このgemを使用したことによるバグなどの責任は負えません。
3
+ > [!IMPORTANT]
4
+ > 本ライブラリは個人によって開発・保守されています。予告なく仕様変更または提供を終了する場合があります。ご利用にあたってはバージョンを固定のうえ、更新時は変更内容をご確認ください。
8
5
 
9
6
  ## 概要
10
7
 
11
- Railsの`Date`、`ActiveSupport::TimeWithZone`に対する機能拡張を行います。
8
+ `::Date` / `::Time` / `::DateTime` / `::ActiveSupport::TimeWithZone` に対して、四半期・上下期・年度・暦月などの日付操作メソッドを追加するRuby gemです。
9
+
10
+ 第1四半期の開始月を設定できるため、1月始まり以外の会計年度(4月始まりなど)にも対応します。
12
11
 
13
- ## refinements
12
+ ## 特徴
14
13
 
15
- gemによる影響範囲を限定するため、refinementsを採用しています。
16
- 利用する場合は、適切なスコープで`using`を利用してください。
14
+ - 四半期・上下期・年度の期首/期末/期間を取得(開始月は設定で変更可能)
15
+ - 次の四半期・前の年度など、隣接する期間の取得
16
+ - 暦月(1月〜12月)の月初/月末/期間の取得と判定
17
+ - Nヶ月前・Nヶ月後の取得メソッド
18
+ - ActiveSupportの四半期メソッド(`quarter` / `beginning_of_quarter` など)を設定を反映した値に上書き
19
+ - 民法(初日不算入・応当日前日満了)に従った満経過月数の計算
20
+ - `using` 不要(`require` した時点でアプリケーション全体に適用)
21
+ - RBS型定義同梱
17
22
 
18
- ## 機能
23
+ ## 要件
19
24
 
20
- ### Dateクラス拡張
25
+ - Ruby >= 4.0.0
26
+ - ActiveSupport ~> 8.1
21
27
 
22
- #### using
28
+ ## インストール
29
+
30
+ Gemfileに追加します。
23
31
 
24
32
  ```ruby
25
- using ::Decentworks::DateSupport
33
+ gem 'decentworks-date-support'
26
34
  ```
27
35
 
28
- ### ActiveSupport::TimeWithZoneクラス拡張
36
+ ```shell
37
+ bundle install
38
+ ```
29
39
 
30
- #### using
40
+ ## 拡張方式
31
41
 
32
- ```ruby
33
- using ::Decentworks::ActiveSupport::TimeWithZoneSupport
34
- ```
42
+ `::Date` / `::Time` / `::DateTime` / `::ActiveSupport::TimeWithZone` の各クラスを再オープン(reopen)し、拡張モジュールをincludeしてメソッドを追加します。`require` した時点でアプリケーション全体に適用されるため、`using` の記述は不要です。
35
43
 
44
+ | 対象クラス | 拡張モジュール |
45
+ | --- | --- |
46
+ | `::Date` | `Decentworks::DateSupport::DateExtension` |
47
+ | `::Time` / `::DateTime` / `::ActiveSupport::TimeWithZone` | `Decentworks::DateSupport::TimeExtension` |
36
48
 
37
- ### 週関係
49
+ `TimeExtension` をincludeする3クラスは、同じメソッドを同じ仕様で提供します。各メソッドはレシーバと同じクラスの値を返します(`::Time#beginning_of_january` は `::Time`、`::DateTime#beginning_of_january` は `::DateTime`)。
38
50
 
39
- - 週の始まりの曜日を指定しての日付・期間の取得
51
+ `::Date` は日付のみを扱うため、`::Date` のメソッドは `::Date` を返します。
40
52
 
41
- ### 月関係
53
+ ### 判定メソッド(`?` 付き)の`::Date`と日時クラスの違い
42
54
 
43
- - Nヶ月前、Nヶ月後の日付の取得メソッドの追加
44
- - 暦月の日付・期間の取得メソッドの追加
55
+ `beginning_of_january?` / `end_of_january?` のような**期首・期末の判定メソッド**は、`::Date` と日時クラスで判定の粒度が異なります。
45
56
 
46
- ### 四半期関係
57
+ | レシーバ | 判定内容 | `2026-01-01 12:34:56` の場合 |
58
+ | --- | --- | --- |
59
+ | `::Date` | その日付ちょうどか(`self == beginning_of_january`) | ― |
60
+ | `::Time` / `::DateTime` / `::ActiveSupport::TimeWithZone` | その日のうちか(時刻は問わない) | `true` |
47
61
 
48
- - 第1四半期〜第4四半期の日付・期間の取得メソッドの追加
62
+ 日時クラスで「`2026-01-01 00:00:00` ちょうどか」を判定したい場合は、`beginning_of_january == self` のように値そのものを比較してください。
49
63
 
50
- ### 上下期関係
64
+ 期間の判定メソッド(`in_january?` / `in_first_quarter?` など)は、どのクラスでも期間に含まれるかを判定するため差はありません。
51
65
 
52
- - 上期〜下期の日付・期間の取得メソッドの追加
66
+ > [!WARNING]
67
+ > v0.2.0でrefinementsからクラス再オープンに変更しました。v0.1.1以前から移行する場合は、`using ::Decentworks::DateSupport` と `using ::Decentworks::ActiveSupport::TimeWithZoneSupport` の記述をすべて削除してください。
53
68
 
54
- ### その他
69
+ ## 設定
55
70
 
56
- - 満経過月数の計算
71
+ 第1四半期(上期)の開始月を指定します。初期値は `:january`(1月始まり)で、**設定を行わなくてもそのまま利用できます**。
57
72
 
58
- ## インストール
73
+ ```ruby
74
+ ::Decentworks::DateSupport.configure do |config|
75
+ config.first_quarter_month_name = :april # 4月始まり
76
+ end
77
+ ```
78
+
79
+ 指定可能な値は `:january` 〜 `:december` です。それ以外を指定した場合は `ArgumentError` が発生します。
80
+
81
+ > [!WARNING]
82
+ > 設定メソッド名を `beginning_of_first_quarter` から `first_quarter_month_name` に変更しました。`::Date#beginning_of_first_quarter`(第1四半期の期首の**日付**)と同名でありながら戻り値が月名のシンボルで、混同を招いていたためです。旧名は残していないため、初期化ファイルの記述を修正してください。
83
+
84
+ | 設定値 | 第1四半期 | 第2四半期 | 第3四半期 | 第4四半期 | 上期 | 下期 |
85
+ | --- | --- | --- | --- | --- | --- | --- |
86
+ | `:january` | 1〜3月 | 4〜6月 | 7〜9月 | 10〜12月 | 1〜6月 | 7〜12月 |
87
+ | `:april` | 4〜6月 | 7〜9月 | 10〜12月 | 翌1〜3月 | 4〜9月 | 10〜翌3月 |
88
+ | `:july` | 7〜9月 | 10〜12月 | 翌1〜3月 | 翌4〜6月 | 7〜12月 | 翌1〜6月 |
89
+ | `:october` | 10〜12月 | 翌1〜3月 | 翌4〜6月 | 翌7〜9月 | 10〜翌3月 | 翌4〜9月 |
90
+
91
+ その他の設定用APIは以下のとおりです。
59
92
 
60
93
  ```ruby
61
- gem 'decentworks-date-support'
94
+ ::Decentworks::DateSupport.first_quarter_month_name # => :april
95
+ ::Decentworks::DateSupport.first_quarter_month # => 4
96
+ ::Decentworks::DateSupport.first_quarter_month_offset # => 3
97
+ ::Decentworks::DateSupport.reset_configuration! # 設定を初期値に戻す
62
98
  ```
63
99
 
64
100
  ### 初期化ファイルの生成(Rails)
65
101
 
66
- Railsから利用する場合は、以下のジェネレータで`config/initializers/decentworks_date_support.rb`を生成できます。
102
+ Railsから利用する場合は、以下のジェネレータで `config/initializers/decentworks_date_support.rb` を生成できます。
67
103
 
68
104
  ```shell
69
105
  bin/rails generate decentworks:date_support:install
70
106
  ```
71
107
 
72
- - 初期値は1月始まりです。
108
+ - 1月始まりのまま利用する場合、この初期化ファイルは不要です。
73
109
  - その他の月に変更したい場合は、ファイルの内容を修正してください。
74
110
 
75
- ## 使い方の例
111
+ ## 使い方
76
112
 
77
113
  ```ruby
78
114
  require 'decentworks/date_support'
79
115
 
80
- using ::Decentworks::DateSupport
81
-
82
116
  d = ::Date.new(2026, 8, 5)
83
117
  d.all_this_week # => Mon, 03 Aug 2026..Sun, 09 Aug 2026
84
118
  ```
@@ -86,8 +120,179 @@ d.all_this_week # => Mon, 03 Aug 2026..Sun, 09 Aug 2026
86
120
  ```ruby
87
121
  require 'decentworks/date_support'
88
122
 
89
- using ::Decentworks::ActiveSupport::TimeWithZoneSupport
123
+ t = ::Time.zone.local(2026, 8, 5)
124
+ t.all_this_week # => 2026-08-03 00:00:00.000000000 JST +09:00..2026-08-09 23:59:59.999999999 JST +09:00
125
+ ```
90
126
 
91
- d = ::Time.zone.local(2026, 8, 5)
92
- d.all_this_week # => 2026-08-03 00:00:00.000000000 JST +09:00..2026-08-09 23:59:59.999999999 JST +09:00
127
+ ```ruby
128
+ require 'decentworks/date_support'
129
+
130
+ ::Decentworks::DateSupport.configure do |config|
131
+ config.first_quarter_month_name = :april
132
+ end
133
+
134
+ d = ::Date.new(2026, 1, 15)
135
+ d.fiscal_year # => 2025
136
+ d.this_quarter_number # => 4
137
+ d.all_this_quarter # => Thu, 01 Jan 2026..Tue, 31 Mar 2026
138
+ d.this_half_number # => 2
139
+ d.all_this_half # => Wed, 01 Oct 2025..Tue, 31 Mar 2026
140
+ d.all_fiscal_year # => Tue, 01 Apr 2025..Tue, 31 Mar 2026
93
141
  ```
142
+
143
+ ## メソッド一覧
144
+
145
+ 以下のメソッドは `::Date` / `::Time` / `::DateTime` / `::ActiveSupport::TimeWithZone` の全クラスで利用できます。
146
+
147
+ ### 週関係
148
+
149
+ | メソッド | 内容 |
150
+ | --- | --- |
151
+ | `beginning_of_this_week` | 週の始まりの日付 |
152
+ | `end_of_this_week` | 週の終わりの日付 |
153
+ | `all_this_week` | 今週の期間 |
154
+
155
+ 週の始まりは `::Date.beginning_of_week` の設定に従います。
156
+
157
+ ### 月関係
158
+
159
+ | メソッド | 内容 |
160
+ | --- | --- |
161
+ | `beginning_of_this_month` / `end_of_this_month` / `all_this_month` | 現在の日付が属する月の月初 / 月末 / 期間 |
162
+ | `two_months_ago` 〜 `eleven_months_ago` | Nヶ月前の日付(2〜11) |
163
+ | `two_months_since` 〜 `eleven_months_since` | Nヶ月後の日付(2〜11) |
164
+ | `half_year_ago` / `half_year_since` | 半年前 / 半年後の日付(`six_months_ago` / `six_months_since` の別名) |
165
+
166
+ 1ヶ月前・1ヶ月後は定義していません。ActiveSupportの `prev_month` / `next_month` のほうが名前として分かりやすいため、そちらを使ってください。
167
+
168
+ 暦月については、1月〜12月それぞれに以下のメソッドがあります(例は1月)。
169
+
170
+ | メソッド | 内容 |
171
+ | --- | --- |
172
+ | `beginning_of_january` | 1月の月初 |
173
+ | `end_of_january` | 1月の月末 |
174
+ | `all_january` | 1月の期間 |
175
+ | `beginning_of_january?` | 1月の月初か? |
176
+ | `end_of_january?` | 1月の月末か? |
177
+ | `in_january?` | 1月か? |
178
+
179
+ ### 四半期関係
180
+
181
+ | メソッド | 内容 |
182
+ | --- | --- |
183
+ | `this_quarter_number` | 現在の日付が属する四半期の番号(1〜4) |
184
+ | `beginning_of_this_quarter` / `end_of_this_quarter` / `all_this_quarter` | 現在の日付が属する四半期の期首 / 期末 / 期間 |
185
+ | `beginning_of_next_quarter` / `end_of_next_quarter` / `all_next_quarter` | 次の四半期の期首 / 期末 / 期間 |
186
+ | `beginning_of_prev_quarter` / `end_of_prev_quarter` / `all_prev_quarter` | 前の四半期の期首 / 期末 / 期間 |
187
+
188
+ 第1〜第4四半期それぞれに以下のメソッドがあります(例は第1四半期)。
189
+
190
+ | メソッド | 内容 |
191
+ | --- | --- |
192
+ | `beginning_of_first_quarter` | 第1四半期の期首 |
193
+ | `end_of_first_quarter` | 第1四半期の期末 |
194
+ | `all_first_quarter` | 第1四半期の期間 |
195
+ | `beginning_of_first_quarter?` | 第1四半期の期首か? |
196
+ | `end_of_first_quarter?` | 第1四半期の期末か? |
197
+ | `in_first_quarter?` | 第1四半期か? |
198
+
199
+ `first` を `second` / `third` / `fourth` に置き換えたメソッドが同様に定義されています。
200
+
201
+ #### ActiveSupportの四半期メソッドの上書き
202
+
203
+ ActiveSupportの四半期メソッドは**暦年基準(1月・4月・7月・10月始まり固定)**で、`first_quarter_month_name` の設定を参照しません。
204
+ 本ライブラリはこれらを設定を反映した値を返すよう上書きします。
205
+
206
+ | メソッド | 上書き後の内容 |
207
+ | --- | --- |
208
+ | `quarter` | `this_quarter_number` と同じ |
209
+ | `beginning_of_quarter` / `at_beginning_of_quarter` | `beginning_of_this_quarter` と同じ |
210
+ | `end_of_quarter` / `at_end_of_quarter` | `end_of_this_quarter` と同じ |
211
+ | `all_quarter` | `all_this_quarter` と同じ |
212
+ | `next_quarter` | `beginning_of_next_quarter` と同じ |
213
+ | `prev_quarter` / `last_quarter` | `beginning_of_prev_quarter` と同じ |
214
+
215
+ `next_quarter` / `prev_quarter` / `last_quarter` は、ActiveSupportでは3ヶ月後・3ヶ月前の**同日**を返しますが、
216
+ 本ライブラリでは期間ベースに揃えて**期首**を返します。
217
+
218
+ > [!WARNING]
219
+ > `at_beginning_of_quarter` / `at_end_of_quarter` / `last_quarter` はActiveSupportが `alias` で定義しているため、
220
+ > 本体を上書きしただけでは追従しません。値が食い違わないよう本ライブラリ側でメソッド定義として上書きしています。
221
+ >
222
+ > 暦年基準の四半期が必要な場合は、上書きの影響を受けない `beginning_of_year` からの算出など別の手段を使ってください。
223
+
224
+ ### 上下期関係
225
+
226
+ | メソッド | 内容 |
227
+ | --- | --- |
228
+ | `this_half_number` | 現在の日付が属する期の番号(1〜2) |
229
+ | `beginning_of_this_half` / `end_of_this_half` / `all_this_half` | 現在の日付が属する期の期首 / 期末 / 期間 |
230
+ | `beginning_of_next_half` / `end_of_next_half` / `all_next_half` | 次の期の期首 / 期末 / 期間 |
231
+ | `beginning_of_prev_half` / `end_of_prev_half` / `all_prev_half` | 前の期の期首 / 期末 / 期間 |
232
+ | `beginning_of_first_half` / `end_of_first_half` / `all_first_half` | 上期の期首 / 期末 / 期間 |
233
+ | `beginning_of_first_half?` / `end_of_first_half?` / `in_first_half?` | 上期の期首か? / 期末か? / 上期か? |
234
+ | `beginning_of_second_half` / `end_of_second_half` / `all_second_half` | 下期の期首 / 期末 / 期間 |
235
+ | `beginning_of_second_half?` / `end_of_second_half?` / `in_second_half?` | 下期の期首か? / 期末か? / 下期か? |
236
+
237
+ ### 年度関係
238
+
239
+ | メソッド | 内容 |
240
+ | --- | --- |
241
+ | `fiscal_year` | 現在の日付が属する年度(期首の年) |
242
+ | `beginning_of_fiscal_year` / `end_of_fiscal_year` / `all_fiscal_year` | 年度の期首 / 期末 / 期間 |
243
+ | `next_fiscal_year` / `prev_fiscal_year` | 次の年度 / 前の年度(期首の年) |
244
+ | `beginning_of_next_fiscal_year` / `end_of_next_fiscal_year` / `all_next_fiscal_year` | 次の年度の期首 / 期末 / 期間 |
245
+ | `beginning_of_prev_fiscal_year` / `end_of_prev_fiscal_year` / `all_prev_fiscal_year` | 前の年度の期首 / 期末 / 期間 |
246
+
247
+ 年度は `first_quarter_month_name` の設定に従い、期首の年を返します(4月始まりの場合、`::Date.new(2026, 3, 31).fiscal_year` は `2025`)。
248
+
249
+ > [!NOTE]
250
+ > 四半期・上下期には `this_quarter_number` / `beginning_of_this_quarter` のように `this_` が付きますが、年度には付きません。
251
+ > `this_` は「第1四半期」「上期」といった**絶対的な期間を指すメソッドと区別するため**に付けているものです。
252
+ > 年度には `first_fiscal_year` のような絶対版が存在せず、`fiscal_year` / `beginning_of_fiscal_year` は常にレシーバが属する年度を指すため、区別する必要がありません。
253
+ > ActiveSupportの `beginning_of_year` / `end_of_year` / `all_year` も同じ理由で `this_` を付けていません。
254
+
255
+ ### 満経過月数
256
+
257
+ 各クラスのクラスメソッドとして定義されています。
258
+
259
+ ```ruby
260
+ ::Date.whole_months_elapsed(from: ::Date.new(2026, 1, 31), to: ::Date.new(2026, 2, 27)) # => 0
261
+ ::Date.whole_months_elapsed(from: ::Date.new(2026, 1, 31), to: ::Date.new(2026, 2, 28)) # => 1
262
+ ::Date.whole_months_elapsed(from: ::Date.new(2024, 2, 29), to: ::Date.new(2025, 2, 28)) # => 12
263
+ ```
264
+
265
+ - 民法第140条(初日不算入)に従い `from` の翌日を起算日とし、民法第143条第2項に従い応当日の前日をもって満了とします(`2026-01-31` → `2026-02-28` は1ヶ月)。
266
+ - 応当日が存在しない月は、同項ただし書に従いその月の末日をもって満了とします(`2026-01-30` → `2026-02-28` は1ヶ月)。
267
+ - `from` が月末日の場合は起算日が月初となるため、満了日も月の末日になります(`2026-02-28` → `2026-03-30` は0ヶ月、`2026-03-31` で1ヶ月)。
268
+ - `to` が `from` より前の場合は `ArgumentError` が発生します。
269
+ - `::Time` / `::DateTime` / `::ActiveSupport::TimeWithZone` 版は日付単位で判定し、時刻は考慮しません。
270
+
271
+ ### ActiveSupportと同名の値を返すメソッド
272
+
273
+ `beginning_of_this_week` / `end_of_this_week` / `all_this_week` / `beginning_of_this_month` / `end_of_this_month` / `all_this_month` は、ActiveSupportの `beginning_of_week` / `end_of_week` / `all_week` / `beginning_of_month` / `end_of_month` / `all_month` と同じ値を返します。本ライブラリが追加する `*_this_*` という命名に揃えるために定義しているものであり、機能の追加ではありません。
274
+
275
+ 一方、ActiveSupportの**四半期**メソッドは同名のまま値を上書きしています。「ActiveSupportの四半期メソッドの上書き」を参照してください。
276
+
277
+ ## 開発
278
+
279
+ ```shell
280
+ bin/setup # 依存関係のインストール
281
+ bundle exec rake # spec / rubocop / steep をまとめて実行
282
+ ```
283
+
284
+ 個別に実行する場合は以下のとおりです。
285
+
286
+ ```shell
287
+ bundle exec rake spec # RSpec
288
+ bundle exec rake rubocop # RuboCop
289
+ bundle exec rake steep # Steep(RBSによる型検査)
290
+ ```
291
+
292
+ ## ライセンス
293
+
294
+ MIT License. 詳細は [LICENSE](LICENSE) を参照してください。
295
+
296
+ ## 変更履歴
297
+
298
+ [CHANGELOG.md](CHANGELOG.md) を参照してください。
@@ -1,30 +1,31 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "date"
4
+ require "active_support"
4
5
  require "active_support/core_ext/module/delegation"
5
6
 
6
7
  module Decentworks
7
8
  module DateSupport
8
9
  class << self
10
+ # 設定を変更する
11
+ # 未実行の場合は初期値(1月始まり)が使用される
9
12
  def configure
10
- @configuration ||= Configuration.new
11
-
12
- yield(@configuration) if block_given?
13
+ yield(configuration) if block_given?
13
14
  end
14
15
 
16
+ # 設定を取得する
17
+ # configureが未実行の場合は初期値で生成する
15
18
  def configuration
16
- raise "Initialization has not been performed." if @configuration.nil?
17
-
18
- @configuration
19
+ @configuration ||= Configuration.new
19
20
  end
20
21
 
21
22
  # 開始月名
22
- delegate :beginning_of_first_quarter, to: :configuration
23
+ delegate :first_quarter_month_name, to: :configuration
23
24
 
24
25
  # 開始月数
25
- delegate :beginning_of_first_quarter_month, to: :configuration
26
+ delegate :first_quarter_month, to: :configuration
26
27
 
27
- # 開始月の初期
28
+ # 設定を初期化する
28
29
  def reset_configuration!
29
30
  @configuration = nil
30
31
  end
@@ -37,35 +38,35 @@ module Decentworks
37
38
  # { january: 1, february: 2, ... december: 12 }
38
39
  MONTHS = ::Date::MONTHNAMES
39
40
  .each_with_index
40
- .filter_map { |name, index| [name.downcase.to_sym, index] if name }
41
+ .filter_map { |name, index| [ name.downcase.to_sym, index ] if name }
41
42
  .to_h
42
43
  .freeze
43
44
 
44
45
  # 開始月の初期値(1月)
45
46
  DEFAULT = :january
46
47
 
47
- # 開始月
48
- attr_reader :beginning_of_first_quarter
48
+ # 開始月名
49
+ attr_reader :first_quarter_month_name
49
50
 
50
51
  def initialize
51
- @beginning_of_first_quarter = DEFAULT
52
+ @first_quarter_month_name = DEFAULT
52
53
  end
53
54
 
54
- def beginning_of_first_quarter=(month_name)
55
+ def first_quarter_month_name=(month_name)
55
56
  unless MONTHS.key?(month_name)
56
57
  raise ::ArgumentError,
57
- "beginning_of_first_quarter must be one of #{MONTHS.keys.inspect} (got #{month_name.inspect})"
58
+ "first_quarter_month_name must be one of #{MONTHS.keys.inspect} (got #{month_name.inspect})"
58
59
  end
59
60
 
60
- @beginning_of_first_quarter = month_name
61
+ @first_quarter_month_name = month_name
61
62
  end
62
63
 
63
64
  # 開始月数
64
- def beginning_of_first_quarter_month = MONTHS.fetch(beginning_of_first_quarter)
65
+ def first_quarter_month = MONTHS.fetch(first_quarter_month_name)
65
66
 
66
67
  # 1月始まりとの開始月のずれ
67
68
  def first_quarter_month_offset
68
- beginning_of_first_quarter_month - 1
69
+ first_quarter_month - 1
69
70
  end
70
71
  end
71
72
  end