回答:
これを処理するために、json.dumpsに 'default'パラメータを追加できます。
date_handler = lambda obj: (
obj.isoformat()
if isinstance(obj, (datetime.datetime, datetime.date))
else None
)
json.dumps(datetime.datetime.now(), default=date_handler)
'"2010-04-20T20:08:21.634121"'
これはISO 8601形式です。
より包括的なデフォルトのハンドラー関数:
def handler(obj):
if hasattr(obj, 'isoformat'):
return obj.isoformat()
elif isinstance(obj, ...):
return ...
else:
raise TypeError, 'Object of type %s with value of %s is not JSON serializable' % (type(obj), repr(obj))
更新:タイプと値の出力が追加されました。
更新:日付も処理
dthandler = lambda obj: obj.isoformat() if isinstance(obj, datetime) else json.JSONEncoder().default(obj)
言語間プロジェクトの場合、RfC 3339の日付を含む文字列が最適な方法であることを知りました。RfC 3339の日付は次のようになります。
1985-04-12T23:20:50.52Z
ほとんどのフォーマットは明白だと思います。少し変わったのは、最後の "Z"だけかもしれません。これはGMT / UTCの略です。CEST(夏のドイツ)の場合は、+ 02:00のようなタイムゾーンオフセットを追加することもできます。個人的には、表示されるまですべてをUTCで保持することを好みます。
表示、比較、および保存については、すべての言語で文字列形式のままにすることができます。計算に日付が必要な場合は、ほとんどの言語のネイティブ日付オブジェクトに簡単に変換して戻すことができます。
したがって、次のようにJSONを生成します。
json.dump(datetime.now().strftime('%Y-%m-%dT%H:%M:%SZ'))
残念ながら、JavascriptのDateコンストラクターはRfC 3339文字列を受け入れませんが、インターネット上には多くのパーサーがあります。
huTools.hujsonは、タイムゾーンを正しく処理しながら、日付/日付時刻オブジェクトを含むPythonコードで遭遇する可能性のある最も一般的なエンコーディングの問題を処理しようとします。
datetime
ます。datetime.isoformat()とによってサポートされます。デフォルトsimplejson
では、datetime
オブジェクトはisoformat
文字列としてダンプされます。手動でstrftime
ハッキングする必要はありません。
datetime
オブジェクトからisoformat
文字列への自動変換を取得していません。私にとって、simplejson.dumps(datetime.now())
利回りTypeError: datetime.datetime(...) is not JSON serializable
json.dumps(datetime.datetime.now().isoformat())
魔法が起こる場所です。
私はそれを解決しました。
たとえば、datetime.now()で作成されたPythonのdatetimeオブジェクトdがあるとします。その値は次のとおりです。
datetime.datetime(2011, 5, 25, 13, 34, 5, 787000)
ISO 8601日時文字列としてJSONにシリアル化できます。
import json
json.dumps(d.isoformat())
サンプルの日時オブジェクトは次のようにシリアル化されます。
'"2011-05-25T13:34:05.787000"'
この値は、JavaScriptレイヤーで受信されると、Dateオブジェクトを構築できます。
var d = new Date("2011-05-25T13:34:05.787000");
Javascript 1.8.5以降、DateオブジェクトにはtoJSONメソッドがあり、標準形式で文字列を返します。したがって、上記のJavaScriptオブジェクトをシリアライズしてJSONに戻すには、コマンドは次のようになります。
d.toJSON()
それはあなたに与えるでしょう:
'2011-05-25T20:34:05.787Z'
この文字列は、Pythonで受信されると、逆シリアル化してdatetimeオブジェクトに戻すことができます。
datetime.strptime('2011-05-25T20:34:05.787Z', '%Y-%m-%dT%H:%M:%S.%fZ')
これにより、次のdatetimeオブジェクトが生成されます。これは、最初に使用したオブジェクトと同じであり、正しいものです。
datetime.datetime(2011, 5, 25, 20, 34, 5, 787000)
を使用するとjson
、JSONEncoderをサブクラス化してdefault()メソッドをオーバーライドし、独自のカスタムシリアライザーを提供できます。
import json
import datetime
class DateTimeJSONEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime.datetime):
return obj.isoformat()
else:
return super(DateTimeJSONEncoder, self).default(obj)
その後、次のように呼び出すことができます。
>>> DateTimeJSONEncoder().encode([datetime.datetime.now()])
'["2010-06-15T14:42:28"]'
obj.isoformat()
。dumps()
他の便利な引数(などindent
)を取る、より一般的な呼び出しを使用することもできます:simplejson.dumps(myobj、cls = JSONEncoder、...)
標準ライブラリjson
モジュールを使用して、datetime.datetimeおよびdatetime.dateオブジェクトを再帰的にエンコードおよびデコードするためのかなり完全なソリューションを次に示します。%f
datetime.datetime.strptime()フォーマット文字列のフォーマットコードはそれ以降のみサポートされているため、Python> = 2.6が必要です。Python 2.5をサポートするに%f
は、ISO日付文字列からマイクロ秒を削除して削除してから変換しますが、もちろんマイクロ秒の精度が失われます。タイムゾーン名またはUTCオフセットが含まれている可能性がある他のソースからのISO日付文字列との相互運用性のために、変換の前に日付文字列の一部を取り除く必要がある場合もあります。ISO日付文字列(および他の多くの日付形式)の完全なパーサーについては、サードパーティのdateutilモジュールを参照してください。
デコードは、ISO日付文字列がJavaScriptリテラルオブジェクト表記またはオブジェクト内のネストされた構造の値である場合にのみ機能します。トップレベルの配列の項目であるISO日付文字列はデコードされません。
すなわちこれは動作します:
date = datetime.datetime.now()
>>> json = dumps(dict(foo='bar', innerdict=dict(date=date)))
>>> json
'{"innerdict": {"date": "2010-07-15T13:16:38.365579"}, "foo": "bar"}'
>>> loads(json)
{u'innerdict': {u'date': datetime.datetime(2010, 7, 15, 13, 16, 38, 365579)},
u'foo': u'bar'}
そしてこれも:
>>> json = dumps(['foo', 'bar', dict(date=date)])
>>> json
'["foo", "bar", {"date": "2010-07-15T13:16:38.365579"}]'
>>> loads(json)
[u'foo', u'bar', {u'date': datetime.datetime(2010, 7, 15, 13, 16, 38, 365579)}]
しかし、これは期待どおりに機能しません。
>>> json = dumps(['foo', 'bar', date])
>>> json
'["foo", "bar", "2010-07-15T13:16:38.365579"]'
>>> loads(json)
[u'foo', u'bar', u'2010-07-15T13:16:38.365579']
コードは次のとおりです。
__all__ = ['dumps', 'loads']
import datetime
try:
import json
except ImportError:
import simplejson as json
class JSONDateTimeEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, (datetime.date, datetime.datetime)):
return obj.isoformat()
else:
return json.JSONEncoder.default(self, obj)
def datetime_decoder(d):
if isinstance(d, list):
pairs = enumerate(d)
elif isinstance(d, dict):
pairs = d.items()
result = []
for k,v in pairs:
if isinstance(v, basestring):
try:
# The %f format code is only supported in Python >= 2.6.
# For Python <= 2.5 strip off microseconds
# v = datetime.datetime.strptime(v.rsplit('.', 1)[0],
# '%Y-%m-%dT%H:%M:%S')
v = datetime.datetime.strptime(v, '%Y-%m-%dT%H:%M:%S.%f')
except ValueError:
try:
v = datetime.datetime.strptime(v, '%Y-%m-%d').date()
except ValueError:
pass
elif isinstance(v, (dict, list)):
v = datetime_decoder(v)
result.append((k, v))
if isinstance(d, list):
return [x[1] for x in result]
elif isinstance(d, dict):
return dict(result)
def dumps(obj):
return json.dumps(obj, cls=JSONDateTimeEncoder)
def loads(obj):
return json.loads(obj, object_hook=datetime_decoder)
if __name__ == '__main__':
mytimestamp = datetime.datetime.utcnow()
mydate = datetime.date.today()
data = dict(
foo = 42,
bar = [mytimestamp, mydate],
date = mydate,
timestamp = mytimestamp,
struct = dict(
date2 = mydate,
timestamp2 = mytimestamp
)
)
print repr(data)
jsonstring = dumps(data)
print jsonstring
print repr(loads(jsonstring))
datetime.datetime.utcnow().isoformat()[:-3]+"Z"
に日付を出力すると、JSON.stringify()がJavaScriptで生成するものとまったく同じになります
JavaScriptだけがJSONを消費することが確実な場合は、JavaScript Date
オブジェクトを直接渡すことをお勧めします。
オブジェクトのctime()
メソッドはdatetime
、JavaScript Dateオブジェクトが理解できる文字列を返します。
import datetime
date = datetime.datetime.today()
json = '{"mydate":new Date("%s")}' % date.ctime()
Javascriptは喜んでそれをオブジェクトリテラルとして使用し、Dateオブジェクトを組み込みます。
.ctime()
時間情報を渡す.isoformat()
非常に悪い方法ですが、はるかに優れています。何を.ctime()
行うことは、彼らが存在しないように、タイムゾーンと夏時間を捨てています。その機能は殺されるべきです。
ゲームの後半... :)
非常に簡単な解決策は、jsonモジュールのデフォルトにパッチを適用することです。例えば:
import json
import datetime
json.JSONEncoder.default = lambda self,obj: (obj.isoformat() if isinstance(obj, datetime.datetime) else None)
これで、json.dumps()を使用して、あたかもそれが常に日時をサポートしていたかのように...
json.dumps({'created':datetime.datetime.now()})
これは、jsonモジュールへのこの拡張が常に必要であり、あなたや他の人がjsonシリアル化を使用する方法(既存のコードであるかどうかにかかわらず)を変更しないことを望む場合に意味があります。
一部のユーザーは、この方法でライブラリにパッチを適用することを悪い習慣と見なしている場合があります。アプリケーションを複数の方法で拡張したい場合は、特別な注意が必要です。そのような場合、ラーメンまたはJTによるソリューションを使用し、それぞれの場合に適切なjson拡張を選択することをお勧めします。
None
。代わりに例外をスローすることをお勧めします。
タイムスタンプを除いて、コミュニティWikiの回答に追加するものは多くありません。
JavaScriptは次の形式を使用します。
new Date().toJSON() // "2016-01-08T19:00:00.123Z"
Python側(json.dumps
ハンドラーについては、他の回答を参照してください):
>>> from datetime import datetime
>>> d = datetime.strptime('2016-01-08T19:00:00.123Z', '%Y-%m-%dT%H:%M:%S.%fZ')
>>> d
datetime.datetime(2016, 1, 8, 19, 0, 0, 123000)
>>> d.isoformat() + 'Z'
'2016-01-08T19:00:00.123000Z'
そのZを省略した場合、angularなどのフロントエンドフレームワークはブラウザローカルタイムゾーンで日付を表示できません。
> $filter('date')('2016-01-08T19:00:00.123000Z', 'yyyy-MM-dd HH:mm:ss')
"2016-01-08 20:00:00"
> $filter('date')('2016-01-08T19:00:00.123000', 'yyyy-MM-dd HH:mm:ss')
"2016-01-08 19:00:00"
私のアドバイスは、ライブラリを使用することです。pypi.orgにはいくつかのものが用意されています。
私はこれを使用します、それはうまくいきます:https : //pypi.python.org/pypi/asjson
どうやら「正しい」JSON(JavaScriptも)の日付形式は2012-04-23T18:25:43.511Z-UTCおよび "Z"です。このJavaScriptがないと、文字列からDate()オブジェクトを作成するときにWebブラウザのローカルタイムゾーンが使用されます。
「ナイーブ」な時間(Pythonがタイムゾーンのない時間を呼び出し、これがローカルであると想定するもの)の場合、以下はローカルタイムゾーンを強制し、UTCに正しく変換できるようにします。
def default(obj):
if hasattr(obj, "json") and callable(getattr(obj, "json")):
return obj.json()
if hasattr(obj, "isoformat") and callable(getattr(obj, "isoformat")):
# date/time objects
if not obj.utcoffset():
# add local timezone to "naive" local time
# /programming/2720319/python-figure-out-local-timezone
tzinfo = datetime.now(timezone.utc).astimezone().tzinfo
obj = obj.replace(tzinfo=tzinfo)
# convert to UTC
obj = obj.astimezone(timezone.utc)
# strip the UTC offset
obj = obj.replace(tzinfo=None)
return obj.isoformat() + "Z"
elif hasattr(obj, "__str__") and callable(getattr(obj, "__str__")):
return str(obj)
else:
print("obj:", obj)
raise TypeError(obj)
def dump(j, io):
json.dump(j, io, indent=2, default=default)
なぜこれがそんなに難しいのですか。
PythonからJavaScriptへの日付変換では、日付オブジェクトは特定のISO形式、つまりISO形式またはUNIX番号である必要があります。ISO形式に情報が不足している場合は、最初にDate.parseを使用してUnix番号に変換できます。さらに、Date.parseはReactでも機能しますが、新しいDateは例外をトリガーする可能性があります。
ミリ秒のないDateTimeオブジェクトがある場合は、次のことを考慮する必要があります。:
var unixDate = Date.parse('2016-01-08T19:00:00')
var desiredDate = new Date(unixDate).toLocaleDateString();
サンプルの日付は、API呼び出し後のresult.dataオブジェクト内の変数でも同じです。
日付を希望の形式で表示するオプション(長い平日を表示するなど)については、MDNドキュメントをご覧ください。