पाइथन और जावास्क्रिप्ट के बीच JSON डेटाइम


393

मैं JSON का उपयोग करके पायथन से क्रमबद्ध रूप में डेटाटाइम लाइफटाइम ऑब्जेक्ट भेजना चाहता हूं और JSON का उपयोग करके जावास्क्रिप्ट में डी-सीरियलाइज करना चाहता हूं । इसे करने का बेहतरीन तरीका क्या है?


क्या आप किसी लाइब्रेरी का उपयोग करना पसंद करते हैं या क्या आप इसे स्वयं कोड करना चाहते हैं?
गुत्थी

जवाबों:


370

आप इसे संभालने के लिए json.dumps में 'डिफ़ॉल्ट' पैरामीटर जोड़ सकते हैं:

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

जो कि आईएसओ 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))

अद्यतन: मूल्य के साथ ही प्रकार का जोड़ा गया उत्पादन।
अद्यतन: इसके अलावा तारीख संभालें


11
समस्या यह है कि यदि आपके पास सूची में कुछ अन्य वस्तुएं हैं / तो यह कोड उन्हें कोई भी नहीं बदलेगा।
टॉमस वायसॉकी

5
json.dumps को यह नहीं पता होगा कि उन दोनों को कैसे परिवर्तित किया जाए, लेकिन अपवाद को दबाया जा रहा है। अफसोस की बात है कि एक लाइन लंबोदा फिक्स में कमियां हैं। यदि आप इसके बजाय अज्ञात अपवाद (जो कि एक अच्छा विचार है) पर उठाए गए फ़ंक्शन का उपयोग करते हैं जो मैंने ऊपर जोड़ा है।
जेटी।

9
पूर्ण आउटपुट प्रारूप में समय के साथ-साथ उस पर टाइमज़ोन भी होना चाहिए ... और इसोफ़ॉर्मैट () यह कार्यक्षमता प्रदान नहीं करता है ... इसलिए आपको लौटने से पहले स्ट्रिंग पर उस जानकारी को जोड़ना सुनिश्चित करना चाहिए
निक फ्रांसेचिना

3
यह जाने का सबसे अच्छा तरीका है। इसे उत्तर के रूप में क्यों नहीं चुना गया?
ब्रेंडन क्रॉफर्ड

16
लैम्बडा को गैर-डाइमटाइम प्रकारों पर आधार कार्यान्वयन को कॉल करने के लिए अनुकूलित किया जा सकता है, इसलिए यदि आवश्यक हो तो TypeError को उठाया जा सकता है:dthandler = lambda obj: obj.isoformat() if isinstance(obj, datetime) else json.JSONEncoder().default(obj)
पास्कल बॉर्क

81

क्रॉस-लैंग्वेज प्रोजेक्ट्स के लिए, मुझे पता चला कि RfC 3339 तारीख वाले तार जाने का सबसे अच्छा तरीका है। एक RfC 3339 तारीख इस तरह दिखता है:

  1985-04-12T23:20:50.52Z

मुझे लगता है कि ज्यादातर प्रारूप स्पष्ट है। केवल कुछ असामान्य बात अंत में "जेड" हो सकती है। यह GMT / UTC के लिए है। आप CEST (गर्मियों में जर्मनी) के लिए +02: 00 जैसी टाइमज़ोन ऑफ़सेट भी जोड़ सकते हैं। मैं व्यक्तिगत रूप से UTC में सब कुछ रखना पसंद करता हूं जब तक कि यह प्रदर्शित न हो।

प्रदर्शन, तुलना और भंडारण के लिए आप इसे सभी भाषाओं में स्ट्रिंग प्रारूप में छोड़ सकते हैं। यदि आपको अधिकांश भाषा में मूल दिनांक ऑब्जेक्ट पर वापस कनवर्ट करने के लिए गणना के लिए आसान दिनांक की आवश्यकता है।

तो इस तरह JSON उत्पन्न करें:

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

दुर्भाग्य से, जावास्क्रिप्ट का दिनांक निर्माता RfC 3339 तार को स्वीकार नहीं करता है, लेकिन इंटरनेट पर कई पार्सर उपलब्ध हैं।

huTools.hujson सबसे आम एन्कोडिंग मुद्दों को संभालने की कोशिश करता है जो आप समय-समय पर सही ढंग से हैंडल करते हुए दिनांक / डेटाटाइम ऑब्जेक्ट सहित पाइथन कोड में आ सकते हैं।


17
यह दिनांक स्वरूपण तंत्र मूल रूप से समर्थित है, दोनों द्वारा datetime: datetime.isoformat () और simplejson, जो डिफ़ॉल्ट datetimeरूप से ऑब्जेक्ट को isoformatस्ट्रिंग के रूप में डंप करेगा । मैन्युअल strftimeहैकिंग की कोई आवश्यकता नहीं है ।
jrk

9
@jrk - मुझे datetimeऑब्जेक्ट से isoformatस्ट्रिंग में स्वचालित रूपांतरण नहीं मिल रहा है । मेरे लिए, simplejson.dumps(datetime.now())पैदावारTypeError: datetime.datetime(...) is not JSON serializable
kostmo

6
json.dumps(datetime.datetime.now().isoformat())जहां जादू होता है।
२२:१०

2
सरलजन की सुंदरता यह है कि अगर मेरे पास एक जटिल डेटा संरचना है, तो वह इसे पार्स कर देगा और इसे JSON में बदल देगा। अगर मुझे हर डेटाटाइम ऑब्जेक्ट के लिए json.dumps (datetime.datetime.now ()। Isoformat ()) करना है, तो मैं इसे खो देता हूं। क्या इसे ठीक करने का कोई तरीका है?
andrrk

1
superjoe30: stackoverflow.com/questions/455580/… देखें कि कैसे करना है
अधिकतम

67

मैंने इसे काम किया है।

मान लीजिए कि आपके पास एक पायथन डेटाइम ऑब्जेक्ट है, d , जिसे डेटटाइम.वन () के साथ बनाया गया है। इसका मूल्य है:

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

आप इसे आईएसओ 8601 डेटाइम स्ट्रिंग के रूप में JSON पर अनुक्रमित कर सकते हैं:

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

उदाहरण के लिए आजीवन वस्तु को क्रमबद्ध किया जाएगा:

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

यह मान, एक बार जावास्क्रिप्ट लेयर में प्राप्त होने पर, दिनांक ऑब्जेक्ट का निर्माण कर सकता है:

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

जावास्क्रिप्ट के रूप में 1.8.5, दिनांक ऑब्जेक्ट में एक toJSON विधि है, जो एक मानक प्रारूप में एक स्ट्रिंग लौटाता है। उपरोक्त जावास्क्रिप्ट वस्तु को JSON में वापस लाने के लिए, इसलिए, कमांड होगी:

d.toJSON()

जो आपको देगा:

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

पायथन में एक बार प्राप्त होने वाली यह स्ट्रिंग वापस एक डेडटाइम ऑब्जेक्ट के लिए deserialized हो सकती है:

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

इसका परिणाम निम्न डेटाटाइम ऑब्जेक्ट में होता है, जो वही है जिसे आपने शुरू किया था और इसलिए सही है:

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

50

का उपयोग करते हुए json, आप JSONEncoder को उप-वर्ग कर सकते हैं और अपने स्वयं के कस्टम धारावाहिक प्रदान करने के लिए डिफ़ॉल्ट () विधि को ओवरराइड कर सकते हैं:

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

7
मामूली वृद्धि - उपयोग obj.isoformat()। आप अधिक सामान्य dumps()कॉल का भी उपयोग कर सकते हैं , जो अन्य उपयोगी indentआर्ग्स ( जैसे ) लेता है : simplejson.dumps (myobj, cls = JSONEncoder, ...)
rcoup

3
क्योंकि वह JSONEncoder के माता-पिता के तरीके को कहेंगे, न कि DateTimeJSONEncoder के माता-पिता के तरीके को। IE, आप दो स्तरों पर जा रहे हैं।
ब्रायन अरसुगा

30

यहाँ मानक लाइब्रेरी jsonमॉड्यूल का उपयोग करके पुनरावर्ती एन्कोडिंग और डेटाइमटाइम .टाइमटाइम और डेटटाइम.डेट ऑब्जेक्ट्स को डिकोड करने के लिए एक पूर्ण पूर्ण समाधान है । इसके बाद से पायथन> = 2.6 की जरूरत है क्योंकि %fप्रारूप कोड datetime.datetime.strptime () प्रारूप स्ट्रिंग में तब से ही समर्थित है। पायथन 2.5 समर्थन के लिए, %fइसे बदलने की कोशिश करने से पहले आईएसओ तिथि स्ट्रिंग से माइक्रोसेकंड को छोड़ें और पट्टी करें, लेकिन आप निश्चित रूप से माइक्रोसेकंड परिशुद्धता को ढीला कर देंगे। अन्य स्रोतों से आईएसओ तिथि के तार के साथ अंतर के लिए, जिसमें एक समय क्षेत्र का नाम या यूटीसी ऑफसेट शामिल हो सकता है, आपको रूपांतरण से पहले दिनांक स्ट्रिंग के कुछ हिस्सों को पट्टी करने की भी आवश्यकता हो सकती है। ISO दिनांक स्ट्रिंग्स (और कई अन्य दिनांक स्वरूपों) के लिए एक पूर्ण पार्सर के लिए तृतीय-पक्ष डेट्यूटिल मॉड्यूल देखें।

डिकोडिंग केवल तभी काम करती है जब 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 () जावास्क्रिप्ट में पैदा होता है
w00t

24

यदि आप निश्चित हैं कि केवल जावास्क्रिप्ट JSON का उपभोग करेगा, तो मैं Dateसीधे जावास्क्रिप्ट वस्तुओं को पास करना पसंद करता हूं ।

ctime()पर विधि datetimeवस्तुओं एक स्ट्रिंग है कि जावास्क्रिप्ट दिनांक वस्तु को समझ सकते हैं वापस आ जाएगी।

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

जावास्क्रिप्ट खुशी से एक वस्तु शाब्दिक के रूप में उपयोग करेगा, और आपको अपना दिनांक ऑब्जेक्ट सही में बनाया गया है।


12
तकनीकी रूप से JSON मान्य नहीं है, लेकिन यह एक मान्य जावास्क्रिप्ट ऑब्जेक्ट शाब्दिक है। (सिद्धांत की खातिर मैं सामग्री-प्रकार को पाठ / जावास्क्रिप्ट पर अनुप्रयोग / json के बजाय सेट करूँगा।) यदि उपभोक्ता हमेशा और हमेशा के लिए केवल जावास्क्रिप्ट कार्यान्वयन करेगा, तो हाँ, यह बहुत सुंदर है। मैं इसका उपयोग करूंगा।
सिस्टम PAUSE

13
.ctime()एक बहुत बुरा तरीका है समय की जानकारी पारित करने के लिए, .isoformat()बहुत बेहतर है। क्या .ctime()करता है दूर फेंक समयजोन और दिन के उजाले की बचत की तरह वे मौजूद नहीं है। उस फंक्शन को मार देना चाहिए।
एव्जेनी

वर्षों बाद: कृपया ऐसा करने पर कभी विचार न करें। यह केवल तभी काम करेगा जब आप जावास्क्रिप्ट () को अपने जावास्क्रिप्ट में शामिल करेंगे जो आपको वास्तव में नहीं करना चाहिए ...
domenukk

11

खेल में देर ... :)

एक बहुत ही सरल उपाय है कि जैसन मॉड्यूल को डिफ़ॉल्ट रूप से पैच किया जाए। उदाहरण के लिए:

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

यह समझ में आता है अगर आपको इस मॉड्यूल को हमेशा चालू करने के लिए जोंस मॉड्यूल के विस्तार की आवश्यकता होती है और आप या अन्य लोग जिस तरह से जसन क्रमांकन (मौजूदा कोड में या नहीं) का उपयोग करने के तरीके को नहीं बदलना चाहते हैं।

ध्यान दें कि कुछ इस तरह से खराब व्यवहार के रूप में पुस्तकालयों को पैच करने पर विचार कर सकते हैं। यदि आपको अपने आवेदन को एक से अधिक तरीकों से विस्तारित करने की इच्छा हो, तो विशेष देखभाल की आवश्यकता है - ऐसा एक मामला है, मैं रमेन या जेटी द्वारा समाधान का उपयोग करने का सुझाव देता हूं और प्रत्येक मामले में उचित जोंस एक्सटेंशन का चयन करता हूं।


6
यह चुपचाप गैर-अनुक्रमिक वस्तुओं को खाता है और उन्हें बदल देता है None। आप इसके बजाय एक अपवाद फेंकना चाह सकते हैं।
ब्लेंडर

6

टाइमस्टैम्प को छोड़कर, सामुदायिक विकि उत्तर में जोड़ने के लिए बहुत कुछ नहीं !

जावास्क्रिप्ट निम्नलिखित प्रारूप का उपयोग करता है:

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

अजगर पक्ष ( 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'

यदि आप उस जेड को छोड़ देते हैं, तो कोणीय जैसे फ्रंटएंड फ्रेमवर्क ब्राउज़र-स्थानीय टाइमज़ोन में दिनांक प्रदर्शित नहीं कर सकते हैं:

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

4

अजगर की तरफ:

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

जावास्क्रिप्ट पक्ष पर:

var your_date = new Date(data)

जहां डेटा अजगर से परिणाम है


4

मेरी सलाह है कि एक पुस्तकालय का उपयोग करें। Pypi.org पर कई उपलब्ध हैं।

मैं इस का उपयोग करता हूं, यह अच्छा काम करता है: https://pypi.python.org/pypi/asjson


0

जाहिरा तौर पर "सही" JSON (अच्छी तरह से जावास्क्रिप्ट) दिनांक प्रारूप 2012-04-23T18: 25: 43.511Z - UTC और "Z" है। इसके बिना जावास्क्रिप्ट स्ट्रिंग से एक दिनांक () ऑब्जेक्ट बनाते समय वेब ब्राउज़र के स्थानीय समयक्षेत्र का उपयोग करेगा।

एक "भोले" समय के लिए (जिसे पायथन ने बिना समयक्षेत्र के एक समय कहा जाता है और यह माना जाता है कि स्थानीय है) नीचे स्थानीय समय-क्षेत्र को मजबूर कर देगा ताकि इसे तब सही ढंग से यूटीसी में परिवर्तित किया जा सके:

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)

यह इतना मुश्किल क्यों है।


0

पायथन से जावास्क्रिप्ट तिथि रूपांतरण के लिए, दिनांक ऑब्जेक्ट को विशिष्ट आईएसओ प्रारूप, यानी आईएसओ प्रारूप या यूनिक्स नंबर में होना चाहिए। यदि आईएसओ प्रारूप में कुछ जानकारी का अभाव है, तो आप पहले Date.parse के साथ यूनिक्स नंबर में बदल सकते हैं। इसके अलावा, Date.parse रिएक्ट के साथ काम करता है जबकि नई तिथि एक अपवाद को ट्रिगर कर सकती है।

यदि आपके पास मिलीसेकंड के बिना डेटटाइम ऑब्जेक्ट है, तो निम्नलिखित पर विचार किया जाना चाहिए। :

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

उदाहरण की तारीख समान रूप से एपीआई कॉल के बाद result.data ऑब्जेक्ट में एक चर हो सकती है।

वांछित प्रारूप में दिनांक प्रदर्शित करने के लिए विकल्पों के लिए (जैसे लंबे कार्यदिवस प्रदर्शित करने के लिए) एमडीएन डॉक्टर की जाँच करें ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.