function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Rahul Gupta 162Rahul Gupta 162 

How do I get the last modified date of a particular field of a object in salesforce

Best Answer chosen by Rahul Gupta 162
NagendraNagendra (Salesforce Developers) 
Hi Rahul,

There are two methods for the above requirement.

Enable field history tracking for the field (or fields) that you wish to track
Create a new custom (DateTime) field, and create a workflow rule that updates this new DateTime field every time your target field is modified

Method 1 is the easiest to set up, and scales up to 20 fields (this is a limit imposed by Salesforce). It takes a little more work to pull the information for use in an Apex class, and has another important limitation that I'll get to later.

Method 2 is the easiest to use in an Apex class but takes longer to set up and doesn't scale well at all (you need a new custom field, a new workflow rule, and a new field update for each field you want to track in this manner). I wouldn't recommend this to anyone unless you only need to track one field. Even then, this method incurs more technical debt than I'm comfortable with.

How to use tracked field history

Making use of field history tracking information in an Apex class requires a query. For standard objects (Account, Case, Contact, etc...), the object you'll be querying is simply <sObjectName>History(AccountHistory, CaseHistory, ContactHistory, etc...) For custom objects, you'll be querying the respective __History object (the history object for My_Custom_Object__c is My_Custom_Object__History). You just replace __c with __History

The history tracking object always comes with the same 8 fields, CreatedById, CreatedDate, Field, Id, isDeleted, NewValue, OldValue. The 8th field is a lookup to the object that history is being tacked on. For Custom Objects, this appears to always be ParentId. For Standard Objects, this is <sObjectName>Id (AccountId, CaseId, ContactId, etc...)

Assuming you're working in a Trigger, or otherwise have access to Trigger Context Variables, your query would end up looking like this

[SELECT ParentId, Field, CreatedById FROM My_Custom_Object__History WHERE ParentId IN :trigger.newMap.keySet()]

Now, the problem with making business logic depend on tracked field history is that it is currently impossible to insert data into the history object in a unit test. You can't insert directly into history objects, and field history is not tracked in unit tests (even if the field is set up for history tracking).

You could manage to test the logic that depends on field history by wrapping your history query inside an if(test.isrunningtest()), and providing your own 'history' records in your test, but this limitation was a dealbreaker for me.

The other limitation is that you can't track field history on formula fields, auto number fields, or roll-up summary fields.

Another option

To get around the limitations of standard history tracking (if you need to track more than 20 fields, track a formula field, or want to reasonably test your code), you'd need to use a different method than the two listed above:

Create your own Custom History object, as well as an interface to use it
This option is more work up front but gives you the most freedom. I've done this in my org so that the interface to my custom History__c object is sObject agnostic, and only requires a single line of code to use in my Update triggers.

Adding or removing fields from my Custom History tracking is a matter of updating a fieldset (which can be done without a deployment).

Adding a new sObject to my Custom History tracking requires a new lookup field on my custom History__c object as well as a new fieldset on the newly tracked object.

Mark this as best answer by closing this thread so that it gets removed from the unanswered queue and will be available as proper solution for others.

Regards,
Nagendra.

All Answers

NagendraNagendra (Salesforce Developers) 
Hi Rahul,

There are two methods for the above requirement.

Enable field history tracking for the field (or fields) that you wish to track
Create a new custom (DateTime) field, and create a workflow rule that updates this new DateTime field every time your target field is modified

Method 1 is the easiest to set up, and scales up to 20 fields (this is a limit imposed by Salesforce). It takes a little more work to pull the information for use in an Apex class, and has another important limitation that I'll get to later.

Method 2 is the easiest to use in an Apex class but takes longer to set up and doesn't scale well at all (you need a new custom field, a new workflow rule, and a new field update for each field you want to track in this manner). I wouldn't recommend this to anyone unless you only need to track one field. Even then, this method incurs more technical debt than I'm comfortable with.

How to use tracked field history

Making use of field history tracking information in an Apex class requires a query. For standard objects (Account, Case, Contact, etc...), the object you'll be querying is simply <sObjectName>History(AccountHistory, CaseHistory, ContactHistory, etc...) For custom objects, you'll be querying the respective __History object (the history object for My_Custom_Object__c is My_Custom_Object__History). You just replace __c with __History

The history tracking object always comes with the same 8 fields, CreatedById, CreatedDate, Field, Id, isDeleted, NewValue, OldValue. The 8th field is a lookup to the object that history is being tacked on. For Custom Objects, this appears to always be ParentId. For Standard Objects, this is <sObjectName>Id (AccountId, CaseId, ContactId, etc...)

Assuming you're working in a Trigger, or otherwise have access to Trigger Context Variables, your query would end up looking like this

[SELECT ParentId, Field, CreatedById FROM My_Custom_Object__History WHERE ParentId IN :trigger.newMap.keySet()]

Now, the problem with making business logic depend on tracked field history is that it is currently impossible to insert data into the history object in a unit test. You can't insert directly into history objects, and field history is not tracked in unit tests (even if the field is set up for history tracking).

You could manage to test the logic that depends on field history by wrapping your history query inside an if(test.isrunningtest()), and providing your own 'history' records in your test, but this limitation was a dealbreaker for me.

The other limitation is that you can't track field history on formula fields, auto number fields, or roll-up summary fields.

Another option

To get around the limitations of standard history tracking (if you need to track more than 20 fields, track a formula field, or want to reasonably test your code), you'd need to use a different method than the two listed above:

Create your own Custom History object, as well as an interface to use it
This option is more work up front but gives you the most freedom. I've done this in my org so that the interface to my custom History__c object is sObject agnostic, and only requires a single line of code to use in my Update triggers.

Adding or removing fields from my Custom History tracking is a matter of updating a fieldset (which can be done without a deployment).

Adding a new sObject to my Custom History tracking requires a new lookup field on my custom History__c object as well as a new fieldset on the newly tracked object.

Mark this as best answer by closing this thread so that it gets removed from the unanswered queue and will be available as proper solution for others.

Regards,
Nagendra.
This was selected as the best answer
Rahul Gupta 162Rahul Gupta 162
Thank you Nagendra It will really help me.
NagendraNagendra (Salesforce Developers) 
Hi Rahul,

Please mark this as best answer if it helps.

Regards,
Nagendra.
EGA FuturaEGA Futura
Thanks Nagendra!
harshita gupta 10harshita gupta 10
@Nagendra I have the same issue, I'm interested in the first approach you mentioned. I want to fetch the date n time from Account history for a particular field, can I do that using process builder? I tried but I cannot find how to look for the fields of account history as history isn't a sole object.
please suggest