plaid/plaid-python

datetime formatting causes JSON parse failure

matthew-mcallister opened this issue · 7 comments

Using version 9.3.0, when I pass a datetime to LinkTokenCreateRequestUser.phone_number_verified_time, I get this error:

{
  "display_message": null,
  "documentation_url": "https://plaid.com/docs/?ref=error#invalid-request-errors",
  "error_code": "INVALID_BODY",
  "error_message": "body could not be parsed as JSON",
  "error_type": "INVALID_REQUEST",
  "request_id": "yhfHXxGXoh8NoIQ",
  "suggested_action": null
}

Inspecting the request body, I see the issue is that the formatted datetime is missing the "Z" at the end, i.e. "1969-12-31T16:00:00" instead of "1969-12-31T16:00:00Z". Though the error message is misleading, since this is actually valid JSON.

@matthew-mcallister Thank you for the report -- can you show how you are generating and providing the datetime?

request = plaid_api.LinkTokenCreateRequest(
    client_name='name',
    language='en',
    country_codes=[models.CountryCode('US')],
    products=[models.Products('auth'), models.Products('transactions')],
    user=models.LinkTokenCreateRequestUser(
        client_user_id=str(user.external_id),
        email_address=user.email,
        phone_number=user.phone_number,
        # FIXME: https://github.com/plaid/plaid-python/issues/414
        # phone_number_verified_time=datetime.fromtimestamp(0),
    ),
)

Same thing happens with any datetime I input.

Does this suggested approach from StackOverflow work?
https://stackoverflow.com/questions/8556398/generate-rfc-3339-timestamp-in-python

import datetime
n = datetime.datetime.now(datetime.timezone.utc)
n.isoformat()
'2021-07-13T15:28:51.818095+00:00'

I'll also file an issue with the team to see if we can be a little less picky with the date-time formatting, similarly to how we treat phone numbers.

Does this suggested approach from StackOverflow work?

I can't pass a str to the SDK because it's type-checked:

plaid.exceptions.ApiTypeError: Invalid type for variable 'phone_number_verified_time'. Required value type is datetime and passed type was str at ['phone_number_verified_time']

What about something like this?

https://stackoverflow.com/questions/796008/cant-subtract-offset-naive-and-offset-aware-datetimes/25662061#25662061

from datetime import datetime, timezone

now = datetime.now(timezone.utc)

Hi @matthew-mcallister! Looking at the /link/token/create docs, it looks like you'll need to pass in a date-time object that includes timezone information (datetime.fromtimestamp(0) doesn't appear to include timezone information). @phoenixy1 's suggestion above should work. You could also try something like:

import datetime

# change to your date
n = datetime.datetime(2021, 11, 1, 0, 0, tzinfo=datetime.timezone.utc)

If you really want to use fromtimestamp(), consider something like:

import datetime
import pytz

n = datetime.fromtimestamp(0, pytz.timezone("UTC"))

If you call .isoformat() on any of the n variables above (just to inspect the value), you should see +00:00 appended to the end of the string, which is the necessary timezone information (I found this section in Wikipedia helpful: https://en.wikipedia.org/wiki/ISO_8601#Time_zone_designators, namely "An offset of zero, in addition to having the special representation "Z", can also be stated numerically as "+00:00", "+0000", or "+00".").

The world of date-times is unfortunately full of rabbit holes, but I hope this is helpful! If you're still encountering issues, please reach out again. Thanks. 🙏

Ah, I didn't understand the first response. Adding a timezone fixes the issue, obviously. Thank you. A better error message would help as it's a tricky problem to diagnose, but that's not really the SDK's problem.