[Power BI] 誕生日から現在の年齢を計算する。DAXとJAPAN RUGBY LEAGUE ONE の選手プロフィールで。

# はじめに

2022年に開幕したJAPAN RUGBY LEAGUE ONEの公式ホームページから取得したデータを勝手にいじりながら勉強をしています。

https://qiita.com/hanaseleb/items/ffb70fba16aa073a8814

https://qiita.com/hanaseleb/items/a6f77d453107bd05acf4

https://qiita.com/hanaseleb/items/9e579c65220edb40a22a

## やってみたこと

**DAX**を使用して生年月日から年齢を計算。なかなか難しかった。

https://app.powerbi.com/view?r=eyJrIjoiOGMzYTNmMTAtMGY1MC00OGEwLWExOGQtOTgyZDdhNDdiNTU5IiwidCI6IjdkMDZmZWVlLWI3MzYtNDE3Zi1hMGUyLTE3NTZjOTdiMDU5YyJ9&pageName=ReportSectioncc8e8604c14700c30eb3

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/3e9b110d-e1bc-6c47-f87e-c913458039a3.png)

本記事での完成形はこちらです。参考にしてください。

```datastudio
Age =
VAR today =
    UTCNOW () + 9 / 24
VAR basedate =
    MAXX ( 'Height&Weight', 'Height&Weight'[Birthday] )
VAR compare_date =
    IF (
        basedate <> BLANK (),
        DATE ( YEAR ( today ), MONTH ( basedate ), DAY ( basedate ) )
    )
VAR hikaku =
    DATEDIFF ( compare_date, today, DAY )
VAR result =
    IF (
        hikaku >= 0,
        DATEDIFF ( basedate, today, YEAR ),
        DATEDIFF ( basedate, today, YEAR ) - 1
    )
RETURN
    IF (
        HASONEVALUE ( 'Height&Weight'[Birthday] ),
        IF ( basedate <> BLANK (), result, BLANK () ),
        BLANK ()
    )
```

# 検証スタート

## 誕生日を取得

公式サイトのプロフィールページを見ると、生年月日は記載があるものの、現年齢がわかりません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/2b3713ca-cc76-be9d-57b9-46ab8e10d69a.png)

ここから現年齢を計算していきます。

## 実験準備

※本記事は**2022/02/12**に書いています。

まずは実験用の日付テーブルを作成します。
Power Query Editor の「空のクエリ」に書きPower Queryを書き、年齢の計算が期待通り行ってくれるかを調べていきます。

```
= List.Dates(#date(1984,02,05),20,#duration(1,0,0,0))
```

`実験`テーブルに [baseday] という列を作成しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/003172cd-7a09-24d9-0809-b25b3ba42158.png)

## 実験１

まずはDAXの`DATEDIFF`関数を使用して計算します。
引数の`startday`から`endday`の間に年の区切りが何個あるかを数えてくれます。

https://docs.microsoft.com/ja-jp/dax/datediff-function-dax

```datastudio
DATEDIFF(
    MAXX( '実験', '実験'[baseday] ),
    UTCTODAY( ) + 9 / 24,
    YEAR
)
```

### 結果１

引数に２つの値を指定しましたが、その間にある年区切りの数なので、すべての行で38という数字が出ています。この数式だと指定日を基準に年を数えているわけではなくなっているため、1月1日誕生日の人しか正しい計算がされません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/dd75f8fb-8a6b-699f-036e-7242f5366d6f.png)

## 実験 ２

そこで基準日（誕生日）を境に年齢が変化するように分岐を作成していきます。
**今日**と**今年の誕生日**を比較してすでに誕生日を過ぎているなら`DATEDIFF`関数の求めた値のまま、まだ誕生日前なら`DATEDIFF`関数の値から１を引きます。

### まずは今日を求める。

Power BI Serviceにもアップする可能性があるなら、`TODAY`関数などを使うとTimezone計算で日付がずれてしまうことも考えられるので、UTCを求めてからタイムゾーンを調整する方法がオススメ。

```datastudio
today = UTCNOW( ) + 9 / 24
```

### `今日`と比較する`日付の作成`

単純に基準日（誕生日）を今日と比較すると、西暦が古いため比較ができない。`DATE`関数を使用して`月日`は同じで西暦だけ今日の西暦をもってくる。

```datastudio
compare_date = 
VAR today = UTCNOW( ) + 9 / 24
VAR compare_date =
    DATE(
        YEAR( today ),
        MONTH( MAXX( calender, calender[Date] ) ),
        DAY( MAXX( calender, calender[Date] ) )
    )
RETURN
    compare_date
```

### 結果２

今日の日付と、年号を揃えた基準日付を用意できました。この２つを比較します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/4af2e3fa-598a-f5c5-ff5a-fb29880eacb7.png)

## 実験３

実験２で用意した日付データ２つを比較し、**基準日よりも大きければ１を引く**処理を加えています。比較する際にも`DATEDIFF`関数を使用。

```datastudio
Age_proto_1 =
VAR today = UTCNOW( ) + 9 / 24
VAR basedate = MAXX( '実験', '実験'[baseday] )
VAR compare_date =
    DATE(
        YEAR( today ),
        MONTH( MAXX( calender, calender[Date] ) ),
        DAY( MAXX( calender, calender[Date] ) )
    )
VAR hikaku = DATEDIFF( compare_date, today, DAY )
VAR result =
    IF(
        hikaku >= 0,
        DATEDIFF( basedate, today, YEAR ),
        DATEDIFF( basedate, today, YEAR ) - 1
    )
RETURN
    result
```

### 結果３

おおむね完成しました。今日（2022/02/12）を境に年齢が変わっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/12fa65f3-f045-375f-815f-38b0213b4d17.png)

## 実験４

あとは細かい微調整です。まずは１行目に表示されている`ブランク`行になにも表示されないようにします。さきほど取得した値を、**行コンテキストがBlankではなかったら**を判定するIF文で囲います。

```datastudio
Age_proto_2 = 
VAR today = UTCNOW( ) + 9 / 24
VAR basedate = MAXX( '実験', '実験'[baseday] )
VAR compare_date =
    DATE(
        YEAR( today ),
        MONTH( MAXX( calender, calender[Date] ) ),
        DAY( MAXX( calender, calender[Date] ) )
    )
VAR hikaku = DATEDIFF( compare_date, today, DAY )
VAR result =
    IF(
        hikaku >= 0,
        DATEDIFF( basedate, today, YEAR ),
        DATEDIFF( basedate, today, YEAR ) - 1
    )
RETURN
    IF(
        basedate <> BLANK(),
        result
    )
```

### 結果４

基準日がBlankになっている行の計算列もBlankになりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/4cacdc84-4c97-e7a1-c760-4e5911ad7e61.png)

## 実験５

合計列が表示されてしまっているのも非表示にしましょう。さらに`HASONEVALUE`関数で囲います。

https://docs.microsoft.com/ja-jp/dax/hasonevalue-function-dax

```datastudio
Age_proto_3 = 
VAR today =
    UTCNOW () + 9 / 24
VAR basedate =
    MAXX ( 'Height&Weight', 'Height&Weight'[Birthday] )
VAR compare_date =
    IF (
        basedate <> BLANK (),
        DATE ( YEAR ( today ), MONTH ( basedate ), DAY ( basedate ) )
    )
VAR hikaku =
    DATEDIFF ( compare_date, today, DAY )
VAR result =
    IF (
        hikaku >= 0,
        DATEDIFF ( basedate, today, YEAR ),
        DATEDIFF ( basedate, today, YEAR ) - 1
    )
RETURN
    IF (
        HASONEVALUE ( 'Height&Weight'[Birthday] ),
        IF ( basedate <> BLANK (), result, BLANK () ),
        BLANK ()
    )

```

### 結果５

合計行の計算結果も消えました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/a28be71e-9989-b324-214f-9b0bf5edd26f.png)

## 実際に生年月日列に適用する。

実験を終え、関数の動きは把握できたので、実際に誕生日カラムに適用します。
40歳以上で現役プレイヤーがこんなにたくさん・・！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/c26486b1-0d32-f68d-8f0c-189165ac75a7.png)


## 完成

https://app.powerbi.com/view?r=eyJrIjoiOGMzYTNmMTAtMGY1MC00OGEwLWExOGQtOTgyZDdhNDdiNTU5IiwidCI6IjdkMDZmZWVlLWI3MzYtNDE3Zi1hMGUyLTE3NTZjOTdiMDU5YyJ9&pageName=ReportSectioncc8e8604c14700c30eb3

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80467/3e9b110d-e1bc-6c47-f87e-c913458039a3.png)

## まとめ

誕生日から年齢を算出するのは簡単かと思いきや、なかなか奥が深かった。もっといい書き方があるんだろうなぁと思い、引き続き勉強を進めようと思った。次回はPower Queryでチャレンジしてみよう。

## その後

いろいろな方々にフィードバックいただき、よりシンプルな計算方法を複数教えてもらいました。

一例

```dax
Age = INT ( YEARFRAC ( Customer[Birthdate], TODAY (), 1 ) )
```

## 参考資料

https://docs.microsoft.com/ja-jp/dax/datediff-function-dax

https://docs.microsoft.com/ja-jp/dax/yearfrac-function-dax