Power BIにおけるTimezoneの扱いについて

この記事は[Microsoft Power BI Advent Calendar 2024](https://qiita.com/advent-calendar/2024/powerbi)に参加しています。
使用しているPower BIは2024/12/22時点の最新バージョンです。

IT系の仕事をしていると国際的なイベントが多く開催され、時差やタイムゾーンに触れる機会も多いと思います。
今回の記事ではそんな時差やタイムゾーンがPower BIやPower Queryでどのように扱われるかを書いていきます。

# Power Queryにおけるタイムゾーン
Power Queryでdatetimezone型の値を作成するには二種類の方法があります。
- 自分で作成する
-  Text型からデータ型の検出でdatetimezone型に変換する

## datetimezone型の作成
[#datetimezone](https://learn.microsoft.com/ja-jp/powerquery-m/sharpdatetimezone)でdatetimezone型の値を作成できます。
~~~
#datetimezone(2010, 12, 31, 12, 26, 2, 8, 0)
~~~
引数は年、月、日、時間、分、秒、タイムゾーンオフセット時間、タイムゾーンオフセット分の順で並んでいます。
### #datetimezoneを記述する場合の注意
#datetimezoneを記述する際は**UTCマイナスの扱いに注意しましょう。**
例として、以下の式でUTC-6:00のdatetimezone型の値を作成できます。
~~~
=#datetimezone(2024, 12, 31, 12, 26, 0, -6, 0)
~~~
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/b3b04aa1-edd2-d07f-258f-b359c62030d4.png)

しかしUTC-6:30のdatetimezone型の値を作成する場合はどうでしょうか？
~~~
=#datetimezone(2024, 12, 31, 12, 26, 0, -6, 30)
~~~
このように記述した場合、UTC-5:30のdatetimezone型の値が作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/78357399-b5c9-006c-dc62-608997e1105f.png)
正しい記述は以下の通りです。

:::note
=#datetimezone(2024, 12, 31, 12, 26, 0, -6, -30)
:::
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/7226f946-7a0d-b80e-7541-bca79399eff6.png)
#datetimezoneを記述する際は、**UTCプラスなら正の値、UTCマイナスなら負の値でタイムゾーンオフセット時間、タイムゾーンオフセット分の引数を揃える必要があります。**
## Text型からデータ型の検出でdatetimezone型に変換する
タイムゾーンオフセット時間、タイムゾーンオフセット分を別途用意しておくと、datetime型からdatetimezone型に変換することは容易です。

まず、datetime型をtext型に変換します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/0498eb9d-2bf7-df4b-e3b3-aba966eff73c.png)
次に割り当てたいタイムゾーンオフセット時間、タイムゾーンオフセット分を数値で用意します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/107e998b-67c0-58f5-9393-21835a6c46ae.png)
この二列を`:`を区切り記号として結合します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/bc02b273-b7f2-3a48-482a-00ded09bc3aa.png)
先程用意したtext型に変換したdatatimeと` `を区切り記号として結合します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/788d3e55-a83d-7256-7681-9d7cc7eb1fe0.png)
最後にデータ型の変更でdatetimezoneに変更すると書式を自動的に識別して良い感じにdatetimezone型へ変換してくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/683eee01-91d4-6a42-f6e5-503e5f67d54e.png)
### データ型の検出でdatetimezone型に変換する場合の注意点
ここでもやはり**UTCマイナスの扱いが注意点になります。**

先程の#datetimezoneを記述する場合の注意では正の値と負の値を揃えましたが、データ型の変更の場合はどうでしょうか？

同じようにUTC-6:30のdatetimezone型の値を作成してみましょう。
まず、タイムゾーンオフセット時間とタイムゾーンオフセット分を負の値で揃えた場合です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/9fbb4915-3f36-7240-a853-1a0513fc0db1.png)
これはデータ型の変更でエラーになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/bf545b67-4b71-15d3-1657-a963c6b0869e.png)
次はタイムゾーンオフセット時間を負の値、タイムゾーンオフセット分を正の値にした場合です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/cf737b23-f935-2a64-3014-4c9d183f74f8.png)
正しくUTC-6:30であるdatetimezone型の値に変換されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/88d3b363-be36-c6e0-2a89-ce50bb8c1aa0.png)
データの変更でdatetimezone型の値に変換する場合、**タイムゾーンオフセット分は必ず正の値である必要があります。**
## 番外編:データソース側でdatetimezone型にしておく
datetimezone型に対応しているデータソースであれば、そのままPower Queryにdatetimezone型として取り込むことが出来ます。

Excelなどのdatetimezone型が扱えないデータソースではtext型のデータとして入力してPower Queryで変換する事になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/b8b1a8c8-4a76-c47d-f9b8-695d333f4eb2.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/dacbb45c-73b0-4a41-e4b2-e35a0a33055a.png)
# Power BIにおけるタイムゾーン
**Power BIでdatetimezone型は扱えません。**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/338dbc04-0718-eaba-682c-d39c21b61483.png)
Power Query上でdatetimezone型として扱った列はPower BIに取り込んだ時点で自動的にdatetime型に変換され、タイムゾーン情報は無くなります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/31ccd88e-7c1e-4a23-08dc-96af958ab2fd.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/072771dd-fa20-6913-ed84-097096cca49c.png)

そのため、Power BIでタイムゾーンの計算をしたい場合は事前にUTC0に揃えたdatetime列を作成しておくなどの工夫が必要になります。
## Power QueryでdatetimezoneをUTCに変換する
Power Query上にdatetimezone型の値があるなら[DateTimeZone.ToUtc](https://learn.microsoft.com/ja-jp/powerquery-m/datetimezone-toutc)関数を使うことでUTCに変換できます。
~~~
=DateTimeZone.ToUtc([現地開始時刻タイムゾーン])
~~~
UTC-6:00が+6:00され、UTCに変換されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/7c909758-dc1b-acfb-7f7f-3b2c5e22048a.png)
## タイムゾーンを扱う為のディメンションテーブルを用意する
**time型はマイナスの値を持つ事は出来ません。**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/06876ca6-dad4-b8d2-df89-e418254bee85.png)
そのため、UTC±のフラグを持ったtime型のデータを用意すると計算が楽になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/0fae6319-5555-ef8d-c74c-607832aa1539.png)
フラグを作成する際は、UTC-0:30というタイムゾーンは存在しないためタイムゾーンオフセット時間が負の値であるかを条件にすれば問題無く作成できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/771b0624-b561-df1c-77ae-c49ab7a0d384.png)
## Power BI レポート上でタイムゾーンを計算する
Microsoft Igniteのような海外のイベントや、Microsoft AI tourのような多国籍イベントを扱う場合、タイムゾーン計算の為のUTC日時、開催地の現地日時、そしてどの国から見るかで変わる視聴地日時の三つが必要になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/910934f2-b4d5-05ff-089e-71cc98d15d74.png)
### データモデル
今回使用するデータモデルは以下の通りです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/71207d78-17f5-f815-c235-46f653a0effc.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/c919552c-3af6-1cba-8ed6-32a66ca35093.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/67ba1182-efbb-da69-9099-ebc99edc11f0.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/3e0286ef-7859-d6f2-faf8-e47c4a442b59.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/58ebb2b4-bad2-eb7a-6ea7-5f1f053c23de.png)
`d_タイムゾーンマスタ`テーブルはフィルターで値を使用するのでリレーションシップは設定しません。
### UTC日時から視聴地日時を計算する。
先程作成した`UTC±Flag`列とIF文を組み合わせて加算と減算を制御します。
datetime型とtime型の値は直接加算減算できるので、`+`と`-`を入れ替えるだけでどちらの計算もできます。
更に[MAXX](https://learn.microsoft.com/ja-jp/dax/maxx-function-dax)関数を使うことで確実にファクトテーブル内だけで評価させます。
DAX式は以下の通りです。
~~~
視聴地時刻 = 
IF(
    SELECTEDVALUE(
        'd_タイムゾーンマスタ'[UTC±Flag]
        )=TRUE(),
        MAXX(
            'f_セッションリスト',
            [UTC開始時刻]
            +
            SELECTEDVALUE(
                'd_タイムゾーンマスタ'[タイムゾーン]
                )
            ),
        MAXX(
            'f_セッションリスト',
            [UTC開始時刻]
            -
            SELECTEDVALUE(
                'd_タイムゾーンマスタ'[タイムゾーン]
                )
            )
)
~~~
ビジュアルは`d_タイムゾーンマスタ`テーブルの`視聴国`をスライサーとして配置します。
これにより動的に`視聴地時刻`で使用されているタイムゾーンを制御できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/7e4c5140-2120-2673-b8a0-d82d2b9f3521.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/9138e10e-5029-8943-7def-f29c26d37ab2.png)
以下はUTC+9の日本とUTC-6のアメリカ(シアトル)をスライサーで切り替えている例です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/31cab467-7382-361d-30f5-fd7898945e90.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/5d01ab22-6900-ec6a-bdcc-68b3989e0342.png)
## 番外編:スライサーは非表示でも機能する
**スライサービジュアルは非表示にしても、選択された内容は他のビジュアルに作用します。**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/0b35a9be-a200-8481-be65-5582d55a0137.png)
`d_タイムゾーンマスタ`テーブルはスライサーを選んでいない状態ではアメリカと日本の2行です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/df03e9d2-8c64-e8a3-42ef-2cd110202346.png)
ここに日本を選択したスライサーを追加して非表示にしても、選択されたフィルターは有効なままです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/237d9ba3-d4c2-34b1-4b24-e26f1084bec0.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/313502/aaf77383-23a1-4327-9876-c66c7b6b2243.png)
これを使うことで最初に選んだ視聴国の選択を、ページを跨いでも一貫して有効化することが出来ます。
# まとめ
## Power BIとPower Queryで使えるデータ型はイコールではない
datetimezone型以外にもPower Query内でしか使えないデータ型はいくつかある。
Power BIのレポートに落とし込む前に、Power BIで扱えるデータ型になっているか確認しよう
## データ型の検出による自動変換はそれなりに融通が利く
完全な書式ではなくとも保管してくれる場合が多い。
知っていれば入力の手間が軽減されるかも。
## DAX式だけではなく、ビジュアルも計算に組み込める
テーブルを一つ用意してビジュアルに組み込むことで動的な計算がとても楽になる事もある。
インタラクティブな操作が出来るPower BIの強みを生かそう。

---
Power Queryでdate型やdatetime型をdatetimezone型に変換すると、システムロケールに基づいたTimezone情報が自動的に付与される挙動ってどうにか変更できないのかな。