[SalesForce] system.runas and user’s time zone

I am writing a test class for testing an API, which populates the value of an iVAR with the logged in user's time zone.
In real time, this API works fine. If the logged in User's time zone is EST, I get the value in EST (after formatting).

However, in the test class, I create a user with a Time zone of PST. Then I use the runAs api to execute code as the new user that I just created. However, the result is as per the logged in user's time zone (EST).

Any pointers would be greatly appreciated.

UPDATE:

Test Code

1. API to create a standard test user, refactored as this is used in multiple places.

public static User getTestUser(String profileName){

    Profile pro = getTestUserProfile(profileName); 

    UserRole role = getUserRole(profileName.equals(System.Label.OperationUserProfile)
                  ? Constants_TVNA.OPS_ROLENAME : Constants_TVNA.SALES_ROLENAME);
    Long randomNumber = Math.mod (Math.mod (System.currentTimeMillis(), 1000000) , 989898989);

    User myUser = new User(alias = 'ABS', 
                 email='TestUser@salesforce.com', 
                   emailencodingkey='UTF-8', 
                   firstname='AB', 
                   lastname='S', 
                   languagelocalekey='en_US', 
                   localesidkey='en_US', 
                   profileId = pro.Id, 
                   userRoleId = role.Id,
                   timezonesidkey='America/Los_Angeles', 
                   username='unittestuser'+randomNumber+'@testorg.com',
                   RestrictRegion_TVNA__c = false, 
                   isActive = true;
    insert   myUser; 
    return myUser;
}

2. Code that is being tested:

public with sharing class ClassBeingTested {
    public String timeZoneShortString;

    public ClassBeingTested() {
        Time_Zone_Abbreviation_TVNA__mdt abbreviation = [Select DeveloperName from Time_Zone_Abbreviation_TVNA__mdt WHERE label = :(UserInfo.getTimeZone().getDisplayName())];
        timeZoneShortString = abbreviation.DeveloperName ;
    }

    public String getTimeZoneShortString() {
        return timeZoneShortString;
    }
}  

3. Testing Code:
@isTest
public class ClassBeingTested_Test {

static testMethod void orderPDFControllerTest()
{
    System.RunAs(TestDataFactory_TVNA.getTestUser(System.Label.SalesUserProfile)){
         ClassBeingTested cls = new ClassBeingTested();
         System.assertEquals('PST', cls.timeZoneShortString);
        }
}

The logged in user's time zone is EST. When the test case executes, the assert fails.
Although when I make the logged in user's time zone as PST, the assert succeeds.

Best Answer

System's runAs method lacks the documentation on timezone behavior. When you are using this method, the values are automatically changed to the user's timezone when the code is executed.

Outside the method's context the timezone correction only occurs for the running user. This can be demonstrated in this code:

// Considering that 'neutral_user' has 'GMT' as its 'TimeZoneSidKey' field,
// and that the other two users run with 'America/Puerto_Rico' and 
// 'America/Sao_Paulo'.
Datetime christmas2018utc;

System.runAs(neutral_user) {
    // Creates a datetime instance on December 25th, at 12:00 (GMT).
    // Using the 'runAs' method because if we don't, then the date instance will be
    // on the same timezone as the test running user.
    christmas2018utc = Datetime.newInstance(Date.newInstance(2018, 12, 25), Time.newInstance(12, 0, 0, 0));    
}

TimeZone mtz = Timezone.getTimeZone('America/Puerto_Rico'); // UTC-4
TimeZone btz = Timezone.getTimeZone('America/Sao_Paulo'); // UTC-3 (UTC-2 if on DST)
Datetime now = Datetime.now();

Integer m_diff = (mtz.getOffset(now) / 3600000);
Integer b_diff = (btz.getOffset(now) / 3600000);

System.runAs(manaus_user) {
    // In Manaus (Brazil) the timezone is UTC-4, so the hour value will be 8.
    System.debug('For the Manaus user, the time is ' + (12 + m_diff));
    System.assertEquals(12 + m_diff, christmas2018utc.hour());
}

System.runAs(minas_user) {
    // In Belo Horizonte (Brazil) the timezone is UTC-2 (DST), so the hour value will be 10.
    // If it is not on DST, then it will be UTC-3, and the hour value would be 9.
    System.debug('For the Belo Horizonte user, the time is ' + (12 + b_diff));
    System.assertEquals(12 + b_diff, christmas2018utc.hour());
}

If you want to assert the timezone value, do it inside the runAs context.

Related Topic