Power Query の タイムゾーン を含む計算は実行環境に依存するのですよ

うっかりはまってることがひきつづき散見されるので。

# Power Query は実行される環境により動作が異なることがある
といっても、ほとんどは期待通りに動作するようになっているけど、タイムゾーンについてはデザイン時のローカル環境と異なることがある。Power BI データモデルで定義できる データ型には *datetimezone* はないので、Power Query で実施した処理に原因があることは明白ではある。

具体的に言うと、Power BI Desktop で *datetimezone (UTC+9)* を考慮したデータセット更新処理を行ったとしても、Power BI Service でのオンデマンド更新、スケジュール更新すると UTC になってるのはなんでなん？って。

Power BI Desktop もしくは Excel の Power Query エディタで作業をしたとき、そのローカルシステムのタイムゾーン情報が利用されているので、ぱっと見問題がないように感じてしまうのは当たり前だ。Power BI Service に限ってではないけれども、グローバルで利用されているサービスではあるから、UTC で動作するというのは合理的な挙動という理解も必要だ。

## どんなときに起きるのさ
データ型が *datetime* になっていて これにタイムゾーン情報を追加したとき

```text:PowerQuery
let
    Source = #table(
        type table [ ColumnDateTime = datetime ],
        { { #datetime( 2021, 3, 12, 0, 0, 0 ) } }
    ),
    ChangedType = Table.TransformColumnTypes(
        Source,
        { "ColumnDateTime", type datetimezone }
    )
in
    ChangedType
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193509/b6b2fc33-efbd-01a6-dda4-8f78be45ea7d.png)
ね、+ 9になってるでしょ

データ型が *datetimezone* になっていて、[Local time] / [現地時間] を計算したときも同じく、

```text:PowerQuery
let
    Source = #table(
        type table [ ColumnDateTimeZone = datetimezone ],
        { { #datetimezone( 2021, 3, 12, 0, 0, 0, 0, 0 ) } }
    ),
    CalculatedLocalTime = Table.TransformColumns(
        Source,
        { "ColumnDateTimeZone", DateTimeZone.ToLocal, type datetimezone }
    )
in
    CalculatedLocalTime
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193509/032de99c-5026-418a-c6d1-358659c631b0.png)
ね、+ 9になってるでしょ。これは実行した環境の タイムゾーン情報が JST(UTC+9) になっているから。

わかりやすいところで Power BI データフロー で同じスクリプトを実行したときどのような結果になるか。いずれも UTC になる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193509/b769fe1a-b358-c325-4954-f6d0f6957386.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193509/bab44428-54db-7514-9b0a-2ab437f2ba88.png)


# データソース固有のことは各自が調べ、各自が対応しなければならない
データソースから提供される *datetime* 型のデータがどのタイムゾーンに設定されているかについてはデータを利用する側が調べ、どのような調整が必要なのかを検討。どの実行環境であっても一貫したタイムゾーンになるようなスクリプトが望ましいというケースが多いってことだ。

多くの場合、UTC が利用されていて、これを JST に変換するにはどうするか。

```text:PowerQuery
let
    Source = #table(
        type table [ ColumnDateTime = datetime ],
        { { #datetime( 2021, 3, 12, 0, 0, 0 ) } }
    ),
    UTCToJST = Table.TransformColumns(
        Source,
        {
            "ColumnDateTime",
            each
                DateTimeZone.RemoveZone(            // オフセットを切り捨て
                    DateTimeZone.SwitchZone(        // オフセット + 9 に変換
                        DateTime.AddZone( _, 0 ),   // オフセット + 0 を追加
                        9
                    )
                ),
            type datetime
        }
    )
in
    UTCToJST
```

```text:PowerQuery
let
    Source = #table(
        type table [ ColumnDateTime = datetime ],
        { { #datetime( 2021, 3, 12, 0, 0, 0 ) } }
    ),
    UTCToJST = Table.TransformColumns(
        Source,
        {
            "ColumnDateTime",
            each _ + #duration( 0, 9, 0, 0 ),
            type datetime
        }
    )
in
    UTCToJST
```

UTC のままを受け入れ DAX で調整するときは、

```text:DAX
ColumnDateTime (JST) = 'TableName'[ColumnDateTime (UTC)] + 24 / 9
```

# 思ったこと🙄
文字列からのパースなどに利用される *culture* については、環境のデフォルト設定、オプション引数 *culture* がサポートされる Power Query 関数があるのだけど、タイムゾーンについてはどうにもならんよね。

# その他
- [Power BI 勉強会 - connpass](https://powerbi.connpass.com/)
- [Power BI Desktop を使い始めるには](http://qiita.com/PowerBIxyz/items/6c4735cb5b5712e70981)
- [Excel で Power Query を使い始めるには](http://qiita.com/PowerBIxyz/items/52e563037b855a099ca9)