两个日期间的相隔年月计算

以下の端数調整(EOM 月末/1日開始)**を正しく考慮できています。大筋で問題ありません。

YEAR/ MONTH差で基礎となる総月数を計算

開始日が1日 & 終了日が月末 → その月を丸々1か月としてカウント(-1 を引いているので実質 +1 調整)

終了日が月末 & 開始日の「日」が終了日の「日」より大きい → 本来は -1 されるところを減らさない

上記以外で 開始日の「日」> 終了日の「日」 → -1 か月(満月に達していないため)

結果の文字列は TEXT(FLOOR(.../12)) & "年" & TEXT(MOD(...,12)) & "ヶ月" で「n年mヶ月」と表記されます。

  • 2024-01-01 ~ 2024-01-31(同月・月末) → 1ヶ月(調整により 0→1)
  • 2024-01-31 ~ 2024-02-29(閏年・月末) → 1ヶ月(EOM ルールで月欠け扱いしない)
  • 2023-01-31 ~ 2023-02-28(平年・月末) → 1ヶ月
  • 2024-01-01 ~ 2024-02-29(1日開始・月末) → 2ヶ月(両月を丸々カウント)
  • 2024-01-15 ~ 2024-02-14 → 0ヶ月(満月未満なので -1 調整)
  • 2024-01-15 ~ 2024-02-15 → 1ヶ月(ちょうど満月)

いずれも、「1日開始」「終了が月末」の特殊処理と、

**「開始日の方が日付が大きい場合は -1」**という通常処理が矛盾なく効いています。

复制代码
IF(
  AND(NOT(ISBLANK( StartDate__c )), NOT(ISBLANK( EndDate__c ))),
  /* 年の計算 */
  TEXT(
    FLOOR(
      (
        (YEAR(EndDate__c )-YEAR(StartDate__c ))*12 +
        (MONTH(EndDate__c )-MONTH(StartDate__c )) -
  /* 端数調整 */
        IF(
          AND(DAY(StartDate__c )=1,
          EndDate__c = ADDMONTHS(DATE(YEAR(EndDate__c ), MONTH(EndDate__c ), 1),1)-1
          ),-1,
        IF(
          AND(EndDate__c = ADDMONTHS(DATE(YEAR(EndDate__c ), MONTH(EndDate__c ), 1),1)-1,
          DAY(StartDate__c ) > DAY(EndDate__c )
          ),0,
        IF( DAY(StartDate__c ) > DAY(EndDate__c ),1,0 )))
        ) / 12
        )
        ) & "年"&
  /* 月の計算 */
  TEXT(
    MOD(
      (YEAR(EndDate__c )-YEAR(StartDate__c ))*12 +
      (MONTH(EndDate__c )-MONTH(StartDate__c )) -
      IF(
        AND(DAY(StartDate__c )=1,
        EndDate__c = ADDMONTHS(DATE(YEAR(EndDate__c ), MONTH(EndDate__c ), 1),1)-1
        ),-1,
      IF(
        AND(EndDate__c = ADDMONTHS(DATE(YEAR(EndDate__c ), MONTH(EndDate__c ), 1),1)-1,
        DAY(StartDate__c ) > DAY(EndDate__c )
        ),0,
      IF( DAY(StartDate__c ) > DAY(EndDate__c ),1,0 ))),
        12
      )
      )
      & "ヶ月",
"")

改善したソースコード:

  1. 開始日 > 終了日の場合の扱い

現行式だと負の値(「-1年◯ヶ月」のような表示)になり得ます。

ビジネスルール的に許可しないなら、ガードを入れて空文字や 0 にできます。

  1. ゼロ抑制(任意)

「0年5ヶ月」はよいが、「0年0ヶ月」は空白にしたい・「5ヶ月」とだけ表示したい等の表記ルールがある場合は表示部分を調整します。

  1. マイナス総月の MOD

終了 < 開始 のときに負の総月を許す設計だと、MOD(負の数, 12) は負の剰余になることがあります。見栄えを崩す要因なので、(1) のようにガードするか、負値のときは絶対値化・空文字にするのが無難です。

复制代码
/* 総月数を一回だけ計算し、それを使って表示を分岐(可読性向上のための書き方例) */

IF(

  AND(NOT(ISBLANK(StartDate__c)), NOT(ISBLANK(EndDate__c))),

  /* 総月数(調整後) */

  IF(

    /* 終了 < 開始 のときは空文字を返す(任意) */

    EndDate__c < StartDate__c,

    "",

    /* 表示生成 */

    IF(

      FLOOR(

        (

          (YEAR(EndDate__c)-YEAR(StartDate__c))*12 +

          (MONTH(EndDate__c)-MONTH(StartDate__c)) -

          IF(

            AND(

              DAY(StartDate__c)=1,

              EndDate__c = ADDMONTHS(DATE(YEAR(EndDate__c), MONTH(EndDate__c), 1),1)-1

            ),

            -1,

            IF(

              AND(

                EndDate__c = ADDMONTHS(DATE(YEAR(EndDate__c), MONTH(EndDate__c), 1),1)-1,

                DAY(StartDate__c) > DAY(EndDate__c)

              ),

              0,

              IF(DAY(StartDate__c) > DAY(EndDate__c), 1, 0)

            )

          )

        ) / 12

      ) > 0,

      /* 年が1以上のときは「n年mヶ月」 */

      TEXT(

        FLOOR(

          (

            (YEAR(EndDate__c)-YEAR(StartDate__c))*12 +

            (MONTH(EndDate__c)-MONTH(StartDate__c)) -

            IF(

              AND(

                DAY(StartDate__c)=1,

                EndDate__c = ADDMONTHS(DATE(YEAR(EndDate__c), MONTH(EndDate__c), 1),1)-1

              ),

              -1,

              IF(

                AND(

                  EndDate__c = ADDMONTHS(DATE(YEAR(EndDate__c), MONTH(EndDate__c), 1),1)-1,

                  DAY(StartDate__c) > DAY(EndDate__c)

                ),

                0,

                IF(DAY(StartDate__c) > DAY(EndDate__c), 1, 0)

              )

            )

          ) / 12

        )

      ) & "年" &

      TEXT(

        MOD(

          (YEAR(EndDate__c)-YEAR(StartDate__c))*12 +

          (MONTH(EndDate__c)-MONTH(StartDate__c)) -

          IF(

            AND(

              DAY(StartDate__c)=1,

              EndDate__c = ADDMONTHS(DATE(YEAR(EndDate__c), MONTH(EndDate__c), 1),1)-1

            ),

            -1,

            IF(

              AND(

                EndDate__c = ADDMONTHS(DATE(YEAR(EndDate__c), MONTH(EndDate__c), 1),1)-1,

                DAY(StartDate__c) > DAY(EndDate__c)

              ),

              0,

              IF(DAY(StartDate__c) > DAY(EndDate__c), 1, 0)

            )

          ),

          12

        )

      ) & "ヶ月",

      /* 年が0のときは「mヶ月」のみ */

      TEXT(

        MOD(

          (YEAR(EndDate__c)-YEAR(StartDate__c))*12 +

          (MONTH(EndDate__c)-MONTH(StartDate__c)) -

          IF(

            AND(

              DAY(StartDate__c)=1,

              EndDate__c = ADDMONTHS(DATE(YEAR(EndDate__c), MONTH(EndDate__c), 1),1)-1

            ),

            -1,

            IF(

              AND(

                EndDate__c = ADDMONTHS(DATE(YEAR(EndDate__c), MONTH(EndDate__c), 1),1)-1,

                DAY(StartDate__c) > DAY(EndDate__c)

              ),

              0,

              IF(DAY(StartDate__c) > DAY(EndDate__c), 1, 0)

            )

          ),

          12

        )

      ) & "ヶ月"

    )

  ),

  ""

)

よくテストをしてから、使ってください。
まとめ

現状ロジックは 月末・1日開始・満月未満の調整を適切にカバーしており、誤りはありません。

実運用では **「終了日が開始日より前」**のケースの扱いと、表示のゼロ抑制を整えると、より堅牢・見やすくなります。

もし「日」まで出したい(例:1年2ヶ月と14日)や、2/29 を含む特殊契約のビジネスルールがあるなど、さらに要件があれば教えてください。要件に合わせて式を調整します。

相关推荐
上海合宙LuatOS2 小时前
LuatOS核心库API——【io】 io操作(扩展)
java·服务器·前端·网络·单片机·嵌入式硬件·物联网
GISer_Jing3 小时前
Taro多端开发
前端·react.js·taro
未来龙皇小蓝4 小时前
RBAC前端架构-04:设置代理及开发配置
前端·vue.js
祈安_4 小时前
深入理解指针(一)
c语言·前端
SuperEugene4 小时前
对象数组的排序与分组:sort / localeCompare / 自定义 compare
前端·javascript·面试
扶苏10025 小时前
“解构”与“响应”的博弈——深入剖析 Vue 3 的 toRef 与 toRefs
前端·javascript·vue.js
icestone20005 小时前
使用Cursor开发大型项目的技巧
前端·人工智能·ai编程
Channing Lewis6 小时前
zoho crm的子表添加行时,有一个勾选字段,如何让它在details页面新建子表行(点击add row)时默认是勾选的
开发语言·前端·javascript
董员外7 小时前
LangChain.js 快速上手指南:模型接入、流式输出打造基础
前端·javascript·后端