Problem/Motivation
Pushing a Drupal date field (with time) to a Salesforce datetime field results in an incorrect value stored and displayed in Salesforce.
To reproduce:
1. Create a date (with time) field on a Drupal entity and map this to a Salesforce datetime field.
2. Set data for this field on a Drupal entity and save the entity. Pull up the corresponding object in Salesforce and see that the date is wrong in Salesforce.
It appears that Drupal\salesforce_mapping\SalesforceMappingFieldPluginBase::pushValue() is utilizing strtotime() on the raw value of date fields. These raw values are in UTC timezone, but strtotime() doesn't know this (timezone isn't stored in Drupal dates) and instead converts this value to a timestamp using the default timezone. If the default timezone for the server isn't UTC, then the timestamp strtotime() creates is inaccurate. This timestamp is then converted to a Salesforce-compatible string using the "time zone used to display the page" (see Drupal\Core\Datetime\DateFormatterInterface::format()) and sent off for storage into Salesforce.
It's clear we have some timezone issues in this code. Depending on the server's default timezone and the timezone used to display the page, the time we send to Salesforce can be shifted from what we have in Drupal.
Proposed resolution
Utilize something more robust than strtotime(), something that can convert a UTC Drupal-formatted date into a UTC Salesforce-formatted date (SF also stores dates in UTC), keeping UTC timezone the whole time (maybe Drupal\Core\Datetime\DrupalDateTime).
Remaining tasks
Patch, review.
User interface changes
None.
API changes
None.
Data model changes
None.
| Comment | File | Size | Author |
|---|---|---|---|
| #11 | salesforce-datetime-push-bug-3074441-11.patch | 4.13 KB | aaronbauman |
| #9 | salesforce-datetime-push-bug-3074441-TEST-ONLY.patch | 2.71 KB | aaronbauman |
Comments
Comment #2
chrisolof commentedPatch attached, needs review.
Comment #3
aaronbaumanCurrent approach formats dates using ISO 8601, e.g. 2004-02-12T15:19:21+00:00
This patch proposes eliminating the timezone portion, e.g. 'Y-m-d\TH:i:s'
Will Salesforce assume UTC if no timezone is specified?
Comment #4
cwcorrigan commentedAlternative patch attached, it's actually the Date Formatting service that's applying Drupal's default timezone rather than strtotime.
Some brief testing suggests that Salesforce does assume UTC however it's probably better to be explicit and continue to use ISO 8601 rather than rely on undefined behavior as I can't find that explicitly stated in the Salesforce Docs.
Comment #5
aaronbaumanLooks like
strtotimeassumes PHP's default timezone.This causes it to misinterpret Drupal dates, which are all stored in UTC without any explicit timezone attached.
#2 correctly interprets the given date as UTC, whereas #4 incorrectly casts into the wrong timezone.

Here's an example, with a Drupal site whose default timezone is -04:00:
When formatting for Salesforce, I think we should use the PHP's
DateTime::ISO8601format (equivalent to "c") to be explicit about the timezone.Comment #6
aaronbaumanHere's a test to prove this bug exists, and which is solved by #5.
Comment #7
cwcorrigan commentedConfirming #5 solves the issue.
Comment #8
aaronbaumanWTF? Now just have to figure out why the test in #6 fails on my local but passes on testbot.
I hate testbot so much.
Comment #9
aaronbaumanApparently neither assertEquals() nor assertSame() work on even the simplest arrays.
Which means there's literally no way to compare arrays without iterating over every single element recursively?!?!?
Comment #11
aaronbaumanThere we go.
And here's the same test + patch from #5
If this passes, i'll push it right away.
Comment #13
aaronbaumanComment #15
armyguyinfl commentedI believe this issue 3074441 commit 5783bbe2 line 205-206 broke any SF mappings for any date fields that are mapped. If the value of the date field is null or not populated by user input then you are passing a default current date/time in UTC which SF rejects as a non-valid date (8:00 PM 6/25 = 0000 UTC 6/26 Future Date for GMT -4) for date of birth or invalid future date use cases.
Released: https://www.drupal.org/project/salesforce/releases/8.x-3.5
We had to roll back the Salesforce module to 8.x-3.4 because this broke all lead object submission mappings. This also pollutes any date field that is mapped and null on POST with the current/datetime which is unwanted bad data.
Comment #16
armyguyinfl commentedComment #17
didebruFirst apoligise for hijacking a closed issue.
2 problems with the patch.
DateTime::ISO8601 is not longer available for php >7.2
The date timestamp needs also the ISO8601 format.
Proposal: