Locale Aware DateTime Component

I am working with a client that is deploying some existing Visualforce pages to international Users. The Visualforce includes some Date and DateTime values so I checked them to make sure they would render appropriately for people accessing the logic internationally. It turns out that the original Visualforce code uses the <apex:outputText> tag to drive formatting for much of the Date/DateTime values within the pages. Therefore, I am converting the occurrences of each <apex:outputText> tag to the Visualforce component I built for rendering either Date or DateTime values based upon the User's individual locale settings.

My original DateTime formatting component works just fine but I wanted to improve it a bit. The enhancements support two goals I have for the code:

  1. The ability to handle new & future locale settings as they are made generally available by salesforce.com.
  2. Overall reduction in the total number of lines of code used for the logic.

The bulk of the improvements to the original code are being done in the Visualforce controller class.

/*
	Created by: Greg Hacic
	Last Update: 28 January 2016 by Greg Hacic
	Questions?: greg@interactiveties.com
	
	Notes:
		- controller for the localeFormattedDatetime Visualforce component
		- tests located at localeFormattedDatetimeTest.class
*/
public class localeFormattedDatetime {
	
	public Datetime datetimeValue {get;set;} //property that reads the DateTime value from the component attribute tag
	
	public String getFormattedDatetime() {
		String datetimeFormatted; //variable for the DateTime
		if( datetimeValue != null ) { //if the DateTime variable is not null
			datetimeFormatted = datetimeValue.format(); //the datetimeValue as a string using the locale of the User
		}
		return datetimeFormatted; //return the string
	}

}

If you compare the code above to the controller I wrote back in 2011 you will see that I am removing the original method that was used in formatting the DateTime value based upon a hardcoded string, which was stored in a rather long map declaration. By switching from that map to the use of the standard DateTime class' format() method, I am essentially making the logic future-proof. Meaning that the standard format() method will always convert the DateTime value to a string based upon the User's locale settings and, therefore, inherently convert any new locales that salesforce.com decides to support in the coming years.

The component itself remains relatively unchanged from what I originally wrote except I decided to use camelcase for my naming conventions now.

<apex:component access="global" controller="localeFormattedDatetime">
<!--
	Created by: Greg Hacic
	Last Update: 28 January 2016 by Greg Hacic
	Questions?: greg@interactiveties.com
	
	NOTES:
		- when adding to your Salesforce org set the name of component to localeFormattedDatetime
-->
<apex:attribute assignTo="{!datetimeValue}" description="The DateTime value to be rendered based upon the user's locale" name="datetimeProvided" type="Datetime"></apex:attribute>
{!formattedDatetime}
</apex:component>

The last part of this logic is the Apex unit tests. I am tweaking my original Apex test class to better support best practices that have evolved since the original logic was written. That new Apex test class is below.

/*
	Created by: Greg Hacic
	Last Update: 28 January 2016 by Greg Hacic
	Questions?: greg@interactiveties.com
	
	NOTES:
			- tests the localeFormattedDatetime class (100.00% coverage)
*/
@isTest
private class localeFormattedDatetimeTest {
	
	//English (United States)
	static testMethod void en_US() {
		//BEGIN: perform some setup steps...
		UserRole role = [SELECT Id, Name FROM UserRole LIMIT 1]; //grab a UserRole entry
		Profile p = [SELECT Id FROM Profile LIMIT 1]; //grab a profile for a new testing user
		//create a test user
		List<User> users = new List<User>();
		users.add(new User(Alias = 'test', Email = 'test@ities.co', EmailEncodingKey = 'ISO-8859-1', FirstName = 'Test', LanguageLocaleKey = 'en_US', LastName = 'User', LocaleSidKey='en_US', ProfileId = p.Id, TimeZoneSidKey = 'America/Denver', UserName = 'test@ities.co', UserRoleId = role.Id));
		insert users;
		//END: perform some setup steps...
		System.runAs(users[0]) { //run as the newly created User
			Test.startTest(); //denote testing context
			localeFormattedDatetime controller = new localeFormattedDatetime(); //construct the controller
			controller.datetimeValue = DateTime.valueOf('2007-01-01 2:35:21'); //set the DateTime variable to 1 January 2007
			System.assertEquals('1/1/2007 2:35 AM', controller.getFormattedDatetime()); //validate the results
			Test.stopTest(); //revert from testing context
		}
	}
	
	//Spanish (Paraguay)
	static testMethod void es_PY() {
		//BEGIN: perform some setup steps...
		UserRole role = [SELECT Id, Name FROM UserRole LIMIT 1]; //grab a UserRole entry
		Profile p = [SELECT Id FROM Profile LIMIT 1]; //grab a profile for a new testing user
		//create a test user
		List<User> users = new List<User>();
		users.add(new User(Alias = 'test', Email = 'test@ities.co', EmailEncodingKey = 'ISO-8859-1', FirstName = 'Test', LanguageLocaleKey = 'en_US', LastName = 'User', LocaleSidKey='es_PY', ProfileId = p.Id, TimeZoneSidKey = 'America/Denver', UserName = 'test@ities.co', UserRoleId = role.Id));
		insert users;
		//END: perform some setup steps...
		System.runAs(users[0]) { //run as the newly created User
			Test.startTest(); //denote testing context
			localeFormattedDatetime controller = new localeFormattedDatetime(); //construct the controller
			controller.datetimeValue = DateTime.valueOf('2005-03-07 5:02:21'); //set the DateTime variable to 7 March 2005
			System.assertEquals('07/03/2005 05:02 AM', controller.getFormattedDatetime()); //validate the results
			Test.stopTest(); //revert from testing context
		}
	}
	
	//French (Canada)
	static testMethod void fr_CA() {
		//BEGIN: perform some setup steps...
		UserRole role = [SELECT Id, Name FROM UserRole LIMIT 1]; //grab a UserRole entry
		Profile p = [SELECT Id FROM Profile LIMIT 1]; //grab a profile for a new testing user
		//create a test user
		List<User> users = new List<User>();
		users.add(new User(Alias = 'test', Email = 'test@ities.co', EmailEncodingKey = 'ISO-8859-1', FirstName = 'Test', LanguageLocaleKey = 'en_US', LastName = 'User', LocaleSidKey='fr_CA', ProfileId = p.Id, TimeZoneSidKey = 'America/Denver', UserName = 'test@ities.co', UserRoleId = role.Id));
		insert users;
		//END: perform some setup steps...
		System.runAs(users[0]) { //run as the newly created User
			Test.startTest(); //denote testing context
			localeFormattedDatetime controller = new localeFormattedDatetime(); //construct the controller
			controller.datetimeValue = DateTime.newInstance(2011, 1, 3, 12, 41, 15); //set the DateTime variable to 3 January 2011
			System.assertEquals('2011-01-03 12:41', controller.getFormattedDatetime()); //validate the results
			Test.stopTest(); //revert from testing context
		}
	}
	
	//Chinese (Taiwan)
	static testMethod void zh_TW() {
		//BEGIN: perform some setup steps...
		UserRole role = [SELECT Id, Name FROM UserRole LIMIT 1]; //grab a UserRole entry
		Profile p = [SELECT Id FROM Profile LIMIT 1]; //grab a profile for a new testing user
		//create a test user
		List<User> users = new List<User>();
		users.add(new User(Alias = 'test', Email = 'test@ities.co', EmailEncodingKey = 'ISO-8859-1', FirstName = 'Test', LanguageLocaleKey = 'en_US', LastName = 'User', LocaleSidKey='zh_TW', ProfileId = p.Id, TimeZoneSidKey = 'America/Denver', UserName = 'test@ities.co', UserRoleId = role.Id));
		insert users;
		//END: perform some setup steps...
		System.runAs(users[0]) { //run as the newly created User
			Test.startTest(); //denote testing context
			localeFormattedDatetime controller = new localeFormattedDatetime(); //construct the controller
			controller.datetimeValue = DateTime.newInstance(2011, 1, 3, 12, 41, 15); //set the DateTime variable to 3 January 2011
			System.assertEquals('2011/1/3 PM 12:41', controller.getFormattedDatetime()); //validate the results
			Test.stopTest(); //revert from testing context
		}
	}

}

Rendering the Visualforce component within a Visualforce page is unchanged.

<c:localeFormattedDatetime datetimeProvided="{!Account.CreatedDate}"></c:localeFormattedDatetime>

Automated Exchange Rates in Salesforce.com

Reduce Repetitive Tasks, Eliminate Errors & Free Up Your Administrators.

Birthday Reminders for Salesforce.com

It might lead to a sale. Or it might make you feel good.