新しいカスタムフィールド型「時間」を使ってみた

##ようこそ、「時間」型の世界へ
「時間」型は日付を含まず、時間のみを保持できる項目です。
現在がベータですが、Summer 18 で　GA が予定されています。
およそ 11 年ほど前から Idea Exchange に登録されていたのですが、ようやく実装される目処が立ったようですね。

##ユースケース
例えば、一定期間の間で繰り返されるようなイベントやスケジュールを管理する時に便利そうですね。
<img width="400" alt="Screen_Shot_2018-04-02_at_15_33_13.png" src="https://qiita-image-store.s3.amazonaws.com/0/26378/9ef09488-49ad-c476-0b0d-af247b312987.png">

##常に GMT として扱われるという落とし穴
<img width="400" alt="Screen_Shot_2018-04-02_at_15_35_09.png" src="https://qiita-image-store.s3.amazonaws.com/0/26378/4d0672e6-607a-507d-302e-95a598498f19.png">

時間項目の標準の入力フィールドから入力された時間は、ユーザーのロケールに関わらず常に GMT として扱われ保存されます。
これは、GA　で解消して欲しい所です。

##出力は数式で解消
表示の方は数式で +9 時間(32400,000ミリ秒)してしまえばいいと思いました。

```java:開始時間(日本標準時)を数式項目で作成
LEFT(TEXT(Start_Time__c + 32400000),2) & ':' & RIGHT(LEFT(TEXT(Start_Time__c + 32400000),5),2)
```

<img width="400" alt="Screen Shot 2018-04-02 at 15.35.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/26378/a6448648-9c4c-f781-6e81-5d26ae8bdc47.png">

##入力は「選択リスト +　ワークフロールール + 項目自動更新」という力技
入力に関しては、ユーザー側に常に時差を計算してもらうのは負担が大きく運用として現実的ではないですよね。
ユーザーの混乱は必至。

それでも、時間項目が絶対必要！という特殊な環境におられる方には、選択リストとワークフロールールを使う方法をご紹介します。
端的には、時間項目を UI 上で利用する事を諦めて、「時」と「分」をそれぞれ選択リストで作成し、ワークフロールールと項目自動更新で時間項目に反映という方法です。

<img width="400" alt="Screen_Shot_2018-04-02_at_19_13_26.png" src="https://qiita-image-store.s3.amazonaws.com/0/26378/f01f597a-ef01-8a3c-e718-a2b33bf0b7da.png">

ちなみに、「時」と「分」の選択値は繰り返し使う事があると思うので、グローバル値として作成するのがおすすめします。

<img width="400" alt="Screen_Shot_2018-04-02_at_17_28_16.png" src="https://qiita-image-store.s3.amazonaws.com/0/26378/8ad04ec6-783b-b966-9e41-111f1e09eb8e.png">

そして、以下の要領でワークフルールールと項目自動更新を設定します。

###項目自動更新を作成
<img width="400" alt="Screen Shot 2018-04-02 at 18.42.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/26378/6e194567-76bf-5b4a-07f5-580bbcb36090.png">

```java:数式の値
TIMEVALUE( TEXT(Start_Time_Hour_JST__c) & ':' & TEXT(Start_Time_Minute_JST__c) & ':00.000' ) - 32400000
```

###ワークフロールールを作成
<img width="400" alt="Screen_Shot_2018-04-02_at_18_44_16.png" src="https://qiita-image-store.s3.amazonaws.com/0/26378/c19f3c98-c929-6209-1782-9bd0edaecdd9.png">


```java:ルール条件
OR(ISNEW(), 
OR (ISCHANGED( Start_Time_Hour_JST__c ) , ISCHANGED( Start_Time_Minute_JST__c )))
```

### ワークフロールール + 項目自動更新 を Apex で代替
ワークフロールールと項目自動更新の代わりに、トリガを書くこともできます。
コードを書ける方であれば、こちらのほうが早いかもしれません。
お好きな方をお試しください。

```java:MeetingTrigger.apxt
trigger MeetingTrigger on Meeting__c (before insert, before update) {
    if (Trigger.isBefore && Trigger.isInsert) {
        for (Meeting__c newMeeting : Trigger.new) {

            // 選択リストの値(時と分)を数値型に変換する
            Integer startTimeHour = Integer.valueOf(newMeeting.Start_Time_Hour_JST__c);
            Integer startTimeMinute = Integer.valueOf(newMeeting.Start_Time_Minute_JST__c);
            
            // 時間型のインスタンスを作成する。
            Time startTimeJST = Time.newInstance(startTimeHour, startTimeMinute, 0, 0);
            
            // JST(+09:00) から GMT(+00:00) に変換する
            Time startTimeGMT = startTimeJST.addHours(-9);
            
            // 時間項目を更新する
            newMeeting.Start_Time__c = startTimeGMT;
        }
    } else if (Trigger.isBefore && Trigger.isUpdate) {
        for (Meeting__c newMeeting : Trigger.new) {
            
            // 更新の場合、選択リストが変更されている時にのみ、時間項目を更新する。
            // 同時に時間項目が直接更新された場合は、選択リストの値で上書きされていますので注意
            Meeting__c oldMeeting = Trigger.oldMap.get(newMeeting.Id);
            if (newMeeting.Start_Time_Hour_JST__c != oldMeeting.Start_Time_Hour_JST__c || 
                newMeeting.Start_Time_Minute_JST__c != oldMeeting.Start_Time_Minute_JST__c) {
                    newMeeting.Start_Time__c = Time.newInstance(Integer.valueOf(newMeeting.Start_Time_Hour_JST__c), 
                                                                Integer.valueOf(newMeeting.Start_Time_Minute_JST__c),
                                                                0, 0).addHours(-9);
            }
        }
    }
}
```

##まとめ
時間項目を日本標準時で利用するには、まだまだ厳しい状況です。
しかし、入力には選択リスト +　ワークフロールール + 項目自動更新、出力には数式を使うことでほとんど問題なく利用できるのではないでしょうか？
とはいえ、現在はベータなので無理せず GA まで待つのが無難だと思います！