我怎样才能克服“datetime.datetime 不是 JSON 可序列化”的问题?

2024-12-05 08:38:00
admin
原创
138
摘要:问题描述:我有一个基本的字典如下:sample = {} sample['title'] = "String" sample['somedate'] = somedatetimehere 当我尝试这样做时,jsonify(sample)我得到:TypeError:datetime.date...

问题描述:

我有一个基本的字典如下:

sample = {}
sample['title'] = "String"
sample['somedate'] = somedatetimehere

当我尝试这样做时,jsonify(sample)我得到:

TypeError:datetime.datetime(2012, 8, 8, 21, 46, 24, 862000) 不是 JSON 可序列化的

我该怎么做才能使我的字典样本能够克服上述错误?

注意:虽然可能不相关,但字典是从检索记录生成的,mongodb当我打印出时str(sample['somedate']),输出是2012-08-08 21:46:24.862000


解决方案 1:

我的快速而肮脏的 JSON 转储,包含日期和所有内容:

json.dumps(my_dictionary, indent=4, sort_keys=True, default=str)

default是一个应用于不可序列化对象的函数。

在本例中是str,所以它只是将不知道的所有内容转换为字符串。这对于序列化来说很棒,但在反序列化时就不是那么好了(因此是“快速而肮脏的”),因为任何东西都可能在没有警告的情况下被字符串化,例如函数或 numpy 数组。

解决方案 2:

在其他答案的基础上,基于特定序列化器的简单解决方案,仅将对象转换datetime.datetimedatetime.date字符串。

from datetime import date, datetime

def json_serial(obj):
    """JSON serializer for objects not serializable by default json code"""

    if isinstance(obj, (datetime, date)):
        return obj.isoformat()
    raise TypeError ("Type %s not serializable" % type(obj))

如您所见,代码只是检查对象是否属于类datetime.datetimedatetime.date,然后使用.isoformat()它根据 ISO 8601 格式 YYYY-MM-DDTHH:MM:SS(JavaScript 可以轻松解码)生成它的序列化版本。如果寻求更复杂的序列化表示,可以使用其他代码代替 str()(有关示例,请参阅此问题的其他答案)。代码以引发异常结束,以处理使用不可序列化类型调用的情况。

此 json_serial 函数可按如下方式使用:

from datetime import datetime
from json import dumps

print dumps(datetime.now(), default=json_serial)

有关 json.dumps 的默认参数如何工作的详细信息,请参阅json 模块文档的基本用法部分。

解决方案 3:

2018 年更新

原始答案适应了 MongoDB“日期”字段的表示方式:

{"$date": 1506816000000}

如果您想要一个用于序列化为datetimejson 的通用 Python 解决方案,请查看@jjmontes 的答案,以获得不需要任何依赖项的快速解决方案。


由于您正在使用 mongoengine(根据评论)并且 pymongo 是一个依赖项,因此 pymongo 具有内置实用程序来帮助进行 json 序列化:

http://api.mongodb.org/python/1.10.1/api/bson/json_util.html

使用示例(序列化):

from bson import json_util
import json

json.dumps(anObject, default=json_util.default)

使用示例(反序列化):

json.loads(aJsonString, object_hook=json_util.object_hook)

Django

Django 提供了一个本机DjangoJSONEncoder序列化器来正确处理此类问题。

请参阅https://docs.djangoproject.com/en/dev/topics/serialization/#djangojsonencoder

from django.core.serializers.json import DjangoJSONEncoder

return json.dumps(
  item,
  sort_keys=True,
  indent=1,
  cls=DjangoJSONEncoder
)

我注意到使用这样的DjangoJSONEncoder自定义方法和使用default下面的自定义方法之间存在一个区别:

import datetime
import json

def default(o):
    if isinstance(o, (datetime.date, datetime.datetime)):
        return o.isoformat()

return json.dumps(
  item,
  sort_keys=True,
  indent=1,
  default=default
)

Django 是否剥离了一些数据:

 "last_login": "2018-08-03T10:51:42.990", # DjangoJSONEncoder 
 "last_login": "2018-08-03T10:51:42.990239", # default

所以,在某些情况下您可能需要对此小心谨慎。

解决方案 4:

我刚刚遇到这个问题,我的解决方案是子类化json.JSONEncoder

from datetime import datetime
import json

class DateTimeEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, datetime):
            return o.isoformat()

        return json.JSONEncoder.default(self, o)

在您的通话中执行以下操作:json.dumps(yourobj, cls=DateTimeEncoder).isoformat()从上面的一个答案中得到了。

解决方案 5:

将日期转换为字符串

sample['somedate'] = str( datetime.utcnow() )

解决方案 6:

对于其他不需要或不想使用 pymongo 库的人,您可以使用这个小代码片段轻松实现日期时间 JSON 转换:

def default(obj):
    """Default JSON serializer."""
    import calendar, datetime

    if isinstance(obj, datetime.datetime):
        if obj.utcoffset() is not None:
            obj = obj - obj.utcoffset()
        millis = int(
            calendar.timegm(obj.timetuple()) * 1000 +
            obj.microsecond / 1000
        )
        return millis
    raise TypeError('Not sure how to serialize %s' % (obj,))

然后像这样使用它:

import datetime, json
print json.dumps(datetime.datetime.now(), default=default)

输出:

'1365091796124'

解决方案 7:

以下是我的解决方案:

import json

class DatetimeEncoder(json.JSONEncoder):
    def default(self, obj):
        try:
            return super().default(obj)
        except TypeError:
            return str(obj)

然后你可以像这样使用它:

json.dumps(dictionary, cls=DatetimeEncoder)

解决方案 8:

如果您使用的是 Python 3.7,那么最好的解决方案是使用
datetime.isoformat()
datetime.fromisoformat();它们适用于简单对象和感知datetime对象:

#!/usr/bin/env python3.7

from datetime import datetime
from datetime import timezone
from datetime import timedelta
import json

def default(obj):
    if isinstance(obj, datetime):
        return { '_isoformat': obj.isoformat() }
    raise TypeError('...')

def object_hook(obj):
    _isoformat = obj.get('_isoformat')
    if _isoformat is not None:
        return datetime.fromisoformat(_isoformat)
    return obj

if __name__ == '__main__':
    #d = { 'now': datetime(2000, 1, 1) }
    d = { 'now': datetime(2000, 1, 1, tzinfo=timezone(timedelta(hours=-8))) }
    s = json.dumps(d, default=default)
    print(s)
    print(d == json.loads(s, object_hook=object_hook))

输出:

{"now": {"_isoformat": "2000-01-01T00:00:00-08:00"}}
True

如果您使用的是 Python 3.6 或更低版本,并且您只关心时间值(而不是时区),那么您可以使用datetime.timestamp()and
datetime.fromtimestamp()代替;

如果你使用的是 Python 3.6 或更低版本,并且你确实关心时区,那么你可以通过获取它datetime.tzinfo,但你必须自己序列化这个字段;最简单的方法是_tzinfo在序列化对象中添加另一个字段;

最后,要注意所有这些例子中的精确性;

解决方案 9:

您应该将该.strftime()方法应用于datetime.datetime对象以使其成为string

以下是一个例子:

from datetime import datetime

time_dict = {'time': datetime.now().strftime('%Y-%m-%dT%H:%M:%S')}
sample_dict = {'a': 1, 'b': 2}
sample_dict.update(time_dict)
sample_dict

输出:

Out[0]: {'a': 1, 'b': 2, 'time': '2017-10-31T15:16:30'}

[更新]:

在 Python 3.6 或更高版本中,您可以简单地使用该.isoformat()方法:

from datetime import datetime

datetime.now().isoformat()

解决方案 10:

json.dumps 方法可以接受一个名为default 的可选参数,该参数应为一个函数。每次 JSON 尝试转换它不知道如何转换的值时,它都会调用我们传递给它的函数。该函数将接收相关对象,并应返回该对象的 JSON 表示形式。

def myconverter(o):
  if isinstance(o, datetime.datetime):
    return o.__str__()

print(json.dumps(d, default = myconverter))

解决方案 11:

我有一个有类似问题的应用程序;我的方法是将日期时间值 JSON 化为 6 项列表(年、月、日、时、分、秒);你可以将微秒作为 7 项列表,但我不需要:

class DateTimeEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime.datetime):
            encoded_object = list(obj.timetuple())[0:6]
        else:
            encoded_object =json.JSONEncoder.default(self, obj)
        return encoded_object

sample = {}
sample['title'] = "String"
sample['somedate'] = datetime.datetime.now()

print sample
print json.dumps(sample, cls=DateTimeEncoder)

生成:

{'somedate': datetime.datetime(2013, 8, 1, 16, 22, 45, 890000), 'title': 'String'}
{"somedate": [2013, 8, 1, 16, 22, 45], "title": "String"}

解决方案 12:

我的解决方案(我认为不太冗长):

def default(o):
    if type(o) is datetime.date or type(o) is datetime.datetime:
        return o.isoformat()

def jsondumps(o):
    return json.dumps(o, default=default)

然后使用jsondumps而不是json.dumps。它将打印:

>>> jsondumps({'today': datetime.date.today()})
'{"today": "2013-07-30"}'

如果您愿意,稍后您可以通过简单修改default方法添加其他特殊情况。例如:

def default(o):
    if type(o) is datetime.date or type(o) is datetime.datetime:
        return o.isoformat()
    if type(o) is decimal.Decimal:
        return float(o)

解决方案 13:

这个问题一次又一次地重复出现——一个简单的方法是修补json模块,以便序列化支持datetime

import json
import datetime

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

然后像往常一样使用 JSON 序列化,这次将 datetime 序列化为isoformat

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

结果为:‘{“created”:“2015-08-26T14:21:31.853855”}’

查看更多详细信息和一些注意事项:
Stack Overflow:Python 和 JavaScript 之间的 JSON 日期时间

解决方案 14:

这是一个解决“日期时间不是 JSON 可序列化”问题的简单解决方案。

enco = lambda obj: (
    obj.isoformat()
    if isinstance(obj, datetime.datetime)
    or isinstance(obj, datetime.date)
    else None
)

json.dumps({'date': datetime.datetime.now()}, default=enco)

输出:-> {“date”:“2015-12-16T04:48:20.024609”}

解决方案 15:

您必须提供一个带有cls参数的自定义编码器类json.dumps。引用文档中的一段话:

>>> import json
>>> class ComplexEncoder(json.JSONEncoder):
...     def default(self, obj):
...         if isinstance(obj, complex):
...             return [obj.real, obj.imag]
...         return json.JSONEncoder.default(self, obj)
...
>>> dumps(2 + 1j, cls=ComplexEncoder)
'[2.0, 1.0]'
>>> ComplexEncoder().encode(2 + 1j)
'[2.0, 1.0]'
>>> list(ComplexEncoder().iterencode(2 + 1j))
['[', '2.0', ', ', '1.0', ']']

这使用复数作为示例,但您也可以轻松创建一个类来编码日期(但我认为 JSON 对日期有点模糊)。

解决方案 16:

其实很简单。如果您需要经常序列化日期,那么就将它们作为字符串使用。如果需要,您可以轻松地将它们转换回日期时间对象。

如果您需要主要以日期时间对象的形式工作,那么请在序列化之前将它们转换为字符串。

import json, datetime

date = str(datetime.datetime.now())
print(json.dumps(date))
"2018-12-01 15:44:34.409085"
print(type(date))
<class 'str'>

datetime_obj = datetime.datetime.strptime(date, '%Y-%m-%d %H:%M:%S.%f')
print(datetime_obj)
2018-12-01 15:44:34.409085
print(type(datetime_obj))
<class 'datetime.datetime'>

如你所见,两种情况下的输出是相同的。只有类型不同。

解决方案 17:

我通常使用orjson。不仅因为它的性能出色,还因为它对以下内容的出色支持(符合 RFC-3339)datetime

import orjson # via pip3 install orjson
from datetime import datetime

data = {"created_at": datetime(2022, 3, 1)}

orjson.dumps(data) # returns b'{"created_at":"2022-03-01T00:00:00"}'

如果您想使用datetime.datetime没有 tzinfo 的对象作为 UTC,您可以添加相关选项:

orjson.dumps(data, option=orjson.OPT_NAIVE_UTC) # returns b'{"created_at":"2022-03-01T00:00:00+00:00"}'

解决方案 18:

最简单的方法是将 dict 中 datetime 格式的部分更改为isoformat 。该值实际上是json可以接受的isoformat字符串

v_dict = version.dict()
v_dict['created_at'] = v_dict['created_at'].isoformat()

解决方案 19:

尝试用一个例子来解析它:

#!/usr/bin/env python

import datetime
import json

import dateutil.parser  # pip install python-dateutil


class JSONEncoder(json.JSONEncoder):

    def default(self, obj):
        if isinstance(obj, datetime.datetime):
            return obj.isoformat()
        return super(JSONEncoder, self).default(obj)


def test():
    dts = [
        datetime.datetime.now(),
        datetime.datetime.now(datetime.timezone(-datetime.timedelta(hours=4))),
        datetime.datetime.utcnow(),
        datetime.datetime.now(datetime.timezone.utc),
    ]
    for dt in dts:
        dt_isoformat = json.loads(json.dumps(dt, cls=JSONEncoder))
        dt_parsed = dateutil.parser.parse(dt_isoformat)
        assert dt == dt_parsed
        print(f'{dt}, {dt_isoformat}, {dt_parsed}')
        # 2018-07-22 02:22:42.910637, 2018-07-22T02:22:42.910637, 2018-07-22 02:22:42.910637
        # 2018-07-22 02:22:42.910643-04:00, 2018-07-22T02:22:42.910643-04:00, 2018-07-22 02:22:42.910643-04:00
        # 2018-07-22 06:22:42.910645, 2018-07-22T06:22:42.910645, 2018-07-22 06:22:42.910645
        # 2018-07-22 06:22:42.910646+00:00, 2018-07-22T06:22:42.910646+00:00, 2018-07-22 06:22:42.910646+00:00


if __name__ == '__main__':
    test()

解决方案 20:

我在调试期间经常使用 IntelliJEvaluate Expression工具来复制某些对象以进行分析。这种方法的问题是,如果您尝试转储的字典中有日期,它就会失效,另一个问题是您无法使用该工具定义转换器,因此我想出了这个一行代码:

json.dumps(dict_to_dump, default=lambda o: o.__str__() if isinstance(o, datetime) else None)

在此处输入图片描述

解决方案 21:

如果您正在使用Django模型,您可以直接将其传递encoder=DjangoJSONEncoder给字段构造函数。它会非常有效。

from django.core.serializers.json import DjangoJSONEncoder
from django.db import models
from django.utils.timezone import now


class Activity(models.Model):
    diff = models.JSONField(null=True, blank=True, encoder=DjangoJSONEncoder)


diff = {
    "a": 1,
    "b": "BB",
    "c": now()
}

Activity.objects.create(diff=diff)

解决方案 22:

通常,有几种序列化日期时间的方法,例如:

  1. ISO 8601字符串,简短且可以包含时区信息,例如jgbarah 的答案

  2. 时间戳(时区数据丢失),例如JayTaylor 的答案

  3. 属性字典(包括时区)。

如果您对最后一种方式满意,json_tricks包可以处理日期、时间和日期时间(包括时区)。

from datetime import datetime
from json_tricks import dumps
foo = {'title': 'String', 'datetime': datetime(2012, 8, 8, 21, 46, 24, 862000)}
dumps(foo)

其结果为:

{"title": "String", "datetime": {"__datetime__": null, "year": 2012, "month": 8, "day": 8, "hour": 21, "minute": 46, "second": 24, "microsecond": 862000}}

所以你需要做的就是

`pip install json_tricks`

然后从 而json_tricks不是导入json

不将其存储为单个字符串、整数或浮点数的优点在于解码时:如果您遇到的只是字符串,或者特别是整数或浮点数,则需要了解一些有关数据的信息才能知道它是否是日期时间。作为字典,您可以存储元数据,以便可以自动解码,这就是json_tricks您要做的。它也易于人类编辑。

免责声明:这是我做的。因为我遇到了同样的问题。

解决方案 23:

根据jjmontes 的回答,我使用了以下方法。对于Flask和flask-restful用户

# Get JSON string
jsonStr = json.dumps(my_dictionary, indent=1, sort_keys=True, default=str)
# Then convert the JSON string to a JSON object
return json.loads(jsonStr)

解决方案 24:

如果您在视图中使用结果,请确保返回正确的响应。根据 API,jsonify 执行以下操作:

使用 application/json mimetype 创建具有给定参数的 JSON 表示形式的响应。

要使用 json.dumps 模仿这种行为,您必须添加几行额外的代码。

response = make_response(dumps(sample, cls=CustomEncoder))
response.headers['Content-Type'] = 'application/json'
response.headers['mimetype'] = 'application/json'
return response

您还应该返回一个字典来完全复制 jsonify 的响应。因此,整个文件将如下所示

from flask import make_response
from json import JSONEncoder, dumps


class CustomEncoder(JSONEncoder):
    def default(self, obj):
        if set(['quantize', 'year']).intersection(dir(obj)):
            return str(obj)
        elif hasattr(obj, 'next'):
            return list(obj)
        return JSONEncoder.default(self, obj)

@app.route('/get_reps/', methods=['GET'])
def get_reps():
    sample = ['some text', <datetime object>, 123]
    response = make_response(dumps({'result': sample}, cls=CustomEncoder))
    response.headers['Content-Type'] = 'application/json'
    response.headers['mimetype'] = 'application/json'
    return response

解决方案 25:

我的解决方案...

from datetime import datetime
import json

from pytz import timezone
import pytz


def json_dt_serializer(obj):
    """JSON serializer, by macm.
    """
    rsp = dict()
    if isinstance(obj, datetime):
        rsp['day'] = obj.day
        rsp['hour'] = obj.hour
        rsp['microsecond'] = obj.microsecond
        rsp['minute'] = obj.minute
        rsp['month'] = obj.month
        rsp['second'] = obj.second
        rsp['year'] = obj.year
        rsp['tzinfo'] = str(obj.tzinfo)
        return rsp
    raise TypeError("Type not serializable")


def json_dt_deserialize(obj):
    """JSON deserialize from json_dt_serializer, by macm.
    """
    if isinstance(obj, str):
        obj = json.loads(obj)
    tzone = timezone(obj['tzinfo'])
    tmp_dt = datetime(obj['year'],
                      obj['month'],
                      obj['day'],
                      hour=obj['hour'],
                      minute=obj['minute'],
                      second=obj['second'],
                      microsecond=obj['microsecond'])
    loc_dt = tzone.localize(tmp_dt)
    deserialize = loc_dt.astimezone(tzone)
    return deserialize    

好的,现在进行一些测试。

# Tests
now = datetime.now(pytz.utc)

# Using this solution
rsp = json_dt_serializer(now)
tmp = json_dt_deserialize(rsp)
assert tmp == now
assert isinstance(tmp, datetime) == True
assert isinstance(now, datetime) == True

# using default from json.dumps
tmp = json.dumps(datetime.now(pytz.utc), default=json_dt_serializer)
rsp = json_dt_deserialize(tmp)
assert isinstance(rsp, datetime) == True

# Lets try another timezone
eastern = timezone('US/Eastern')
now = datetime.now(eastern)
rsp = json_dt_serializer(now)
tmp = json_dt_deserialize(rsp)

print(tmp)
# 2015-10-22 09:18:33.169302-04:00

print(now)
# 2015-10-22 09:18:33.169302-04:00

# Wow, Works!
assert tmp == now

解决方案 26:

将转换datestring

date = str(datetime.datetime(somedatetimehere)) 

解决方案 27:

这是我将日期时间转换为 JSON 并转回的完整解决方案......

import calendar, datetime, json

def outputJSON(obj):
    """Default JSON serializer."""

    if isinstance(obj, datetime.datetime):
        if obj.utcoffset() is not None:
            obj = obj - obj.utcoffset()

        return obj.strftime('%Y-%m-%d %H:%M:%S.%f')
    return str(obj)

def inputJSON(obj):
    newDic = {}

    for key in obj:
        try:
            if float(key) == int(float(key)):
                newKey = int(key)
            else:
                newKey = float(key)

            newDic[newKey] = obj[key]
            continue
        except ValueError:
            pass

        try:
            newDic[str(key)] = datetime.datetime.strptime(obj[key], '%Y-%m-%d %H:%M:%S.%f')
            continue
        except TypeError:
            pass

        newDic[str(key)] = obj[key]

    return newDic

x = {'Date': datetime.datetime.utcnow(), 34: 89.9, 12.3: 90, 45: 67, 'Extra': 6}

print x

with open('my_dict.json', 'w') as fp:
    json.dump(x, fp, default=outputJSON)

with open('my_dict.json') as f:
    my_dict = json.load(f, object_hook=inputJSON)

print my_dict

输出

{'Date': datetime.datetime(2013, 11, 8, 2, 30, 56, 479727), 34: 89.9, 45: 67, 12.3: 90, 'Extra': 6}
{'Date': datetime.datetime(2013, 11, 8, 2, 30, 56, 479727), 34: 89.9, 45: 67, 12.3: 90, 'Extra': 6}

JSON 文件

{"Date": "2013-11-08 02:30:56.479727", "34": 89.9, "45": 67, "12.3": 90, "Extra": 6}

这使我能够导入和导出字符串、整数、浮点数和日期时间对象。扩展其他类型应该不难。

解决方案 28:

我在使用 sqlalchemy 在类中编写序列化装饰器时收到了相同的错误消息。因此,不要这样做:

Class Puppy(Base):
    ...
    @property
    def serialize(self):
        return { 'id':self.id,
                 'date_birth':self.date_birth,
                  ...
                }

我只是借用了 jgbarah 使用 isoformat() 的想法,并将原始值附加到 isoformat() 中,现在看起来像这样:

                  ...
                 'date_birth':self.date_birth.isoformat(),
                  ...

解决方案 29:

如果您想要自己的格式,可以快速修复

for key,val in sample.items():
    if isinstance(val, datetime):
        sample[key] = '{:%Y-%m-%d %H:%M:%S}'.format(val) #you can add different formating here
json.dumps(sample)

解决方案 30:

当我将Django模型对象外部化并转储为 JSON时,我遇到了同样的问题。

以下是解决方法。

def externalize(model_obj):
  keys = model_obj._meta.get_all_field_names()
  data = {}
  for key in keys:
    if key == 'date_time':
      date_time_obj = getattr(model_obj, key)
      data[key] = date_time_obj.strftime("%A %d. %B %Y")
    else:
      data[key] = getattr(model_obj, key)
  return data
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

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

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

内置subversion和git源码管理

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

免费试用