質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

3回答

3822閲覧

Rubyで"UTC"な日時をto_jsonした文字列がmoment.jsで直接解釈できない

raccy

総合スコア21735

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2016/06/26 02:09

RubyでTimeオブジェクトをto_jsonをした場合、次のような形になります。

JSON

1["2016-06-26 00:00:00 +0900","2016-06-25 15:00:00 UTC"]

二つはタイムゾーンが異なるだけで、全く同じ日時です。この二番目の文字列をmoment.jsを使ってパースしようとしたときに、うまくいきません。

JavaScript

1var t = "2016-06-25 15:00:00 UTC"; 2new Date(t); // Sun Jun 26 2016 00:00:00 GMT+0900 3 4moment(t); // Sat Jun 25 2016 15:00:00 GMT+0900 5moment(t, 'YYYY-MM-DD HH:mm:ss Z'); // Sat Jun 25 2016 15:00:00 GMT+0900

new Date()ではゾーンの情報(UTCの部分)も見てくれます。しかし、momemnt()では、そのまま渡した場合も、ゾーン情報ありとしてフォーマットを指定した場合もゾーン情報が無視されて、9時間前になってしまいます。

そこで、下記のようにすることで、なんとかゾーンを見てくれるようになりました。

JavaScript

1moment(new Date(t)); // Sun Jun 26 2016 00:00:00 GMT+0900 2moment(t.replace('UTC', '+0000'), 'YYYY-MM-DD HH:mm:ss Z'); // Sun Jun 26 2016 00:00:00 GMT+0900

一旦new Date()でパースさせてしまうか、ゾーンを"±hhmm"の形にしてしまうと、一応はうまくいきます。

###聞きたいこと

上二つの解決方法のいずれも、一旦Dateにするとか、文字列を置換するとか、余計とも思えるような処理が入っており、しっくりきません。moment.jsで"UTC"を直接読めるような方法が本当はあるのではないかと思っているのですが、そのような方法は無いのでしょうか?

###その他の情報
JSONを出している側はRubyのSinatraで作成しています。直接Timeオブジェクトが含まれるHashやArrayをto_jsonする場合と、mongodbから取得したBSONオブジェクトをto_jsonする場合があります。Timeオブジェクトは"+0900'に統一できているのですが、BSONはタイムゾーン情報が無いためか常に"UTC"になります。このため、JSONを出している側で調整は難しいと考えています。

作成中のWebアプリは利用者が非常に限定(2〜3人ぐらい)されているため、ブラウザはGoogle Chromeのみターゲットにしています。Google Chromeで動作すれば、ブラウザを選ぶような解決方法でもかまいません。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

UTC という文字列からのパースはサポートされていません.

対応フォーマット表
イメージ説明
公式ドキュメントから

そして,文字列へのフォーマットも UTC という文字列での表示形式のサポートはしていないみたいです.(昔はあったっぽい,そして moment-timezone には今もあるっぽい)

イメージ説明

https://github.com/moment/moment/issues ここから,enhancement として要望を出してみると良いかもしれません.

代替案

active-model-serializer を使って,バックエンド側のARからjsonを生成するときに,Date format を整形するのはいかがでしょうか.

https://github.com/rails-api/active_model_serializers

追記

あ,mongoDB だから ORマッパーは使ってないのですね...失礼しました.

投稿2016/06/29 09:51

編集2016/06/29 09:54
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

raccy

2016/06/29 10:31 編集

はい、bsonをjsonにして直接渡すだけなのでORMなんて無粋な物は使ってないです。Mongoidすら使ってませんから。 やっぱり駄目っぽそうですね。とりあえずいったんnew Date()する今の対応でしばらくいきたいと思います。JavaScriptのDateは駄目すぎるし、かといってmoment.jsも完璧じゃないと…やはりここは全てOpalにすることを検討すべきか…
guest

0

momentにtimezoneを付け加えた,moment-timezone を使うのはどうでしょうか?

javascript

1var moment = require('moment-timezone'); 2 3var sample1 = '2016-06-26 00:00:00 +0900'; 4var sample2 = '2016-06-25 15:00:00 UTC'; 5 6console.log(moment(sample1).format('YYYY-MM-DD HH:mm:ss Z')); 7// => 2016-06-26 00:00:00 +09:00 8console.log(moment.utc(sample2).tz('Asia/Tokyo').format('YYYY-MM-DD HH:mm:ss Z')); 9// => 2016-06-26 00:00:00 +09:00 10console.log(moment(sample1).isSame(moment.utc(sample2))); 11// => true

追記

ただし,mongoDBから取得したUTCであるか,それともSinatra側で生成したJSTか,判断する情報がなければ,.utc()を呼べばいいかわからないので,APIか何かのレスポンスにis_utc みたいなものが必要かもしれません.

投稿2016/06/26 05:09

編集2016/06/26 05:12
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

raccy

2016/06/26 05:26

決め打ちでunc()をしちゃうと言うのは確かにありですね。 mongodbからのデータの場合は、mongodb特有のIDが付いてくるのでそれで判断はできると思っています。でも、それで条件分岐するのもなんか嫌な形になると思っています。なるべく同じコードでエレガントに…そんな方法がほしいのです。
退会済みユーザー

退会済みユーザー

2016/06/26 05:31

ではすべてのタイムゾーンに対して, .utc().tz('Asia/Tokyo') でゴリおしてしまう...という手もあります,if 文が消えることがエレガントとするのであれば,エレガントかも知れませんが,普通に考えてエレガントではないですね... ``` var moment = require('moment-timezone') var sample1 = '2016-06-26 00:00:00 +0900'; var sample2 = '2016-06-25 15:00:00 UTC'; console.log(moment.utc(sample1).tz('Asia/Tokyo').format('YYYY-MM-DD HH:mm:ss Z')); // => 2016-06-26 00:00:00 +09:00 console.log(moment.utc(sample2).tz('Asia/Tokyo').format('YYYY-MM-DD HH:mm:ss Z')); // => 2016-06-26 00:00:00 +09:00 console.log(moment(sample1).isSame(moment.utc(sample2))); // => true ```
guest

0

試せていないので申し訳ないですが、UTCを扱う関数はあるようです。ただ、そのままパースできると思うので、moment.js のバージョンを確認してみてはいかがでしょうか。

JavaScript

1// http://momentjs.com/docs/#/parsing/utc/ 2// http://momentjs.com/docs/#/manipulating/utc-offset/ 3// http://momentjs.com/docs/#/parsing/parse-zone/ 4var s = "2013-01-01T00:00:00-13:00"; 5moment(s).utcOffset(s);

【Moment.js | Docs】
http://momentjs.com/docs/#/parsing/utc/

【.zone() always returns the local zone · Issue #611 · moment/moment · GitHub】
https://github.com/moment/moment/issues/611#issuecomment-16916541
(「ゾーンが無視される」に対して「直った」と返していると思う)

投稿2016/06/26 03:56

kei344

総合スコア69400

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

raccy

2016/06/26 04:18

示していただいたコードだと"Fri Jun 24 2016 05:00:00 GMT-2500"になってしまいました。 moment.jsは、npm installで取得して確認していますので最新の2.13.0です(実環境も先日bower installで取ったばかりなので同じバージョンのはずです)。"+0000"とかであれば正常にパースはできるのですが、"UTC"という形での指定だとうまくパースしてくれないのが悩みなのです。Ruby側から"+0900"と"UTC"どちらがくるかわからないため、"UTC"だと決め打ちすることもできません。
kei344

2016/06/26 05:13

いくつか試してみましたが、やはりUTCを関係の無い文字列として除外していますね。 https://jsfiddle.net/broto8ur/1/ 質問で書かれている対策が手早いものだと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問