Rule #1 – Every User in Salesforce has a Time Zone which is based on the region and adjusts automatically for DST
Whenever you create a new User in Salesforce, the Time Zone field should be populated as it is required, which means that every User has an associated Time Zone. In other words, no User can be created without a Time Zone! On top of that, the Company has a default Time Zone.
You can set a User’s Time Zone in the User’s record, and to get your User’s Time Zone, run this in Anonymous Apex:
TimeZone tz = UserInfo.getTimeZone(); System.debug('Time Zone ID: ' +tz.getID()); System.debug('Time Zone Display name: ' +tz.getDisplayName()); // Returns: // DEBUG|Time Zone ID: America/New_York // DEBUG|Time Zone Display name: (GMT-05:00) Eastern Standard Time (America/New_York)
And to get the Organization default Time Zone, we use a SOQL query which returns the Time Zone Id, in my case “America/New_York”:
SELECT TimeZoneSidKey FROM Organization
Also, as you can see, the Time Zone is displaying a region, and not a difference in hours. So, the difference in hours will change according to the Daylight Saving Time! A Time Zone of “America/New_York” will change from UTC/GMT-04:00 to UTC/GMT-05:00 according to the DST.
So what? What does this affect DateTime objects in Apex? Let’s visit the second Rule below.
Rule #2 – DateTime objects are saved in GMT
In Salesforce, every time you instantiate and insert a DateTime object, it gets saved in the database in GMT Time Zone and it is translated to the user’s time zone when reading it.
There are many ways to instantiate a DateTime object in Salesforce: using the DateTime class with many methods! The most popular method is DateTime.newInstance(year, month, day, hour, minute, second). This method constructs a Datetime from Integer representations of the specified year, month (1=Jan), day, hour, minute, and second in the User’s time zone. My User’s Time Zone is America/New_York, so everytime I instantiate a DateTime object using the newInstance method, I use this Time Zone as my reference, but remember, Salesforce only deals with GMT DateTime! To make it clear, check the below code, and keep in mind my User’s Time Zone. What do you think the debug outcome will be?
DateTime dt = DateTime.newInstance(2020, 01, 20, 15, 0, 0); System.debug(dt);
I am instantiating a new DateTime object of January 20, 2020, 3 PM. This will be based on my User’s Time Zone because I am using the method newInstance, and will be saved in the database in GMT! Yes, the input is based on the User’s Time Zone, but the actual record is saved in the equivalent GMT time, because GMT is used to save ANY DateTime object! For that, and because the difference between Eastern Time and GMT is 5 hours, the debug outcome is:
But there are other ways to instantiate a DateTime object. For example, using DateTime.newInstanceGMT will treat the parameters as GMT, and the below 2 objects yield the same retult:
DateTime dtGMT = DateTime.newInstanceGMT(2020, 01, 20, 20, 0, 0); DateTime dtLocal = DateTime.newInstance(2020, 01, 20, 15, 0, 0); System.debug('GMT DateTime: ' +dtGMT); System.debug('Local DateTime: ' +dtLocal); // Returns: // DEBUG|GMT DateTime: 2020-01-20 20:00:00 // DEBUG|Local DateTime: 2020-01-20 20:00:00
There is also a way to read the DateTime in any Time Zone that you want using the method DateTime.format. This method can take 2 parameters. The first one is the date format string, and the second is the Time Zone ID. The date format string specifies the format of the returned DateTime string. For more information on the Java simple date format, see Java SimpleDateFormat. The Time Zone Id should be a valid time zone of the Java TimeZone class that correspond to the time zones returned by the TimeZone.getAvailableIDs method in Java.
Datetime GMTDate = Datetime.newInstanceGmt(2011,6,1,12,1,5); String strConvertedDate = GMTDate.format('MM/dd/yyyy HH:mm:ss', 'America/New_York'); // Date is converted to the new time zone and is adjusted for daylight saving time. System.assertEquals('06/01/2011 08:01:05', strConvertedDate);
Rule #3 – If possible, try to avoid Datetime field, and use Date field instead
If your use case only requires a Date without a specific Time, do use the Date type instead of the DateTime type, that’s because the Date type does not care about anything related to Timezone.
For example, let’s instantiate a Date and a DateTime objects:
DateTime dt = DateTime.newInstance(2020, 01, 20, 22, 0, 0); Date d = Date.newInstance(2020, 01, 20); System.debug(dt); System.debug(d); System.debug('DateTime: ' +dt); System.debug('Date: ' +d); // Returns: // DEBUG|GMT DateTime: 2020-01-21 03:00:00 // DEBUG|Local DateTime: 2020-01-20 00:00:00
- Every User has an associated TimeZone
- DateTime objects are saved in GMT in Salesforce
- A User will read a DateTime object depending on his/her TimeZone
- Try to avoid DateTime if what you need is just a Date