The Local Time App for Salesforce has out-of-the-box support for getting the time zone information for Account, Contact, and Lead standard Salesforce objects. However, if you have another standard or custom object where you would like to fetch similar time zone information, then this blog post could be of interest to you.
The following sample apex code illustrates how to write a trigger on a fictitious custom object called Activation__c to get the time zones information. You can use this sample code as a starting point and customize it to fit your specific requirements.
Pre-requisite
It is assumed that you have installed Local Time App version v2.20 or later in your sandbox and production environments. You can install the latest version of the App from this link.
Process
- Create the custom fields, trigger code, and test class in the sandbox. Test thoroughly.
- Create a change set with all the relevant components from the sandbox (custom fields, trigger code, and test class) and send the change set to production.
- Deploy the change set in production by using the inbound change set.
Create Custom Fields
Create the following custom fields in the custom object for which you are implementing the trigger. Note that if you already have fields that store Country, State, City, and Postal Code values, then you do not have create them again, but can re-use them in the apex code.
- Timezone_F__c formula
IF(DST_Setting__r.tz__DST__c , Timezone_DST__c, Timezone_Standard__c )
- Timezone_Full_F__c formula
IF(DST_Setting__r.tz__DST__c , Timezone_DST_Full__c, Timezone_Standard_Full__c )
- UTC_Offset_F__c formula
IF( DST_Setting__r.tz__DST__c , UTC_Offset_DST__c, UTC_Offset_Standard__c )
- Local_Time__c Formula (Text)
IF(ISBLANK(UTC_Offset_F__c), "Unknown", MID( TEXT( NOW()+ UTC_Offset_F__c /24 ), 6, 2 ) & "/" & MID( TEXT( NOW()+ UTC_Offset_F__c /24 ), 9, 2 ) & "/" & LEFT( TEXT( NOW()+ UTC_Offset_F__c /24 ), 4 ) & " " & TEXT( IF( OR( VALUE( MID( TEXT( NOW()+ UTC_Offset_F__c /24 ), 12, 2 ) ) = 0, VALUE( MID( TEXT( NOW()+ UTC_Offset_F__c /24 ), 12, 2 ) ) = 12 ), 12, VALUE( MID( TEXT( NOW()+ UTC_Offset_F__c /24 ), 12, 2 ) ) - IF( VALUE( MID( TEXT( NOW()+ UTC_Offset_F__c /24 ), 12, 2 ) ) < 12, 0, 12 ) ) ) &":"& MID( TEXT( NOW()+ UTC_Offset_F__c /24 ), 15, 2 ) &" "& IF( VALUE( MID( TEXT( NOW()+ UTC_Offset_F__c /24 ), 12, 2 ) ) < 12, "AM", "PM" ) & " " & Timezone_F__c )
Create Trigger code
Implement the following trigger on the custom object.
trigger ActivationLocalTimeTrigger on Activation__c (before insert, before update) { ActivationTriggerHandler.populateTimezoneInfo(Trigger.new); }
Create Trigger Handler Class
Implement the following apex class which is called from the trigger. Replace Country__c, State__c, City__c, and Postal_Code__c custom fields with the appropriate fields from your custom object.
public with sharing class ActivationTriggerHandler { // sub class to store the time zone request information public with sharing class TimezoneRequest { public String id; // record id or some unique key public String country; public String state; public String city; public String postalcode; public String phone; public Boolean adjust_dst; // set it to true if data needs to be adjusted for DST public Boolean broad_match; // set it to true if result does not need to be very clear-cut or definitive } // sub class to store time zone response public with sharing class TimezoneResponse { public String id; // record id or some unique key public Decimal offset; public Decimal dst_offset; public String abbreviation; public String dst_abbreviation; public String tz_name; public String dst_tz_name; public String tz_iana; // timezone by iana org public String tz_sfdc; // salesforce timezone public String dst_setting; // Id of the DST_Setting__c record public String system_country; // country name in the database public String system_state; // state name in the database } public static void populateTimezoneInfo(List<Activation__c> lstActivations) { // STEP 1 - Create the request List<TimezoneRequest> tz_reqs = new List<TimezoneRequest>(); Map<String, Activation__c> mapObjs = new Map<String, Activation__c>(); Integer nCounter = 0; for(Activation__c act : lstActivations) { // Empty old values act.DST_Setting__c = null; act.UTC_Offset_Standard__c = null; act.UTC_Offset_DST__c = null; act.Timezone_Standard__c = null; act.Timezone_DST__c = null; act.Timezone_IANA__c = null; act.Timezone_SFDC__c = null; act.Timezone_Standard_Full__c = null; act.Timezone_DST_Full__c = null; TimezoneRequest tz_req = new TimezoneRequest(); tz_req.id = 'objkey_' + nCounter; tz_req.country = act.Country__c; tz_req.state = act.State__c; tz_req.city = act.City__c; tz_req.postalcode = act.Postal_Code__c; tz_req.adjust_dst = false; tz_req.broad_match = false; tz_reqs.add(tz_req); mapObjs.put(tz_req.id, act); nCounter++; } // STEP 2 - Make the API call String request = JSON.serialize(tz_reqs); String resp = tz.LocalTimeV2.getTimezones(request); // STEP 3 - Process the response Map<String, List<TimezoneResponse>> map_tzones = (Map<String, List<TimezoneResponse>>) JSON.deserialize(resp, Map<String, List<TimezoneResponse>>.class); for(String key : map_tzones.keySet()) { if(mapObjs.containsKey(key)) { Activation__c act = mapObjs.get(key); List<TimezoneResponse> tzone = map_tzones.get(key); // Set the timezone info on the record only the first time if(act.DST_Setting__c == null && tzone[0].dst_setting != null) { act.DST_Setting__c = tzone[0].dst_setting; act.UTC_Offset_Standard__c = tzone[0].offset; act.UTC_Offset_DST__c = tzone[0].dst_offset; act.Timezone_Standard__c = tzone[0].abbreviation; act.Timezone_DST__c = tzone[0].dst_abbreviation; act.Timezone_IANA__c = tzone[0].tz_iana; act.Timezone_SFDC__c = tzone[0].tz_sfdc; act.Timezone_Standard_Full__c = tzone[0].tz_name; act.Timezone_DST_Full__c = tzone[0].dst_tz_name; } } } } }
Create Test Class
Create a test class to get adequate coverage for your trigger code. Following is a sample test class. Ensure that you make any changes to it where necessary for the test class to pass successfully.
@isTest(SeeAllData=true) private class ActivationLocalTimeTriggerTest { static testmethod void testTrigger(){ // Create a test activation record Activation__c a = new Activation__c(); a.Name = 'Test Activation'; a.City__c = 'Houston'; a.State__c = 'TX'; a.Country__c = 'USA'; // Populate any more mandatory fields insert a; system.assert(a.Id != null); List<Activation__c> aTmp = [SELECT Id, Timezone_F__c FROM Activation__c WHERE Id=:a.Id]; system.assert(aTmp.size() == 1); system.assert(aTmp[0].Timezone_F__c == 'CST' || aTmp[0].Timezone_F__c == 'CDT'); } }
Modify Page Layout
Add the relevant time zone fields to the custom object page layout. Whenever you create or edit the custom object record, the trigger will fire and calculate the values for these fields.
Deploy to Production
Create the outbound change set in the sandbox and add the above components to it. Send the change set to the production org. Login to production org and then deploy the inbound change set.