棉花糖处理时间戳取决于运行它的机器

时间:2017-05-05 12:26:46

标签: python datetime marshmallow

我正在研究使用Flask在python中创建的REST API。我使用SQLalchemy和Marshmallow来处理和存储进出API的数据。

我有一条用于创建活动的路线。它将日期时间作为POST有效负载的信息之一。在模型中,对该字段使用TIMESTAMP类型。 SQLalchemy的TIMESTAMP类型是支持时区的日期时间。

当我在Linux上运行API时,一切正常但是当我在Windows上运行它时,数据会进入,因为它应该从marshmallow的模式中传递到load()方法中 post_campaign, errors = campaign_schema.load(request.get_json()) 一旦它被加载到模式中,日期时间就会丢失时区数据,这对我来说是个大问题。

我在我的架构中没有做任何特殊操作,它是一个经典的"一种架构。

基本上,在我的机器和其他一些人身上,我有

  

test_campaign(tests.test_setup.Testing)...
  < ------------------>
  现在2017-05-05 09:52:39.014386 + 00:00使用datetime.utcnow()生成。替换(tzinfo = pytz.utc)
  在架构加载之前2018-05-05 08:35:17.361864 + 00:00   架构中的数据2018-05-05 08:35:17.361864 + 00:00   < ------------------>

在我有的其他机器上

  

test_campaign(tests.test_setup.Testing)...
  < ------------------>
  现在2017-05-05 09:52:39.014386 + 00:00   在架构加载之前2018-05-05 08:35:17.361864 + 00:00   架构中的数据2018-05-05 08:35:17
  < ------------------>

我的架构(ma是marshmallow):

class CampaignSchema(ma.ModelSchema):
   class Meta:
   model = Campaign
admingroup_id = field_for(Campaign, 'admingroup_id', dump_only=False)
smtp_id = field_for(Campaign, 'smtp_id', dump_only=False)
mail_template_id = field_for(Campaign, 'mail_template_id', dump_only=False)
landing_page_id = field_for(Campaign, 'landing_page_id', dump_only=False)

campaign_schema = CampaignSchema()
campaigns_schema = CampaignSchema(many=True)

你们有没有人知道这种行为?

1 个答案:

答案 0 :(得分:0)

<强> TL; DR
您需要在正在使用的任何计算机上安装dateutils模块:

pip install python-dateutils 

我遇到了类似棉花糖的问题Schema

class TestSchema(Schema):
    dt_field = fields.DateTime(required=True)

按原样使用它我得到的是一个时区不知道的datetime对象:

>>> ts = TestSchema()
>>> ts.load({'dt_field': '2018-03-22T16:30:00+02:00'}).data.get('dt_field')
datetime.datetime(2018, 3, 22, 16, 30)

marshmallow有一个utils.py,其中包含各种方法 其中一些方法用于将日期时间字符串转换为datetime对象,如from_iso_datetime()

def from_iso_datetime(datestring, use_dateutil=True):
       """
       Parse an ISO8601-formatted datetime string and return a datetime object.
       Use dateutil's parser if possible and return a timezone-aware datetime.
       """
    if not _iso8601_re.match(datestring):
        raise ValueError('Not a valid ISO8601-formatted datetime string')
    # Use dateutil's parser if possible
    if dateutil_available and use_dateutil:
        return parser.parse(datestring)
    else:
        # Strip off timezone info.
        return datetime.datetime.strptime(datestring[:19], '%Y-%m-%dT%H:%M:%S')

从这段代码片段中,我们可以看到该方法检查dateutils是否可用,如果不可用,则会删除时区信息。

当我安装dateutils(因此使marshmallow“可用”时)上面的示例按预期工作:

>>> ts.load({'dt_field': '2018-03-22T16:30:00+02:00'}).data.get('dt_field')
datetime.datetime(2018, 3, 22, 16, 30, tzinfo=tzoffset(None, 7200))