[ServiceNow] GlideDateTimeオブジェクトやDate/Timeフィールド対するget系メソッドの挙動を理解する

# 目的
ServiceNowではGlideDateTimeといった日時を扱うためのAPIが用意されていますが、実行環境におけるタイムゾーンや日付・時刻の表示フォーマットの設定によって一部のget系メソッドの挙動が異なります。

同じく、日付・時刻を表すDate/Time型・Date型・Time型のフィールドに対するget系メソッドも実行環境の設定によって挙動が異なります。

スクリプトで扱う時によく混乱するので整理したいと思います。


# 結論
表にまとめると次の通りです。


## GlideDateTimeオブジェクト

|メソッド|戻り値の型|タイムゾーン|日付・時刻のフォーマット|備考|
|:-:|:-:|:-:|:-:|:-:|
|new GlideDateTime()|GlideDateTime|GMT|`yyyy-MM-dd HH:mm:ss (24 hour)`||
|getValue()|String|GMT|`yyyy-MM-dd HH:mm:ss (24 hour)`||
|getDisplayValue()|String|ユーザー設定値|ユーザー設定値||
|getDisplayValueInternal()|String|ユーザー設定値|`yyyy-MM-dd HH:mm:ss (24 hour)`||
|getInternalFormattedLocalTime()|String|ユーザー設定値|`HH:mm:ss (24 hour)`|時刻のみ|
|getUserFormattedLocalTime()|String|ユーザー設定値|ユーザー設定値|時刻のみ|
|getDate()|GlideDate|GMT|`yyyy-MM-dd`|GMTにおける日付を取得してGlideDate型に変換|
|getLocalDate()|GlideDate|ユーザー設定値|`yyyy-MM-dd`|ユーザーのタイムゾーンにおける日付を取得してGlideDate型に変換|
|getTime()|GlideTime|GMT|`1970-01-01 HH:mm:ss (24 hour)`|GMTにおける時刻を取得してGlideTime型に変換|
|getLocalTime()|GlideTime|ユーザー設定値|`1970-01-01 HH:mm:ss (24 hour)`|ユーザーのタイムゾーンにおける時刻を取得してGlideTime型に変換|

(*) 戻り値の型は下記のServiceNowドキュメントを参照してます。
https://www.servicenow.com/docs/csh?topicname=c_GlideDateTimeAPI.html&version=latest


## DateTimeフィールド

|メソッド|戻り値の型|タイムゾーン|日付・時刻のフォーマット|
|:-:|:-:|:-:|:-:|
|getValue()|String|GMT|`yyyy-MM-dd HH:mm:ss (24 hour)`|
|getDisplayValue()|String|ユーザー設定値|ユーザー設定値|

(*) 戻り値の型は下記のServiceNowドキュメントを参照してます。
https://www.servicenow.com/docs/csh?topicname=c_GlideRecordAPI.html&version=latest

## Dateフィールド

|メソッド|戻り値の型|タイムゾーン|日付・時刻のフォーマット|
|:-:|:-:|:-:|:-:|
|getValue()|String|N/A|`yyyy-MM-dd`|
|getDisplayValue()|String|N/A|ユーザー設定値|

(*) 戻り値の型は下記のServiceNowドキュメントを参照してます。
https://www.servicenow.com/docs/csh?topicname=c_GlideRecordAPI.html&version=latest

## Timeフィールド

|メソッド|戻り値の型|タイムゾーン|日付・時刻のフォーマット|
|:-:|:-:|:-:|:-:|
|getValue()|String|GMT|`1970-01-01 HH:mm:ss (24hour)`|
|getDisplayValue()|String|ユーザー設定値|ユーザー設定値|

(*) 戻り値の型は下記のServiceNowドキュメントを参照してます。
https://www.servicenow.com/docs/csh?topicname=c_GlideRecordAPI.html&version=latest

# 詳細
以降は実際にPDIで検証した結果を記載していきます。

## 前提
スクリプトとその実行結果を延々と載せますが、実行時の環境設定は下記の通りとします。

### Systemの設定
Systemの設定として、タイムゾーンおよび日付・時刻フォーマットは次の通りに設定しているとします。
* タイムゾーン(`glide.sys.default.tz`): `America/Los_Angeles (**GMT-8**)`
* 日付フォーマット(`glide.sys.date_format`): `dd-MM-yyyy`
* 時刻フォーマット(`glide.sys.time_format`): `hh.mm.ss a (12 hour AM/PM)`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1923007/a8cc256e-875a-5736-5493-e2cd2c5fb6f8.png)

### スクリプト実行ユーザーA (us-admin) の設定
ユーザーA (以後、us-admin) はプロファイルでタイムゾーンおよび日付・時刻フォーマットを変更していないこととします。つまり、上記のSystemの設定値が適用されます。
* タイムゾーン(`time_zone`): `System`
* 日付フォーマット(`date_format`): `System`
* 時刻フォーマット(`time_format`): `System`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1923007/62e5a645-1413-8f43-814e-27c6b1ae5033.png)

### スクリプト実行ユーザーB (jp-admin) の設定
ユーザーB (以後、jp-admin) のプロファイルにおけるタイムゾーンおよび日付・時刻フォーマットは次の通り個別にカスタマイズしているとします。
* タイムゾーン(`time_zone`): `Japan (**GMT+9**)`
* 日付フォーマット(`date_format`): `yyyy/MM/dd`
* 時刻フォーマット(`time_format`): `hh:mm:ss a (12 hour AM/PM)`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1923007/86852dad-040b-a755-67b1-637b7b56f416.png)


## GlideDateTimeオブジェクト

### 確認方法
`var gdt = new GlideDateTime()`で現在時刻を取得したあと、その後に各get系のメソッドで取得するとどうなるか確認します。

スクリプトを実行した日時は **2024-11-30 16:00:00 (GMT)** とします。
また、スクリプトはBackground Scriptで実行することとします。

### スクリプト
```js
var gdt = new GlideDateTime();
gs.info("                              : " + gdt);
gs.info("getValue                      : " + gdt.getValue());
gs.info("getDisplayValue               : " + gdt.getDisplayValue());
gs.info("getDisplayValueInternal       : " + gdt.getDisplayValueInternal());
gs.info("getInternalFormattedLocalTime : " + gdt.getInternalFormattedLocalTime());
gs.info("getUserFormattedLocalTime     : " + gdt.getUserFormattedLocalTime());
gs.info("getDate                       : " + gdt.getDate());
gs.info("getLocalDate                  : " + gdt.getLocalDate());
gs.info("getTime                       : " + gdt.getTime());
gs.info("getLocalTime                  : " + gdt.getLocalTime());
```

#### us-adminでの実行結果
```
*** Script:                               : 2024-11-30 16:00:00
*** Script: getValue                      : 2024-11-30 16:00:00
*** Script: getDisplayValue               : 30-11-2024 08.00.00 AM
*** Script: getDisplayValueInternal       : 2024-11-30 08:00:00
*** Script: getInternalFormattedLocalTime : 08:00:00
*** Script: getUserFormattedLocalTime     : 08.00.00 AM
*** Script: getDate                       : 2024-11-30
*** Script: getLocalDate                  : 2024-11-30
*** Script: getTime                       : 1970-01-01 16:00:00
*** Script: getLocalTime                  : 1970-01-01 08:00:00
```

#### jp-adminでの実行結果
```
*** Script:                               : 2024-11-30 16:00:00
*** Script: getValue                      : 2024-11-30 16:00:00
*** Script: getDisplayValue               : 2024/12/01 01:00:00 AM
*** Script: getDisplayValueInternal       : 2024-12-01 01:00:00
*** Script: getInternalFormattedLocalTime : 01:00:00
*** Script: getUserFormattedLocalTime     : 01:00:00 AM
*** Script: getDate                       : 2024-11-30
*** Script: getLocalDate                  : 2024-12-01
*** Script: getTime                       : 1970-01-01 16:00:00
*** Script: getLocalTime                  : 1970-01-01 01:00:00
```

## 日付・時刻のフィールド (Date/Time, Date, Time)

### 確認方法
incidentテーブルに下記のテスト用フィールドを作成し、各get系のメソッドで値を取得するとどうなるか確認します。

* Date/Time
    * Label : `Test Date/Time`
    * Name  : `u_test_datetime`
    * Value : `2024-11-30 16:00:00` (GMT)
* Date
    * Label : `Test Date`
    * Name  : `u_test_date`
    * Value : `2024-11-30`
* Time
    * Label : `Test Time`
    * Name  : `u_test_datetime`
    * Value : `16:00:00` (GMT)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1923007/60e60354-5d48-8d0d-4652-f2f81a953014.png)


スクリプトを実行した日時は **2024-11-30 16:00:00 (GMT)** とします。
(実行日時は結果に影響はないですが...。)

また、スクリプトはBackground Scriptで実行することとします。

### スクリプト
```js
var gr = new GlideRecord('incident');
gr.get('number', 'INC0000001');

gs.info('Date/Time > getValue        : ' + gr.getValue('u_test_datetime'));
gs.info('Date/Time > getDisplayValue : ' + gr.getDisplayValue('u_test_datetime'));
gs.info('Date      > getValue        : ' + gr.getValue('u_test_date'));
gs.info('Date      > getDisplayValue : ' + gr.getDisplayValue('u_test_date'));
gs.info('Time      > getValue        : ' + gr.getValue('u_test_time'));
gs.info('Time      > getDisplayValue : ' + gr.getDisplayValue('u_test_time'));
```

#### us-adminでの実行結果
```
*** Script: Date/Time > getValue        : 2024-11-30 16:00:00
*** Script: Date/Time > getDisplayValue : 30-11-2024 08.00.00 AM
*** Script: Date      > getValue        : 2024-11-30
*** Script: Date      > getDisplayValue : 30-11-2024
*** Script: Time      > getValue        : 1970-01-01 16:00:00
*** Script: Time      > getDisplayValue : 08.00.00 AM
```

#### jp-adminでの実行結果
```
*** Script: Date/Time > getValue        : 2024-11-30 16:00:00
*** Script: Date/Time > getDisplayValue : 2024/12/01 01:00:00 AM
*** Script: Date      > getValue        : 2024-11-30
*** Script: Date      > getDisplayValue : 2024/11/30
*** Script: Time      > getValue        : 1970-01-01 16:00:00
*** Script: Time      > getDisplayValue : 01:00:00 AM
```