#PowerApps 満年齢の計算方法

毎週金曜日 21:30頃から まぐろサン こと [Akira](https://twitter.com/akira_365) さんと一緒に、YouTube Live で開催している Power Apps WeeklyNews。その第9回で「Power Apps における誕生日からの年齢計算をどうやるか？」という小ネタを話しました。

https://appsweeklynews.connpass.com/event/272890/

該当回の動画はこちら。（※過去回含めてレコーディングが公開されております）

https://www.youtube.com/live/EQt43fYt2VI

今回は上記内容に対する補足の意味も兼ねた記事になります。収録後に色々と試していて気づいたのですが、当方のやり方だと「生年月日と今日が同月だと、誕生日の日付に達していなくても加算された年齢になっちゃう」のです。何を言っているか？は続きをご確認くださいませ。

:::note info
コッチのが読みやすいかな？と思って「生年月日」と「誕生日」をあえて混在させて記載しています。当記事のなかでは同一と思って読み進めてください。同じ単語が連続すると読み手が混乱することもあるんで、程よい頻度で混在させたつもりなんですが・・・。逆に用語の利用が統一されてないじゃないか！って気になっちゃった方はごめんなさいね。
:::


# 年齢の求め方 ※不完全版
補足の説明に入る前に、Power Apps Weekly News 第9回で、当方が紹介した「満年齢の求め方」は下記になります。まずは基本的な部分から。

```
DateDiff( [生年月日], Today() ) / 365
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215892/64c5a842-c04b-5f00-033b-19a4435c1a42.png)

今日の日付（Today()）から生年月日を減算すれば年齢が計算できますよね？
その計算を DateDiff 関数を利用して実施しています。

https://learn.microsoft.com/ja-jp/power-platform/power-fx/reference/function-dateadd-datediff?WT.mc_id=BA-MVP-5004053#syntax

DateDiff 関数の第三引数を省略した場合、単位が”日”となります。なので 365 日（＝ 1年）で割り算することで年齢を求めました。ただ、この状態だと小数点以下の値も発生するパターンが大半になります。そこで、切り捨てを実施します。（動画内では四捨五入と口を滑らせていますが、切り捨て ですね汗）

数値の切り捨て処理を追加した関数が下記になります。

```
Int( DateDiff( [生年月日], Today() ) / 365 ))
```

動画内では Int 関数に関して公式サイトを調べて Trunc 関数のが良いんじゃないか？等の議論をしておりますので、気になる方は冒頭で紹介した Youtube をご確認ください。

```
Trunc( DateDiff( [生年月日], Today() ) / 365 ))
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215892/8c85bf30-7bdd-a674-0b07-40e4dbf42238.png)


https://learn.microsoft.com/ja-jp/power-platform/power-fx/reference/function-round?WT.mc_id=BA-MVP-5004053#int-and-trunc

:::note info
マイナスの値にならない限り、Int 関数・Trunc 関数のどちらを利用しても同じ結果が得られます。
「小数点以下切り捨て」という明示的な意図を伝えるために Trunc 関数で記載したほうが良いのかな、と個人的には思います。もちろん、RoundDown 関数でも問題ありません。
:::

うるう年は大丈夫なの？という議論も動画でしておりますが、数百年を生きてない限りは小数点以下の誤差で収まるハズなので基本問題無いかな、と判断して良いと考えられます。この考えに基づくと DateDiff 関数の第三引数が”月”（Months）で 12ヶ月で割っても良かったですね。（と記事を書いている時に思いました😇）

# なぜ不完全版なのか？あるいは問題点
ここから、収録後に気付いた「生年月日と今日が同月だと、誕生日の日付より前でも加算された年齢になっちゃう」点です。「年を無視」して誕生日月と当月が同じ場合、誕生日の日付に到達してないにも関わらず加算された年齢となってしまうのです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215892/e56ac59f-d8be-91ec-cfd8-0c0fcb47f539.png)


文章よりも図のほうがわかりやすいと思います。上記の例だと誕生日の日付は 30日 なので、まだ「22歳」のハズです。前述の計算式では「23歳」として計算されちゃいます。困ったね。

”不完全”と言ってしまいましたが、要件が「年月から年齢を求める（日は考慮しない）」であれば現状の方法でも問題は無いですよね。例えば『該当年月で何歳か？』みたいな場合です。厳密に表現すると「おそらく大多数の方が考えうる”年齢の概念”においては不完全」な状態ですかねぇ🤔

# 年齢の求め方 完全版？
「同月で、生年月日の”日付”が今日の”日付”に到達していない場合に －1」してあげれば良いので、下記のような式を組めば対応可能です。

```
If(
    Month( [生年月日] = Month( Today() ) && Day( Today() ) < Day( [生年月日] ) ,
    Trunc(DateDiff( [生年月日], Today() ) /365) -1,
    Trunc(DateDiff( [生年月日], Today() ) /365)
)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/215892/32806fa4-76c8-7704-c79e-b1b89ec916a8.png)

Month 関数を利用して同月なのか？を確認
　→ 同月の場合かつ Day 関数で「今日の”日付”のみで考えて、到達しているか否か？」を確認
　　→ 同月だけど、日付がまだ到達していない場合は計算結果をマイナス１

という処理です。


# Akira 式 年齢計算方法
アキラさんは誕生日と今日（Today）を数値に変換して計算で年齢を求めていました。さすがの数学脳。
気になる方は是非とも Youtube でレコーディングをご覧ください。

:::note info
Akira式の数式
（今日（Today()） - 生年月日） / 10000
※小数点以下切り捨て
:::

C# の例ですが、10000 で割り込む処理は下記が参考になるかもしれません。

https://stackoverflow.com/questions/9/how-do-i-calculate-someones-age-based-on-a-datetime-type-birthday

なお、この計算方法であれば当方が遭遇した「同月で日付がー」問題は発生しません。たぶん。
数学って偉大。

# 結び
「年齢の計算は思った以上に奥が深い」ですね。
様々なパターンを試してみるのもオモシロいかもしれません。

Wiki を引用しておきますが「満年齢」「数え年」のみにとどまらず「通常の法令上の満年齢では誕生日の前日に1歳年を取る」や「保険年齢」等々、業種業界による特殊ルールの数々！！ややこしいコトこのうえないッ！！

https://ja.wikipedia.org/wiki/%E5%B9%B4%E9%BD%A2

今回のイベントでは細かい要件などを詰めずに「誕生日を計算して求める」というお題に対して各々が実装例を提示しました。

繰り返しになりますが、「年齢」とヒトコトで行っても多種多用です。業務アプリなどを作成する場合はアプリを実装する前に「年齢とは具体的にどのような条件なのか？」「計算方法と諸条件、注意事項・特記事項」を明確化しておくべきでしょう。その対応、つまり”ヒトテマ”を惜しまない行動によって後々の混乱や悲しみを回避できると思います。要件の確認と設計は大事です。

また、アプリ作成後に”意図した動作・計算結果になるか？”の動作確認は必須ですね。紙面上の計算式や、Excel の関数を利用した結果と、Power Apps や Power Automate の関数の結果が必ずしも同一になるとは限りません。テストも重要なフェーズです。

・・・あれ？
・・・結びでなんか趣旨が変わってきたかもしれん🤔

(;^ω^)

ってことで、今回は以上です。（ﾑﾘﾔﾘ筆をおく感

それでは皆さま、素晴らしい Power Platform Life を！！