
文字列や配列、オブジェクト、booleanはシリアライザブルである認識なのですが、Dateオブジェクトのインスタンスはシリアライザブルでしょうか?
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。


回答5件
0
JavaScript のタグなので
シリアライザブル = JSON
として回答します。Date オブジェクトはシリアライザブルではありません。一般的に JSON に日付を出力する際は
- ISO 8601 形式の文字列
- RFC3339 形式の文字列
- epoch 秒数
のいずれかを格納する事が多くいです。その中でも見ただけで日付と分かり、多くの JSON パーサがサポートしている RFC3339 を使うのが良いと思います。
2017-08-22T23:59:60Z
投稿2017/08/21 23:51
総合スコア5030
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/08/22 01:35 編集
2017/08/22 01:33
2017/08/23 16:27 編集
2017/08/22 15:28
2017/08/24 12:59 編集

退会済みユーザー
2017/08/24 12:05
2017/08/24 13:16

0
JSONでは無理です。
###JSONは無理
ES5準拠のほとんどのブラウザであれば、Date.prototype.toJSONやJSON.stringifyによって文字列化してシリアライズし、デシリアライズではその文字列をDate.parseやnew Dateで読み取ることはできるでしょう。(古いブラウザではできません。また、なにやら実装ずれがあるようで、最新のブラウザでも全てのブラウザでできるとは限らないようです。)
JavaScript
1const date = new Date(); 2console.log(date); 3console.log(date.constructor); 4const json = JSON.stringify(date); 5console.log(json); 6const newDate = new Date(JSON.parse(json)); 7console.log(newDate); 8console.log(newDate.constructor)
しかし、この方法には致命的な欠点があります。それは、日時っぽい文字列と日時を表す文字列を区別できないと言うこと、つまりは、それが日時として解釈して良いのか判断付かないと言うことです。
実際に.toJSON()やJSON.stringify()した場合、"2017-08-22T14:58:32.352Z"
という文字列になります。JSON上では、これが元々Dateを表していたのか、それとも初めからこういう文字列だったのかを判断することはできません。JSONにはそういった日時のデータの場合の表し方が規定されておらず、単なる文字列としてしか表現しようがないからです。
何が言いたいかというと、JSONだけでは、JSONの中のデータがDateのような日時を表すデータであると言うことを示すことができないと言うことです。それではオブジェクトを正確にシリアライズ化できたのは言えないと思います。
JavaScript
1const date = '2017-08-22T14:58:32.352Z'; 2console.log(date); 3console.log(date.constructor); 4const json = JSON.stringify(date); 5console.log(json); 6const newDate = new Date(JSON.parse(json)); 7console.log(newDate); 8console.log(newDate.constructor)
最初に渡しているものが文字列なのに、同じようにDateになってしまいます。
###YAMLでやってみよう
では、どうするか。答えは簡単です。JSONで無ければ良いのです。日時データを日時データとして扱えるようなフォーマット形式、例えばYAMLやBSONを使えば良いのです。js-yamlを使用したYAMLの場合は次のようになります。(import文を使用していますので、対応していない環境ではBabelを使って変換してください)
JavaScript
1import YAML from 'js-yaml'; 2const date = new Date(); 3console.log(date); 4console.log(date.constructor); 5const yaml = YAML.dump(date); 6console.log(yaml); 7const newDate = YAML.load(yaml); 8console.log(newDate); 9console.log(newDate.constructor)
もし、Dateではなく文字列を渡した場合も見てください。
JavaScript
1import YAML from 'js-yaml'; 2const date = '2017-08-22T14:58:32.352Z'; 3console.log(date); 4console.log(date.constructor); 5const yaml = YAML.dump(date); 6console.log(yaml); 7const newDate = YAML.load(yaml); 8console.log(newDate); 9console.log(newDate.constructor)
文字列が文字列のままであったことが確認できると思います。これは、YAMLでは日付のデータの書き方が規定されており、それと全く同じ文字列とは厳密に区別できるからです。
###それでもJSONを使いたい
それでもやはり、JSONを使いたいと思うかも知れません。その場合は、この部分は日付であるというのが決め打ちされたJSONになることに注意するしかありません。それは、解釈が決め打ちされたJSONであって、汎用的なJSONでは無い、どこに持って行っても同じ解釈をされるJSONではない、と言うことに注意が必要です。
なお、Date.parse等のブラウザ間の実装の違いが気になる場合は、Momemnt.jsを使うことをお勧めします。.NET独自のJSONのDate形式まで対応していますので、どんな形式で作られていようが大抵は対応できます。でも、.NET形式への変換はできないようです。せっかくSurferOnWwwさんが.NETの場合について色々説明してくれているのに、JavaScriptでは実現できる方法が見つけられなくて、ごめんなさい。
ただ、ここの文字列は日時を表すと決め打ちし、読み込ませないと行けないことには変わりありません。
投稿2017/08/22 15:46
編集2017/08/22 15:57総合スコア21741
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/08/22 16:39 編集
2017/08/23 11:38

退会済みユーザー
2017/08/24 12:05

0
ISO 8601 拡張形式 (RFC3339)
既に回答が出ているように、ECMAScript 2017 では、日付と認識可能な文字列として ISO 8601 拡張形式 を定義しています。
ISO 8601 拡張形式は曖昧な部分がある為、RFC3339 でも再定義しているようです。
しかし、ISO 8601 は有料で文書をDLする仕組みのようで対象の曖昧とする部分は確認できませんでした。
下記に各々のリンク先を示します。
- 20.3.1.16 Date Time String Format - ECMAScript® 2017 Language Specification
- RFC3339 インターネット上の日付と時間:タイムスタンプ
- ISO 8601:2004 - Data elements and interchange formats -- Information interchange -- Representation of dates and times
この回答では、ECMAScript 2017が定義する「ISO 8061拡張形式」を基準に説明します。
ECMAScript 2017 では YYYY-MM-DDTHH:mm:ss.sssZ もしくは YYYY-MM-DDTHH:mm:ss.sss[+-]HH:mm の形式として「ISO 8601 拡張形式」を定義しています。
- YYYY … グレゴリオ暦の0000〜9999桁の10進数。
- MM … 01(1月)から12(12月)までの年の月。
- DD … 01から31までの月の日。
- T … 時間要素の始まりを示す文字(訳注: Time の "T" と思われます)
- HH … 深夜0時から24侍を表した、00から24までの2桁の10進数(24時間法)
- : 「時間:分:秒」を区切る為の区切り文字(セパレータ)
- mm … 何時何分における何分を表す00から59までの2桁の10進数
- ss … 0分から1分までの間に存在する2桁の10進数00から59からなる秒数
- . … 「秒.ミリ秒」を区切る為の区切り文字(セパレータ)
- sss 3桁の10進数に構成されるミリ秒
- Z … UTC日時の場合、文字列の終端を表す(タイムゾーン指定子)
- [+-]HH:mm … タイムゾーンとなるUTCからの時差を表す。"+09:00" はUTCから「+9時間」の時差を表し、"-01:00" はUTCから「-1時間」の時差を表す(タイムゾーン指定子)
他にも次のルールがあります。
- ゼロパディングが必須です。
"2017-01-01"
を"2017-1-1"
のようにゼロを切り詰めて表現する事は出来ません(MUST)。 - タームゾーン識別子が省略された場合、UTC として扱われます。
- 後方にある値は一部省略する事が可能です。省略された値は最も小さな値として扱われます。
省略規則はやや特殊な為、コード事例をあげます。
JavaScript
1new Date("2017-08-23T12:00:00.000+09:00").toISOString(); // "2017-08-23T03:00:00.000Z" 2new Date("2017-08-23T12:00:00.000").toISOString(); // "2017-08-23T03:00:00.000Z" 3new Date("2017-08-23T12:00:00").toISOString(); // "2017-08-23T03:00:00.000Z" 4new Date("2017-08-23T12:00").toISOString(); // "2017-08-23T03:00:00.000Z" 5new Date("2017-08-23T12").toISOString(); // RangeError: Invalid time value 6new Date("2017-08-23").toISOString(); // "2017-08-23T00:00:00.000Z" 7new Date("2017-08").toISOString(); // "2017-08-01T00:00:00.000Z" 8new Date("2017").toISOString(); // "2017-01-01T00:00:00.000Z"
HH:mm
から HH
に省略できない事を除いて、後ろの要素を省略可能な事が分かります。
JSONにシリアライズした日付文字列を組み込む場合
オブジェクト初期化子や配列に格納した new Date
にまつわるシリアライズに関しては、非常に複雑でこの回答には書ききれない為、下記リンク先にまとめました。
- ECMAScript 2017 に準拠した方法で Date オブジェクトをシリアライズ(文字列化)する - Qiita
- json-for-date.js: DateオブジェクトをJSON拡張形式にシリアライズ/パースの相互変換
Re: hayatomo さん
投稿2017/08/23 11:24
編集2017/08/23 11:24総合スコア18194
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

退会済みユーザー
2017/08/24 12:04

0
ベストアンサー
多分hayatomoさんはイケてるプログラマになるために必死に勉強中なのでしょう。
JSON云々じゃなくて、本来の意味が知りたいハズなので、他の回答者さんとは違う視点で回答するよ。
そもそもシリアライザブルとはserializableと書くように、
末尾に「able」の付く単語は○○が可能であるという意味の名詞。
そしてシリアライザブルというのは直列化を指す。
http://www.task-notes.com/entry/20150925/1443150000
厳密な意味で言うとストリームなんだけど、JSON.stringifyのように「後で復号できる文字列」に変換する事もほぼ同義なので、
文字列化してテキストファイルやDB等に保存する行為もシリアライズと呼んでも良さそうだね。
シリアライズ - wikipedia
Dateオブジェクトのインスタンスはシリアライザブルでしょうか?
そもそもシリアライズという言葉自体がJavaの用語であり、JavaScritptの用語ではない。
なので単に「JavaScript」「シリアライズ」と聞いても誰も回答出来ないわけだ。
ちゃんとモノやライブラリの対象といった範囲を示す必要があるわけだね。
残念ながらJSONの様式ではDateは定義されていないけど、
本来の意味に近い「後で復号可能な文字列に変換出来るか否か」で言えばDateはシリアライザブル。
JavaScriptのDateはミリ秒までを記憶するから、YYYY-MM-DDThh:mm:ss.zzzZ
の形式の文字列にして、後でnew Dateに突っ込めばいい。
その気になれば関数や正規表現のパターンも文字列にして後で復号できるし、
自分で作ったインスタンスもプロパティを退避させて後でnewして復号出来る作りにしておけば良いわけだ。
JavaScript
1var bk_add = function(a, b) { return a + b; }; 2console.log(bk_add(1, 3)); 3// 4 4 5eval("var add = " + bk_add.toString()); 6console.log(add(1, 4)); 7// 5 8 9var re = /hoge/; 10console.log(re); 11// /hoge/ 12 13// ※ただしJSのRegExpの仕様の問題で復号は少し面倒 14console.log(new RegExp(re.toString())); 15// /¥/hoge¥// 復号出来てないのでアウト 16 17console.log(new RegExp("hoge")); 18// /hoge/ こうすれば良いが区切り文字や正規表現フラグの処理を行う必要あり
JSON程メジャーではないが、出来る限り文字列化を頑張るライブラリも存在する。
serialize-javascript - npm
長々と語ったけど、
そもそも通信やファイル保存が目的になるから
「これはシリアル化出来ませんごめんなさい」は通用しない。
お 前 が 工 夫 し て シ リ ア ル 化 す る ん だ よ !!!
そういう視点で見ると、効率はさておき大抵のものはシリアル化することは可能だから、
広義の意味でいうと大抵のものはシリアライザブルと呼べる。
なので他の回答者は一言目に「JSONだと仮定します」って言ったわけ。
投稿2017/08/22 13:46
編集2017/08/22 14:02総合スコア21393
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

退会済みユーザー
2017/08/24 12:03

0
上の「質問への追記・修正、ベストアンサー選択の依頼」にコメントしましたが、もう少し詳しく回答欄に書いておきます。
Dateオブジェクトのインスタンスはシリアライザブルでしょうか?
JavaScript タグが付いているので、質問者さんの言われる「Dateオブジェクト」とは JavaScript の Data オブジェクトのことと理解しています。
Date
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date
「シリアライザブルでしょうか? 」というのは、JSON 文字列にシリアライズできるか・・・すなわち以下の記事で言う value として設定できるかということだとすると、できないということになります。(直接設定できるのは string, number, object, array, true, false, null)
JSON の紹介
http://www.json.org/json-ja.html
ただし、Date を string に変換して JSON 文字列に設定することはできます。
変換は自力で行わなくても、例えば、JavaScript なら JSON.stringify() メソッド、.NET Framework なら DataContractJsonSerializer クラスを利用すれば自動的に変換してくれます。(ただし変換結果は異なります)
JSON.stringify()
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
DataContractJsonSerializer クラス
https://msdn.microsoft.com/ja-jp/library/system.runtime.serialization.json.datacontractjsonserializer(v=vs.110).aspx
JSON.stringify() メソッドを使用した場合、例えば以下のコードを IE11 で実行し Visual Studio のデバッガで結果を見ると、
var dateTime = new Date(2017, 1, 1, 12, 15, 45); var dateObject = { DateTime: dateTime }; var dateJson = JSON.stringify(dateObject);
dateJson = "{"DateTime":"2017-02-01T03:15:45.000Z"}" となります。
(注:Date コンストラクタの引数で月を表す整数値は 0 (1月) から 11 (12月) なので、1 ⇒ 02 という結果になっている。時間の 12 が 03 になるのは Utc に変換されるため)
DataContractJsonSerializer クラスの方は、JSON.stringify() メソッドとは異なり、.NET Framework の DateTime 型は /Date(836406000000+0900)/ のようにシリアル化されます。詳しくは以下の MSDN ライブラリの記事の「高度な情報 / DateTime ワイヤ形式」のセクションの説明を見てください
スタンドアロン JSON のシリアル化
https://msdn.microsoft.com/ja-jp/library/bb412170(v=vs.110).aspx
投稿2017/08/22 04:31

退会済みユーザー
総合スコア0
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

退会済みユーザー
2017/08/24 12:05

あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。