この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは!DA(データアナリティクス)事業本部 インテグレーション部の大高です。
みなさま、AngularのPipeの一つ「DatePipe」は使われていますでしょうか?
コードベースでのよくある使い方は、UI上に表示したい日付フォーマットを以下のように変換するパターンかと思います。
this.datePipe.transform(new Date(), 'yyyy/MM/dd HH:mm:ss');
この際に、タイムゾーン付きの日付を変換する場合は、注意するべき点があることを初めて知ったので、本エントリにて説明したいと思います。
やりたかったこと
今回、やりたかったことは以下の通りです。
- サーバー側のAPIが、JSTのタイムゾーン付きの日付データを返却する
- 返却された日付をフロントエンド(Angular)で、JSTのまま画面に表示したい
想定外だった挙動
以下のようなコードでtargetDate
にJSTの日付データが入っている場合、formattedDate
にフォーマット変換後の値が入るのですが、この場合ローカル環境のタイムゾーンによって値が変わります。
formattedDate = this.datePipe.transform(targetDate), 'yyyy/MM/dd HH:mm:ss');
詳しく
サンプルとして、以下のようなコードで「2020/12/25 22:15:30+0900」(JSTの日付)が、画面上でどのように表示されるかを試してみました。
date-pipe-sample.component.ts
import { DatePipe } from '@angular/common';
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-date-pipe-sample',
templateUrl: './date-pipe-sample.component.html',
styleUrls: ['./date-pipe-sample.component.scss'],
providers:[DatePipe]
})
export class DatePipeSampleComponent implements OnInit {
localTimezoneOffset:number = -(new Date().getTimezoneOffset() / 60);
originalDateTime:Date = new Date('2020/12/25 22:15:30+0900');
dateTimeValue:string|null = '';
dateTimeValueWithTz:string|null = '';
constructor(public datePipe: DatePipe) { }
ngOnInit(): void {
this.dateTimeValue = this.datePipe.transform(this.originalDateTime, 'yyyy/MM/dd HH:mm:ss');
this.dateTimeValueWithTz = this.datePipe.transform(this.originalDateTime, 'yyyy/MM/dd HH:mm:ss', '+0900');
}
}
date-pipe-sample.component.html
<div>
<div>Local Timezone Offset:</div>
<hr class="fade">
<div class="terminal">
<pre>{{localTimezoneOffset}} Hours</pre>
</div>
<br/>
<div>DateTime:</div>
<hr class="fade">
<div class="terminal">
<pre>{{dateTimeValue}}</pre>
</div>
<br/>
<div>DateTime with Timezone:</div>
<hr class="fade">
<div class="terminal">
<pre>{{dateTimeValueWithTz}}</pre>
</div>
</div>
ローカル環境のタイムゾーンが「(UTC+09:00)大阪、札幌、東京」の場合
まずは、ローカル環境(OS)のタイムゾーンが「(UTC+09:00)大阪、札幌、東京」の環境での結果です。
「Local Timezone Offset」は、タイムゾーンのオフセットとして認識されている時間です。タイムゾーンを「UTC+09:00」にしているので、9 Hours
となっています。
「DateTime」と「DateTime with Timezone」は、どちらもオリジナルのデータと同じく2020/12/25 22:15:30
ですので、この場合は特に問題ないかと思います。
ローカル環境のタイムゾーンが「(UTC+07:00)バンコク、ハノイ、ジャカルタ」の場合
つぎに、ローカル環境(OS)のタイムゾーンを「(UTC+07:00)バンコク、ハノイ、ジャカルタ」に変更して試してみます。
「Local Timezone Offset」は、タイムゾーンのオフセットとして認識されている時間です。タイムゾーンを「UTC+07:00」にしたので、7 Hours
になりました。
「DateTime」は、オリジナルのデータから時間が変わりました。 オリジナルのデータはJST(UTC+09:00)のデータだったので、そこから時差の2時間分の時間がズレて2020/12/25 20:15:30
となっています。
一方で、「DateTime with Timezone」は、オリジナルのデータと同じく2020/12/25 22:15:30
です。
これは、this.datePipe.transform(this.originalDateTime, 'yyyy/MM/dd HH:mm:ss', '+0900')
のように、第3引数のtimezone
にオフセットを明示的に指定したことにより、UI上も時間がズレていません。
具体的には以下に記載があります。
angular/date_pipe.ts at 11.0.2 · angular/angular · GitHub
- @param timezone A timezone offset (such as
'+0430'
), or a standard- UTC/GMT or continental US timezone abbreviation.
- When not supplied, uses the end-user's local system timezone.
記載のとおり、「指定なし」の場合はローカルシステムのタイムゾーンを参照するので、今回のケースでは+0700
を指定したのと同義となっています。
そのため、オリジナルのデータから2時間ズレた値が表示されたということになります。
このように、「JSTのまま時刻を表示したい」というケースでは注意が必要ですね。
まとめ
以上、AngularのDatePipeでタイムゾーン付きの日時変換をする時の注意点についてでした。
「サーバーサイドのAPIがUTCで時刻を返すケースで、フロントエンド側ではタイムゾーンに応じて表示を変えたい」というようなケースでは特に問題はありませんが、「サーバーサイドのAPIがJSTで時刻を返すケースで、フロントエンド側ではタイムゾーンに関わらずJSTで表示したい」というようなケースでは注意が必要ですね。
どなたかのお役に立てば幸いです。それでは!