JSON datetime between Python and JavaScript

2025-02-05 13:24:00
admin
原创
120
摘要:问题描述:I want to send a datetime.datetime object in serialized form from Python using JSON and de-serialize in JavaScript using JSON. What is the best way to...

问题描述:

I want to send a datetime.datetime object in serialized form from Python using JSON and de-serialize in JavaScript using JSON. What is the best way to do this?


解决方案 1:

You can add the 'default' parameter to json.dumps to handle this:

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"'

Which is ISO 8601 format.

A more comprehensive default handler function:

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))

Update: Added output of type as well as value.

Update: Also handle date

解决方案 2:

For cross-language projects, I found out that strings containing RFC 3339 dates are the best way to go. An RFC 3339 date looks like this:

  1985-04-12T23:20:50.52Z

I think most of the format is obvious. The only somewhat unusual thing may be the "Z" at the end. It stands for GMT/UTC. You could also add a timezone offset like +02:00 for CEST (Germany in summer). I personally prefer to keep everything in UTC until it is displayed.

For displaying, comparisons and storage you can leave it in string format across all languages. If you need the date for calculations easy to convert it back to a native date object in most language.

So generate the JSON like this:

  json.dump(datetime.now().strftime('%Y-%m-%dT%H:%M:%SZ'))

Unfortunately, JavaScript's Date constructor doesn't accept RFC 3339 strings, but there are many parsers available on the Internet.

huTools.hujson tries to handle the most common encoding issues you might come across in Python code including date/datetime objects while handling time zones correctly.

解决方案 3:

I've worked it out.

Let's say you have a Python datetime object, d, created with datetime.now(). Its value is:

datetime.datetime(2011, 5, 25, 13, 34, 5, 787000)

You can serialize it to JSON as an ISO 8601 datetime string:

import json
json.dumps(d.isoformat())

The example datetime object would be serialized as:

'"2011-05-25T13:34:05.787000"'

This value, once received in the JavaScript layer, can construct a Date object:

var d = new Date("2011-05-25T13:34:05.787000");

As of JavaScript 1.8.5, Date objects have a toJSON method, which returns a string in a standard format. To serialize the above JavaScript object back to JSON, therefore, the command would be:

d.toJSON()

Which would give you:

'2011-05-25T20:34:05.787Z'

This string, once received in Python, could be deserialized back to a datetime object:

datetime.strptime('2011-05-25T20:34:05.787Z', '%Y-%m-%dT%H:%M:%S.%fZ')

This results in the following datetime object, which is the same one you started with and therefore correct:

datetime.datetime(2011, 5, 25, 20, 34, 5, 787000)

解决方案 4:

Using json, you can subclass JSONEncoder and override the default() method to provide your own custom serializers:

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)

Then, you can call it like this:

>>> DateTimeJSONEncoder().encode([datetime.datetime.now()])
'["2010-06-15T14:42:28"]'

解决方案 5:

Here's a fairly complete solution for recursively encoding and decoding datetime.datetime and datetime.date objects using the standard library json module. This needs Python >= 2.6 since the %f format code in the datetime.datetime.strptime() format string is only supported in since then. For Python 2.5 support, drop the %f and strip the microseconds from the ISO 8601 date string before trying to convert it, but you'll lose microseconds precision, of course. For interoperability with ISO 8601 date strings from other sources, which may include a time zone name or UTC offset, you may also need to strip some parts of the date string before the conversion. For a complete parser for ISO 8601 date strings (and many other date formats) see the third-party dateutil module.

Decoding only works when the ISO 8601 date strings are values in a JavaScript
literal object notation or in nested structures within an object. ISO 8601 date
strings, which are items of a top-level array will not be decoded.

I.e. this works:

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'}

And this too:

>>> 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)}]

But this doesn't work as expected:

>>> 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']

Here's the code:

__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))

解决方案 6:

If you're certain that only JavaScript will be consuming the JSON, I prefer to pass JavaScript Date objects directly.

The ctime() method on datetime objects will return a string that the JavaScript Date object can understand.

import datetime
date = datetime.datetime.today()
json = '{"mydate":new Date("%s")}' % date.ctime()

JavaScript will happily use that as an object literal, and you've got your Date object built right in.

解决方案 7:

A very simple solution is to patch the json module default.

For example:

import json
import datetime

json.JSONEncoder.default = lambda self,obj: (obj.isoformat() if isinstance(obj, datetime.datetime) else None)

Now, you can use json.dumps() as if it had always supported datetime...

json.dumps({'created':datetime.datetime.now()})

This makes sense if you require this extension to the json module to always kick in and wish to not change the way you or others use JSON serialization (either in existing code or not).

Note that some may consider patching libraries in that way as bad practice.

Special care need to be taken in case you may wish to extend your application in more than one way. In such a case, I suggest to use the solution by ramen or JT and choose the proper JSON extension in each case.

解决方案 8:

Not much to add to the community wiki answer, except for timestamp!

JavaScript uses the following format:

new Date().toJSON() // "2016-01-08T19:00:00.123Z"

Python side (for the json.dumps handler, see the other answers):

>>> 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'

If you leave that Z out, frontend frameworks, like Angular, can not display the date in browser-local timezone:

> $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"

解决方案 9:

My advice is to use a library. There are several available at pypi.org.

I use asjson, and it works well.

解决方案 10:

On the Python side:

import time, json
from datetime import datetime as dt
your_date = dt.now()
data = json.dumps(time.mktime(your_date.timetuple())*1000)
return data # Data send to JavaScript

On the JavaScript side:

var your_date = new Date(data)

where data is the result from Python.

解决方案 11:

For the Python to JavaScript date conversion, the date object needs to be in specific ISO format, i.e., ISO format or Unix number. If the ISO format lacks some information, then you can convert to the Unix number with Date.parse() first. Moreover, Date.parse works with React as well while new Date might trigger an exception.

In case you have a DateTime object without milliseconds, the following needs to be considered:

  var unixDate = Date.parse('2016-01-08T19:00:00')
  var desiredDate = new Date(unixDate).toLocaleDateString();

The example date could equally be a variable in the result.data object after an API call.

For options to display the date in the desired format (e.g., to display long weekdays), check out the MDN documentation.

解决方案 12:

Apparently The “right” JSON (well JavaScript) date format is 2012-04-23T18:25:43.511Z - UTC and "Z". Without this JavaScript will use the web browser's local timezone when creating a Date() object from the string.

For a "naive" time (what Python calls a time with no timezone and this assumes is local) the below will force local timezone so that it can then be correctly converted to 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
            # https://stackoverflow.com/questions/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)

why is this so hard.

解决方案 13:

Simply do this:

r = json.dumps(your_json_data, default=str)
your_json_data = json.loads(r)

enter image description here

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2941  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1803  
  PLM(产品生命周期管理)系统在企业的产品研发、生产与管理过程中扮演着至关重要的角色。然而,在实际运行中,资源冲突是经常会遇到的难题。资源冲突可能导致项目进度延迟、成本增加以及产品质量下降等一系列问题,严重影响企业的效益与竞争力。因此,如何有效应对PLM系统中的资源冲突,成为众多企业关注的焦点。接下来,我们将详细探讨5...
plm项目管理系统   31  
  敏捷项目管理与产品生命周期管理(PLM)的融合,正成为企业在复杂多变的市场环境中提升研发效率、增强竞争力的关键举措。随着技术的飞速发展和市场需求的快速更迭,传统的研发流程面临着诸多挑战,而将敏捷项目管理理念融入PLM,有望在2025年实现研发流程的深度优化,为企业创造更大的价值。理解敏捷项目管理与PLM的核心概念敏捷项...
plm项目   31  
  模块化设计在现代产品开发中扮演着至关重要的角色,它能够提升产品开发效率、降低成本、增强产品的可维护性与可扩展性。而产品生命周期管理(PLM)系统作为整合产品全生命周期信息的关键平台,对模块化设计有着强大的支持能力。随着技术的不断发展,到 2025 年,PLM 系统在支持模块化设计方面将有一系列令人瞩目的技术实践。数字化...
plm软件   28  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用