forcedotcom/wsc

getBirthDate() returns java.util.GregorianCalendar with wrong timezome

jersoe-uri opened this issue · 3 comments

Our SF instance is set to America/New_York. I call getBirthDate() on a Contact with a birthdate that is set to 8/2/1983. It returns this object:

java.util.GregorianCalendar[time=428630400000,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="America/New_York",offset=-18000000,dstSavings=3600000,useDaylight=true,transitions=235,lastRule=java.util.SimpleTimeZone[id=America/New_York,offset=-18000000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=1983,MONTH=7,WEEK_OF_YEAR=32,WEEK_OF_MONTH=1,DAY_OF_MONTH=1,DAY_OF_YEAR=213,DAY_OF_WEEK=2,DAY_OF_WEEK_IN_MONTH=1,AM_PM=1,HOUR=8,HOUR_OF_DAY=20,MINUTE=0,SECOND=0,MILLISECOND=0,ZONE_OFFSET=-18000000,DST_OFFSET=3600000]

Notice that the epoch is set to 428630400000. That is the correct date in GMT. I expected to either see that the timezone of the returned object was set to GMT instead of America/New_York, or that the epoch was set to 428644800000, which is 8/2/1983 in America/New_York.

Thanks for reporting this - we'll take a look into it.

The behavior is as expected firstly in above output the message mentions the DAY_OF_MONTH=1 instead of DAY_OF_MONTH=2 for the 8/2/1983 indicative of the fact the user entered the wrong date.

As a measure for checking this behavior went ahead and tested the getBirthDate() for both Enterprise and Partner Connections here is Pull Request for it.

https://gitcore.soma.salesforce.com/core-2206/core-public/pull/164134/files

The output for above case is as follows

java.util.GregorianCalendar[time=428716800000,areFieldsSet=true,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="America/New_York",offset=-18000000,dstSavings=3600000,useDaylight=true,transitions=235,lastRule=java.util.SimpleTimeZone[id=America/New_York,offset=-18000000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=1983,MONTH=7,WEEK_OF_YEAR=32,WEEK_OF_MONTH=1,DAY_OF_MONTH=2,DAY_OF_YEAR=214,DAY_OF_WEEK=3,DAY_OF_WEEK_IN_MONTH=1,AM_PM=1,HOUR=8,HOUR_OF_DAY=20,MINUTE=0,SECOND=0,MILLISECOND=0,ZONE_OFFSET=-18000000,DST_OFFSET=3600000]

The return type for the getBirthDate() is a java.util.Calendar datatype
In Java, Dates are internally represented in UTC milliseconds since the epoch (so timezones are not taken into account, that's why you get the same results for the epoch in milliseconds irrespective of the timezone WHICH IS DEFAULT JAVA BEHAVIOR FOR java.util.Calendar and not something WSC specifically controls it and thus is working as desired.

Please read the following articles to understand the behavior of java.util.Calendar in Java

  1. https://stackoverflow.com/questions/13470830/how-to-change-timezone-for-a-java-util-calendar-date
  2. https://stackoverflow.com/questions/7670355/convert-date-time-for-given-timezone-java%20.
  3. https://stackoverflow.com/questions/42161438/java-calendar-timezone-change-not-working-as-expected

To verify this behavior for the issue raised and to find the actual date that was set just use the epoch in this case 428716800000 and the timezone which was set here for the user it was America/New_York which is also visible from the output for the getBirthDate() method for this example.

Just simply add the offset back to see the original Calendar value that was set to the milliseconds obtained to get back the proper output. (Recommended approach as per all the documentations above)

Solution for the issue above raised is to simply add the offset back while conversion represented below:

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public class SectoDate {
public static void main(String args[])
{

// milliseconds
long milliSec = 428716800000L;

// Creating date format
DateFormat simple = new SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ssZ");
simple.setTimeZone(TimeZone.getTimeZone("America/New_York"));
// Creating date from milliseconds
// using Date() constructor
Date result = new Date(milliSec);

// Formatting Date according to the
// given format
System.out.println(simple.format(result));
}
}

Giving the desired output 02 Aug 1983 20:00:00:000 -0400 on conversion

Closing the issue based on the explanation provided by @riyasurisalesforce in the above comment