Home » Development

Category Archives: Development

All about Date and Time in Salesforce

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);

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:

DEBUG|2020-01-20 20:00:00

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('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 

VS Code Extension: Uncrustify Code Formatter

This is the second post about VS Code Fomatters for Salesforce. In this post, I will explain about Uncrustify.

Download and install Uncrustify:

The first step is to get Uncrustify on our computer

  • Go to: https://sourceforge.net/projects/uncrustify/files/uncrustify/
  • Depending on your OS, download the right package. In my case, I got the Windows 64-bit ZIP file: uncrustify-0.69.0-win64.zip 
  • Unzip the ZIP file to a folder. I picked C:\Uncrustify\
  • Add this folder to the Windows PATH environment variable:
    • Open the “Control Panel”
    • Go to “System and Security”, then to “System”
    • Click on “Advanced system settings” 
    • Go to the Advanced tab, and click on “Environment Variable” button at the bottom
    • In the System Variables section, select the “Path” variable and click on Edit 
    • Nowm click on New, and add the folder above. In my case: C:\Uncrustify\. Click Ok on all open windows. 


Add Uncrustify to VS Code:

Now, it’s time to add the Uncrustify extension on Visual Studio Code. For that:

  • Go to the Extensions tab in VS Code
  • Search for “Uncrustify
  • Add it to VS Code
  • Restart VS Code


Configure Uncrustify in VS Code:

  • In Visual Studio Code, press Ctrl +Shift + P, and search for “Uncrustify: Create Default Config File”. Select it and press Enter
  • This will create a file that you can now access on the Explorer pane pon the left. The file name is “uncrustify.cfg”
  • Click on this file to open it in VS Code
  • Note: to see the Save menu, hover to the right side.
  • Go to the “General Options”
    • Set the value 4 in Input_Tab_Size
    • Set the value 4 in Output_Tab_Size
    • Click on “Save”
  • Go to the “Indenting”
    • Set the value 4 in indent_columns
    • Set to true indent_class
    • Click on Save
  • Feel free to go through al the settings and changing them accordingly 


Run Uncrustify:

  • To Run Uncrustify to format code, open any Apex file, then press Ctrl + Shift + P
  • Search for the word “Format” 
  • Choose “Format Document” 
  • Select Uncrustify. This option will only be displayed if you have multiple formatters. In my cae, I have both Prettier and Uncrustify. 
  • You can avoid all these steps by simple pressing Shift + Alt + F to format the whole document, or Ctrl + K Ctrl + F to format the selection only. 



  • You can use the same “uncrustify.cfg” file in other projects. Just copy it from the source project folder and paste it in the new project folder. 
  • Just as the Prettier post before, you can set the Default formatter in VS Code Settings:
    • In VS Code, go to File – Preferences – Settings.
    • Search for Format.
    • This is where you can also configure many settings for Formatting, like the efautl Formatter, fortmat on Paste and so on…

VS Code Extension: Prettier Code Formatter

VS Code is becoming the most popular Salesforce IDE, but unfortunately, VS Code does not have a default code formatter for Apex! For that, we can use some extensins like Prettier and/or Uncrustify. In this post, I will explain how I installed Prettier, and in the next post I will explain about Uncrustify.


Install Node.Js on your computer:

To begin, Node.JS should be installed on your computer. If it is not installed yet, follow these steps: 

  • Go to: https://nodejs.org/en/download/
  • Depending on your OS, download the right package. In my ase, I got the Windows 64-bit MSI file. 
  • Choose the installation folder. I picked: C:\Program Files\nodejs\
  • Make sure that “Add to PATH” installation option is checked. 

Now, add the Node.JS Extension Pack extension to VS Code:

  • Go to the Extensions tab in VS Code
  • Search for “Node.js Extension Pack
  • Add it to VS Code
  • Restart VS Code 

Once VS Code is restarted, let’s install Prettier.


Install Prettier:

  • First, you don’t already have a package.json in your project, run the command “npm Init”. Check the left Explorer pane to see if this file exists, or search for it usong Ctrl + P. 
    • Go to the Terminal tab, and type “npm init”. Or, press Ctrl + Shift + P, and choose “npm: Run Init”
    • Accept all the defaults
  • Note that this step should be done once per org.
  • Install Prettier by running in the Terminal: npm install --save-dev --save-exact prettier prettier-plugin-apex
  • This should be done for each org. 
  • Create a Prettier configuration file called .prettierrc, in the root of your project, by right clicking on the left Explorer pane, and selecting “New File”. The file should be called .prettierrc, with a dot at the beginning. 
  • Copy and paste the below content and paste them int the file. Save the file.
    "trailingComma": "none",
    "overrides": [
        "files": "**/lwc/**/*.html",
        "options": { "parser": "lwc" }
        "files": "*.{cmp,page,component}",
        "options": { "parser": "html" }
  • Install the Prettier extension for VS Code:
  • Go to the Extensions tab in VS Code
  • Search for “Prettier Code Formatter
  • Add it to VS Code
  • Restart VS Code


Run Prettier:

  • To Run Prettier to format code, open any Apex file, then press Ctrl + Shift + P
  • Search for the word “Format” 
  • Choose “Format Document” 
  • Select the Prettier Formatter. This option will only be displayed if you have multiple formatters. In my case, I have both Prettier and Uncrustify. 
  • You can avoid all these steps by simple pressing Shift + Alt + F to format the whole document, or Ctrl + K Ctrl + F to format the selection only. 

As you can see, my Apex file has been formatted! 



  • If you want to ensure that all your files are formatted, enable the setting editor.formatOnSave in VS Code. For information about configuring your settings, see User and Workspace Settings in the Visual Studio Code docs.

  • Apex Prettier runs slower than most other formatters. In some cases formatting will not succeed because VS Code will time out the operation after 500ms. In order to ensure Apex code has enough time to format your documents we recommend changing the VS Code settings as follows.

  "editor.formatOnSaveTimeout": 5000

This can be done also from the File – Preferences – Settings. Search for Format. This is where you can also configure many settings for Formatting, liek the efautl Formatter, fortmat on PAste and so on…

Trigger to convert FSL Service Appointment time to the Service Territory timezone

Use case:

In Field Service Lighting, and upon scheduling Service Appointment to Resources, the system uses the local user’s Timezone to populate the Scheduled Start and Scheduled End date/time fields: 

But what if the Serivce Appointment location is in a Territory with different Timezone than the logged-in User’s Timezone? We need to find a way to capture the Scheduled Start Time in this Timezone as opposed to the default behavior that displays the Scheduled Start date time following the logged-in User’s timezone. Why? Well, what if we want to send a notification email to the customer informing them of the Scheduled Start time? It wouldn’t make perfect sense if it was not based on their local Timezone! 

As as example, if the Salesforce Dispatcher is in Toronto (Eastern Time), and the Service Appointment belongs to a Service Territory that follows the Pacific Time, then we need to see the Scheduled start date time in the Pacific, and not only in Eastern Time, and then we will use this local Scheduled Start in the email Template sent to the customer upon Dispatching for example. 

The data model is as follows:

  • Work Order is first created. It has a lookup to the Service Territory
  • The Service Territory has a lookup to the Operating Hour
  • The Operating Hour has a field called TimeZone that specifies the Timezone of this Territory 
  • Service Appointment can be created directly with the Work Order or after the Work Order. 
  • Service Appointment has a lookup to the parent Work Order 
  • Service Appointment has a lookup to the Service Territory, which has a lookup to the Operating Hour record, which has the TimeZone 



Upon creating the Service Appointment, the Scheduled Start date time is saved as the current Salesforce User Timezone! There is no way to get the Scheduled Start time on the Territory timezone!


A little bit of background:

There exists a method that deals with time conversion based on Timezones! Passing a day time field to a Format method returns the date time in the format specified, and following the timezone specified. For example: 

System.debug(System.now().format('YYYY-MM-dd HH:mm:ss', 'America/Los_Angeles'));


Returns the current time of the America/Los_Angeles timezone. 

17:35:08:002 USER_DEBUG [1]|DEBUG|2019-06-13 14:35:08


You can find all the available Timezone names here: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones



To sort this, we will use a trigger that will use the format method to give the date time text value.

  • On the Service Appointment object, let’s create a custom field called Local_Scheduled_Start__c,
  • Let’s then create an After Insert and After Update Service Appointment Trigger 
  • Finally, we will create the Trigger Handler class that contains the method called by the Trigger


The Trigger is used to simply call a method on the Handler class:

trigger ServiceAppointmentTrigger on ServiceAppointment (after insert, after update) { 
    If (trigger.isAfter && trigger.isUpdate) {
    If (trigger.isAfter && trigger.isInsert) {


And now the Apex Class Handler that contains the method called by the Trigger:

public class ServiceAppointmentTriggerHandler {
    //Boolean to control recursion as this is after update
    public static Boolean boolStopRun = false;
    public static void handleAfterInsertUpdate(List<ServiceAppointment> triggerNew) {
        //Stop the run if this code was already run
        if (boolStopRun) return;
        //Make boolStopRun true in order to stop the run and prevent recursion - should be here not at the end 
        boolStopRun = true;
        //1- get all SA Ids
        Set<Id> setSAId = new Set<Id>();
        for (ServiceAppointment sa : triggerNew) {
            if (sa.SchedStartTime != Null) {
        //2- Get List of SAs including the ServiceTerritory OperatingHours TimeZone
        List<ServiceAppointment> lstSA = [SELECT Id, AppointmentNumber, SchedStartTime, ServiceTerritory.OperatingHours.TimeZone
                                          FROM ServiceAppointment 
                                          WHERE Id IN : setSAId];
        //3- create thge list with Local Scheduled Start and update it at the end 
        List<ServiceAppointment> lstSaToUpdate = new List<ServiceAppointment>();
        for (ServiceAppointment sa : lstSA) {
            //get the Timezone, returned value example "America/Los_Angeles"
            String strSTTZ = sa.ServiceTerritory.OperatingHours.TimeZone;
            //Passing a day time field to a Format method returns the date time in the format specified, and following the timezone specified
            String strLocalSchedStartTime = sa.SchedStartTime.format('MM/dd/YYY HH:mm', strSTTZ);
            ServiceAppointment saUpdated = new ServiceAppointment();
            saUpdated.Id = sa.Id;
            saUpdated.Local_Scheduled_Start__c = strLocalSchedStartTime;
        update lstSaToUpdate;       

And here’s the result:

Salesforce Ant Migration Tool Tutorial

I recently used the Ant Migration Tool for deployment and loved it compared to the slow Change Sets. The Ant Migration Tool is a Java/Ant-based command-line utility for moving metadata between a local directory and a Salesforce org. You can use it to deploy from any org to any other org, related or not, and it’s way faster than Change Sets.

Before you can use the Ant Migration Tool, Java JDK and Ant must be installed and configured correctly on your computer. If you already have JDK and Ant on your computer, you don’t need to install them, so first verify this from a command prompt.

If you don’t have Java JDK installed, follow these steps:


  • Click on JDK and note the installation path during the installation. My path was C:\Program Files\Java\jdk1.8.0_201
  • After installing JDK, verify the version by typing this command: java -version

If you don’t have Ant installed, follow these steps:


  • Extract the downloaded Zip to a directory that will be used as the Ant home. I extracted the Zip to D:\ANT_HOME

After installing both JDK and Ant, make sure you have these Environment Variables set: 

  • Add ANT_HOME and JAVA_HOME variables::
  • Right-click “This PC” – Properties – Advanced System Setting
  • Click Environment Variables


  • Add 2 new Variables called ANT_HOME pointing to your Ant installation folder D:\ANT_HOME, and JAVA_HOME pointing to the JDK installation folder C:\Program Files\Java\jdk1.8.0_201. Also, add these 2 folders to the Path variables as shown in the second screenshot.


It’s time to install the Ant Migration Tool itself:


  • And the sample Folder contains: 


  • The files build.properties and build.xml are 2 critical files. We will see about these in a while.

Let’s prepare the Ant Migration Tool!

  • To start using the Ant Migration Tool, we should first decide about the Source org, which will be used to get the metadata from, and the Destination org, which will be used to deploy the metadata to, from the Source org. 
  • The Source / Destination orgs can be of any edition (Developer, Production, Sandbox…), and they can indeed be not related at all 
  • Once you know the Source org, go to this tool https://packagebuilder.herokuapp.com/ to retrieve the manifest file package.xml. This file is an XML file that defines the metadata of the org. 
  • Specify the org type (Production or Sandbox), then click on LOGIN TO SALESFORCE WITH OAUTH, then enter your username and password.
  • In my case, the Source org is a Developer org with this username below: 

  • Click on Allow access to give access to the Package Builder tool for it to get the Metadata manifest package.xml file
  • Now choose the components you want, in my case, I will get all the components, excluding the managed ones, Then click on GET COMPONENTS 

  • Once you have the xml file displayed in the browser, select all its content, and copy it… then save it in a file named package.xml. If I can’t save an xml file directly from the browser, I save it as a txt file, then rename it using the “ren” windows command: ren package.xml.txt package.xml. This will rename the file from a txt extension to an xml one. 
  • Open the package.xml file using your preferred editor (I use VS Code to open my xml files), and go through it. You will notice that it is simply an XML file that contains tags corresponding to the different metadata components, just like when you choose components in a Change Set, but this is actually much faster! There is UI, and no need to wait 10 mins for the page to load!
  • The type of the component is inside the name tag, for example
    CustomApplication represents the list of all custom Apps components. MatchingRule represents the list of all Matching Rules components. You can choose to exclude all of the components of type MatchingRule by deleting the whole tag between <type>…</type> , including the corresponding opening and closing tags<type> and </type>. Also, you can delete individual components by deleting members tags instead and keeping the type and the name tags.

Here is the MatchingRule set of components between the <types> tag:


  • Now, specify what metadata you want to keep – for example, in my case, I just want to deploy a custom App with its related metadata.
  • So, here is my final package.xml file that only includes what  I want to retrieve

<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
        <members>Building__c-Building Layout</members>
        <members>Classroom__c-Classroom Layout</members>
        <members>Course_Registration__c-Course Registration Layout</members>
        <members>Course__c-Course Layout</members>
        <members>Student__c-Student Layout</members>

  • Create a folder that clearly specifies the project in the D:\AND_MIG_Tool folder. In my case, I created a folder called PD2__Shark. This folder will be used to retrieve metadata from the PD2 org, and deploy to another org called Shark – which is a Trailhead Playground org 😀  
  • Inside this Folder, create another Folder called codepkg
  • Copy the package.xml file in this folder D:\ANT_MIG_Tool\PD2__Shark\codepkg
  • Copy the 2 files build.properties and build.xml from the sample Folder to the Folder D:\ANT_MIG_Tool\PD2__Shark. We will rely on when retrieving and deploying the metadata
  • Open the build.properties file, and replace as per the below:
  • sf.username is the username of the Source org, sf.password is the password followed by the Token, and sf.serverurl depends on whether the Source is a Production (or Developer) edition or a Sandbox. 

Let’s use the Ant Migration Tool!

  • Now, everything is set to retrieve the actual metadata from the source org:
    • package.xml is ready
    • build.properties is modified with the source org credentials 
    • The folder structure is built
  • Open Command Prompt, and go to the project folder D:\ANT_MIG_Tool\PD2__Shark
  • Issue the command

ant retrieveCode



  • This will fetch the metadata from the source org, and add  them to the folder D:\ANT_MIG_Tool\PD2__Shark\codepkg
  • Now, to deploy this metadata to the Destination org, we need to change the credentials in the build.properties file. We need to replace the username / password+token and server URL with the right Destination values
  • Issue the command: ant deployCodeCheckOnly


ant deployCodeCheckOnly


  • This will Validate the deployment without actually deploying it on the Destination org. Just like your standard Change Set validation. In fact, you can see the validation result on the Destination org as well on the Command Prompt 
  • Finally, to deploy the components, we will issue the command: 


ant deployCode


Here is a list of all commands that can be used with Ant:

Command Description
ant bulkRetrieve
Retrieve all the items of a particular metadata type
ant retrieveUnpackaged
Retrieve an unpackaged set of metadata from your org
ant retrievePkg
Retrieve metadata for all the packages specified under packageNames
ant deployUnpackaged
Deploy the unpackaged set of metadata retrieved with retrieveUnpackaged and run tests in this organization’s namespace only
ant deployZip
Deploy a zip of metadata files to the org
ant deployCode
Upload the contents of the “codepkg” directory, running the tests for just 1 class
ant deployCodeNoTestLevelSpecified
Shows deploying code with no TestLevel sepcified
ant deployCodeRunLocalTests
Shows deploying code and running tests only within the org namespace
ant undeployCode
Shows removing code
ant retrieveCode
Retrieve the contents listed in the file codepkg/package.xml into the codepkg directory
ant deployCodeCheckOnly
Shows check only; never actually saves to the server
ant quickDeploy
Shows quick deployment of recent validation.
ant cancelDeploy
Shows cancel deployment of deploy request either pending or in progress
ant listMetadata
Retrieve the information of all items of a particular metadata type
ant describeMetadata
Retrieve the information on all supported metadata type


Finally, here is the Ant Migration Tool implementation Guide from Salesforce. 





The Complete Salesforce Certified Platform Developer I Course

Hey Folk,

Great News! I just finished recording and uploading the Complete Salesforce Certified Platform Developer I Course on Udemy.

This is a 14-hour course that I have designed and built to be 100% aligned with the official exam Study Guide of the latest Winter 20 Salesforce Certified Platform Developer I release, and I will be updating it on each subsequent release if necessary. I am currently running a promo during July with a heavy discount on this course. Just click on this LINK to access the discount course page.

The official Study Guide has the following Sections, and each Section has many Topics within it:

  1. Salesforce Fundamentals – 10%
  2. Data Modeling and Management – 12%
  3. Logic and Process Automation – 46%
  4. User Interface – 10%
  5. Testing – 12%
  6. Debug and Deployment Tools – 10%

Each topic mentioned in the Study Guide under each Section above is covered in this course, and each topic has at least a video lecture that is divided into a presentation, and a demo on the Salesforce environment. Some topic have up to 5 lectures, like the SOQL, SOSL and DML topic that is under Section 3!

I am sharing all the slides in PDF so that you could download them and read them offline, and I am also sharing a lot of reference links in each lecture. These reference include links to Trailhead modules, links to the sources I have used to build the slides, links to official Salesforce documentation related to the topic, and links to official Salesforce guides and eBooks.

This course also contains more than 100 quiz questions, none of them are from dumps. I HATE dumps, I have never used them in my IT certifications, and I don’t want you to pass this exam based on a bunch of questions from dumps! The questions in this exam are 100% dump free, and they are all designed based on the course content and on real-life scenarios.

Finally, I have been there, I spent hours and hours preparing for this exam, I dissected each and every topic of the Study Guide, and took tons of notes, just like I did when preparing for my other certifications. I guarantee that after completing this course, and after practicing on the Salesforce environment, you will pass this exam, and you will become Salesforce Platform Developer I Certified!

Good Luck!