tyoshikawa1106のブログ

- Force.com Developer Blog -

SFDC:RemoteActionから日付と日時を登録する方法

Visualforceのapexタグをつかってデータ登録するときは、データ型とか特に意識する必要はありませんが、JavaScript Remotingな画面開発ということでRemoteActionをつかって日付/日時を登録する場合は、すこし意識することがあります。


たとえば日付型のsObject項目に値をセットする場合は次のように変換する必要があります。

SLAExpirationDate__c: new Date(accountDate).getTime()
参考

Visualforce × AngularJS - Qiita

日付型に値をセットする方法は確認できましたが、これが日時型の場合はどうなるのか、多言語化対応でユーザの地域が変更されたときはどう対応するのがいいのか、


・・・という疑問が解決していなかったのでこの辺りを調べてみました。

はじめに

JavaScriptで日時を操作する場合、moment.jsというライブラリを利用すると対応がしやすくなるそうです。これを使った方法について確認してみました。

Moment.js | Home

日時の登録方法

Apexの日時型

Apexでは日時型の項目は次のようにDateTime型として宣言します。

public DateTime startTime {get; set;}
HTMLの入力フォーム

HTMLでは時間型の値を入力するためにinputタグにtype="time"が用意されています。これで入力フォームを用意できます。
(このフォームでは時間のみの入力となるため、日付部分は1970-1-1のようなデフォルト値がセットされていました。)

<input name="startTime" ng-model="wrapper.startTimeInput"
        class="slds-input" type="time" required="true" />

f:id:tyoshikawa1106:20160224103841p:plain

RemoteActionで渡す際の変換方法

RemoteActionでこの変数に渡す方法ですが、moment.jsをつかえば次のように宣言するだけで済みました。

moment([year, month, date, hour, minute, second]).toDate().toUTCString();


まずinputタグに入力された日付情報はmoment("要素")で取得できます。

var targetDate = moment(scope.wrapper.workDateInput);

このあとformat()をつかって任意の形式に変換することも可能です。

// 年月日の場合
console.log('targetDate = ' + targetDate.format("YYYY-MM-DD"));
// 時間の場合 (HH=24h表記 / hh=12h表記)
console.log('startTime = ' + startTime.format("HH:mm:ss"));

日付情報を取得したあとは、下記方法で年や月などの情報を取得することができます。

// moment()で取得した日付情報
var d = targetDate;
// 年
var year = d.year();
// 月
var month = d.month();
// 日
var date = d.date();
// 時
var hour = t.hour();
// 分
var minute = t.minute();
// 秒
var second = t.second();

※日はdayではなくdateなので注意してください。


これで最初の方法で日時変換することができます。変換後はRemoteActionでDateTime型の変数にセットできるようになりました。

// 日付取得
var targetDate = moment(scope.wrapper.workDateInput);
// 時間取得
var startTime = moment(scope.wrapper.startTimeInput);
// 日時に変換してセット
scope.wrapper.workTime.startTime = getDateTime(targetDate, startTime);

// 日時変換
function getDateTime(d, t) {
    // 年月日取得
    var year = d.year();
    var month = d.month();
    var date = d.date();
    console.log(year + '-' + (month + 1) + '-' + date);
    // 時分秒取得
    var hour = t.hour();
    var minute = t.minute();
    var second = t.second();
    console.log(hour + ':' + minute + ':' + second);
    // 日時に変換して戻す
    return moment([year, month, date, hour, minute, second]).toDate().toUTCString();
}

f:id:tyoshikawa1106:20160224105833p:plain


登録イメージです。
f:id:tyoshikawa1106:20160224105457p:plain

f:id:tyoshikawa1106:20160224105545p:plain


日時型の値渡しはこんな感じで変換してあげれば大丈夫そうです。

日付の値渡し

日付の場合ですが、まず次の方法でinput type="date"で入力された値を確認してみました。

// 対象日付取得
var targetDate = moment(scope.wrapper.workDateInput);
console.log('targetDate = ' + targetDate.format("YYYY-MM-DD HH:mm:ss"));

これで入力した日付かつ0時0分0秒の値を取得できることを確認できました。
f:id:tyoshikawa1106:20160224110409p:plain


ということで次の書き方で問題なさそうです。

// 日付変換
function getDate(d) {
    return moment(d).toDate().toUTCString();
}


確認して見るとこんな感じ
f:id:tyoshikawa1106:20160224110803p:plain

f:id:tyoshikawa1106:20160224110841p:plain


これでinput type="date" で入力された値も無事にApexに渡して保存できました。今回は時間部分に9時間のズレがでていないか確認するためにDateTime型の項目に値を登録して確認しましたが、Date型の項目にも同じように保存できると思います。

多言語化

ユーザのタイムゾーンを変更したケースです。
f:id:tyoshikawa1106:20160224112257p:plain


情報方法ではSalesforceユーザのタイムゾーンが日本時間でない場合にズレが発生しました。
f:id:tyoshikawa1106:20160224112508p:plain


正確には日本のタイムゾーンとして日時登録されていました。
f:id:tyoshikawa1106:20160224112541p:plain


多言語化対応が必要な場合に関してはもう少し考慮が必要そうです。


多言語化の問題だけ残っていますが、ひとまず上記方法でapexタグに頼らないJavaScript Remotingメインの画面開発でも日付/日時を登録できると思います。