anthonyreilly / NetCoreForce

Salesforce REST API toolkit for .NET Standard and .NET Core
MIT License
110 stars 63 forks source link

DateTime fields automatically converted to UTC by substracting current timezone from date. #55

Closed sergey-bulavskiy closed 1 year ago

sergey-bulavskiy commented 1 year ago

Hello, i'm not sure if it is a expected behavior, but i've encountered a problem with DateTime fields of the entities.

I'm located in +6 timezone and if i create an entity with datetime for example Now or UtcNow, DateTime or DateTimeOffset, seems like during serialization timezone is automatically substracted from DateTime property before sending it to SF. In the end we have a situation when dates converted to previous days.

Example tests: Test scenario is i've created a SfContact with BirthDate specified locally (stored as expected date), sent it to salesforce and got it back via API (actual date)

image

This is when i set date to 07 in the morning for example. image

sergey-bulavskiy commented 1 year ago

Example test:

            var date = new DateTime(2000, 1, 1, 7, 0, 0);
            var dateUnspecified = DateTime.SpecifyKind(date, DateTimeKind.Unspecified);
            var dateUtc = DateTime.SpecifyKind(date, DateTimeKind.Utc);
            var dateLocal = DateTime.SpecifyKind(date, DateTimeKind.Local);

           // Just create SfContact and send RestClient.CreateRecord(SfContact.SObjectTypeName, contact);
            var contactUnspecified = await _salesforceFixture.CreateContact(birthDate: dateUnspecified);
            var contactUtc = await _salesforceFixture.CreateContact(birthDate: dateUtc);
            var contactLocal = await _salesforceFixture.CreateContact(birthDate: dateLocal);

            var actualUnspecified =
                (await _salesforceFixture.RestClient.GetObjectByIdOrDefault<SfContact>(SfContact.SObjectTypeName,
                    contactUnspecified.Id)).Birthdate;

            var actualUtc =
                (await _salesforceFixture.RestClient.GetObjectByIdOrDefault<SfContact>(SfContact.SObjectTypeName,
                    contactUtc.Id)).Birthdate;

            var actualLocal =
                (await _salesforceFixture.RestClient.GetObjectByIdOrDefault<SfContact>(SfContact.SObjectTypeName,
                    contactLocal.Id)).Birthdate;

            _testOutputHelper.WriteLine($"Unspecified\n Expected: {contactUnspecified.Birthdate} - Actual: {actualUnspecified}");
            _testOutputHelper.WriteLine($"Utc\n Expected: {contactUtc.Birthdate} - Actual: {actualUtc}");
            _testOutputHelper.WriteLine($"Local\n Expected: {contactLocal.Birthdate} - Actual: {actualLocal}");

            var expected = (dateUnspecified, dateUtc, dateLocal);
            var actual = (actualUnspecified, actualUtc, actualLocal);

            Assert.Equal(expected, actual);

Assert: image

Output: image

sergey-bulavskiy commented 1 year ago

To be sure that it is not just time-trimming:

If we change date to var date = new DateTime(2000, 1, 1, 0, 0, 0);

We'll get such result: image

anthonyreilly commented 1 year ago

Thanks for the details and tests - I'll look into this

sergey-bulavskiy commented 1 year ago

Hey, just wanted to clarify if you have any plans to fix it soon, or i should go for workarounds. No problem if there are other priorities, just to be sure whether i should spend time on workarounds. I can try to come up with pull request with potential fix if you accept any.

anthonyreilly commented 1 year ago

Sorry it took so long to validate, but this is expected behavior - the Birthdate is a "Date" datatype in salesforce, which does not support timezone offsets, so the offsets will be ignored on the Salesforce side. I added some date handling unit tests to verify this. Other "DateTime" fields should behave as expected. https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/intro_valid_date_formats.htm

sergey-bulavskiy commented 1 year ago

Yes, indeed it seems like it was a two problems, first one is that we expected Date field to have time, which is delirious by itself, second one was that we created date time entities with unspecified timezone and sent them to salesforce, which later convert them to UTC timezone forcibly. I think we can close this issue. Sorry to take your time :)