web-dev-qa-db-ja.com

JavaScriptの日付をJSON文字列化し、タイムゾーンを保持する方法

ユーザーによって作成された日付オブジェクトがあり、タイムゾーンはブラウザによって入力されます。

_var date = new Date(2011, 05, 07, 04, 0, 0);
> Tue Jun 07 2011 04:00:00 GMT+1000 (E. Australia Standard Time)
_

ただし、文字列化すると、タイムゾーンはさようなら

_JSON.stringify(date);
> "2011-06-06T18:00:00.000Z"
_

ブラウザのタイムゾーンを維持しながらISO8601文字列を取得する最良の方法は、moment.jsを使用し、moment.format()を使用することですが、もちろん、 _JSON.stringify_内部(この場合、AngularJS)

_var command = { time: date, contents: 'foo' };
$http.post('/Notes/Add', command);
_

完全を期すために、私のドメインdoesにはローカル時間とオフセットの両方が必要です。

46
XwipeoutX

Dateを含む何らかの種類のオブジェクトがあると仮定します。

var o = { d : new Date() };

toJSONプロトタイプのDate関数をオーバーライドできます。ここでは、moment.jsを使用して日付からmomentオブジェクトを作成し、パラメーターなしでモーメントのformat関数を使用します。これにより、オフセットを含むISO8601拡張形式が生成されます。

Date.prototype.toJSON = function(){ return moment(this).format(); }

これで、オブジェクトをシリアル化するときに、要求した日付形式が使用されます。

var json = JSON.stringify(o);  //  '{"d":"2015-06-28T13:51:13-07:00"}'

もちろん、それはallDateオブジェクトに影響します。特定の日付オブジェクトのみの動作を変更する場合は、次のように、特定のオブジェクトのtoJSON関数のみをオーバーライドできます。

o.d.toJSON = function(){ return moment(this).format(); }
64

Matt Johnsonsの answer に基づいて、toJSONに依存せずにmomentを再実装しました(これは素晴らしいライブラリであると思いますが、 toJSONのような低レベルのメソッドが気になります)。

Date.prototype.toJSON = function () {
  var timezoneOffsetInHours = -(this.getTimezoneOffset() / 60); //UTC minus local time
  var sign = timezoneOffsetInHours >= 0 ? '+' : '-';
  var leadingZero = (Math.abs(timezoneOffsetInHours) < 10) ? '0' : '';

  //It's a bit unfortunate that we need to construct a new Date instance 
  //(we don't want _this_ Date instance to be modified)
  var correctedDate = new Date(this.getFullYear(), this.getMonth(), 
      this.getDate(), this.getHours(), this.getMinutes(), this.getSeconds(), 
      this.getMilliseconds());
  correctedDate.setHours(this.getHours() + timezoneOffsetInHours);
  var iso = correctedDate.toISOString().replace('Z', '');

  return iso + sign + leadingZero + Math.abs(timezoneOffsetInHours).toString() + ':00';
}

setHoursメソッドは、指定された値が「オーバーフロー」するときに、日付オブジェクトの他の部分を調整します。 [〜#〜] mdn [〜#〜] から:

指定したパラメーターが予想範囲外の場合、setHours()は、それに応じてDateオブジェクトの日付情報を更新しようとします。たとえば、secondsValueに100を使用すると、分は1だけ増加し(minutesValue + 1)、40は秒に使用されます。

21
bvgheluwe

ただし、文字列化すると、タイムゾーンはさようなら

Tue Jun 07 2011 04:00:00 GMT+1000 (E. Australia Standard Time)は実際にはtoStringオブジェクトのDateメソッドの結果であるのに対し、stringifytoISOStringメソッドを呼び出すようだからです代わりに。

したがって、toString形式が必要な場合は、単に文字列化してくださいthat

JSON.stringify(date.toString());

または、後で「コマンド」を文字列化するため、最初にthat valueをそこに入れます。

var command = { time: date.toString(), contents: 'foo' };
8
CBroe

日付のようなシステムオブジェクトのプロトタイプ内の関数を混乱させないように常に気を配ります。コードで後で予期しない方法でそれがいつ噛み付くかはわかりません。

代わりに、JSON.stringifyメソッドは「replacer」関数を受け入れます( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#The_replacer_parameter )提供でき、JSON.stringifyがその「文字列化」を実行する方法の内部をオーバーライドできます。したがって、このようなことを行うことができます。

var replacer = function(key, value) {

   if (this[key] instanceof Date) {
      return this[key].toUTCString();
   }
   
   return value;
}

console.log(JSON.stringify(new Date(), replacer));
console.log(JSON.stringify({ myProperty: new Date()}, replacer));
4
Shawson

let date = new Date(JSON.parse(JSON.stringify(new Date(2011、05、07、04、0、0))));

0
sujithklr93