When using Microsoft Dynamics CRM workflow designer tool, you will be limited to a maximum of 31 days (as shown below) if you ever need an offset date based on another CRM date. The same limitation also apply to months, the maximum offset of months is 36 months.
In order to overcome the limit, I have come up two custom workflow activity classes which let you create any offset date, using
the workflow base class that I just created.
1. InvariantOffsetDays
using System;
using System.Globalization;
using System.Workflow.ComponentModel;
using Microsoft.Crm.Workflow;
using Microsoft.Crm.Sdk;
namespace CrmSpikes.Workflow
{
///
/// Calculate a series of dates using a base date with a set of predefined offset numbers.
/// @author Daniel Cai, http://danielcai.blogspot.com/
///
[CrmWorkflowActivity("Invariant Offset Days", "Custom Workflow")]
public class InvariantOffsetDays : SingleActivityBase
{
private DateTime _baseDate;
#region Workflow Parameters
public static DependencyProperty BaseDateProperty =
DependencyProperty.Register("BaseDate", typeof(CrmDateTime), typeof(InvariantOffsetDays));
[CrmInput("Base Date")]
public CrmDateTime BaseDate
{
get
{
return (CrmDateTime)GetValue(BaseDateProperty);
}
set
{
SetValue(BaseDateProperty, value);
}
}
public static DependencyProperty Offset7DaysProperty =
DependencyProperty.Register("Offset7Days", typeof(CrmDateTime), typeof(InvariantOffsetDays));
[CrmOutput("7 Days after the base date")]
public CrmDateTime Offset7Days
{
get
{
return (CrmDateTime)GetValue(Offset7DaysProperty);
}
set
{
SetValue(Offset7DaysProperty, value);
}
}
public static DependencyProperty Offset14DaysProperty =
DependencyProperty.Register("Offset14Days", typeof(CrmDateTime), typeof(InvariantOffsetDays));
[CrmOutput("14 Days after the base date")]
public CrmDateTime Offset14Days
{
get
{
return (CrmDateTime)GetValue(Offset14DaysProperty);
}
set
{
SetValue(Offset14DaysProperty, value);
}
}
public static DependencyProperty Offset21DaysProperty =
DependencyProperty.Register("Offset21Days", typeof(CrmDateTime), typeof(InvariantOffsetDays));
[CrmOutput("21 Days after the base date")]
public CrmDateTime Offset21Days
{
get
{
return (CrmDateTime)GetValue(Offset21DaysProperty);
}
set
{
SetValue(Offset21DaysProperty, value);
}
}
public static DependencyProperty Offset28DaysProperty =
DependencyProperty.Register("Offset28Days", typeof(CrmDateTime), typeof(InvariantOffsetDays));
[CrmOutput("28 Days after the base date")]
public CrmDateTime Offset28Days
{
get
{
return (CrmDateTime)GetValue(Offset28DaysProperty);
}
set
{
SetValue(Offset28DaysProperty, value);
}
}
public static DependencyProperty Offset35DaysProperty =
DependencyProperty.Register("Offset35Days", typeof(CrmDateTime), typeof(InvariantOffsetDays));
[CrmOutput("35 Days after the base date")]
public CrmDateTime Offset35Days
{
get
{
return (CrmDateTime)GetValue(Offset35DaysProperty);
}
set
{
SetValue(Offset35DaysProperty, value);
}
}
public static DependencyProperty Offset42DaysProperty =
DependencyProperty.Register("Offset42Days", typeof(CrmDateTime), typeof(InvariantOffsetDays));
[CrmOutput("42 Days after the base date")]
public CrmDateTime Offset42Days
{
get
{
return (CrmDateTime)GetValue(Offset42DaysProperty);
}
set
{
SetValue(Offset42DaysProperty, value);
}
}
public static DependencyProperty Offset49DaysProperty =
DependencyProperty.Register("Offset49Days", typeof(CrmDateTime), typeof(InvariantOffsetDays));
[CrmOutput("49 Days after the base date")]
public CrmDateTime Offset49Days
{
get
{
return (CrmDateTime)GetValue(Offset49DaysProperty);
}
set
{
SetValue(Offset49DaysProperty, value);
}
}
public static DependencyProperty Offset56DaysProperty =
DependencyProperty.Register("Offset56Days", typeof(CrmDateTime), typeof(InvariantOffsetDays));
[CrmOutput("56 Days after the base date")]
public CrmDateTime Offset56Days
{
get
{
return (CrmDateTime)GetValue(Offset56DaysProperty);
}
set
{
SetValue(Offset56DaysProperty, value);
}
}
#endregion
#region SequenceActivity
protected override void ExecuteBody()
{
_baseDate = BaseDate.UniversalTime;
Offset7Days = CalculateOffsetDate(7);
Offset14Days = CalculateOffsetDate(14);
Offset21Days = CalculateOffsetDate(21);
Offset28Days = CalculateOffsetDate(28);
Offset35Days = CalculateOffsetDate(35);
Offset42Days = CalculateOffsetDate(42);
Offset49Days = CalculateOffsetDate(49);
Offset56Days = CalculateOffsetDate(56);
}
private CrmDateTime CalculateOffsetDate(int offset)
{
DateTime resultDate = _baseDate.AddDays(offset);
return CrmDateTime.FromUniversal(resultDate);
}
#endregion
}
}After you have registered the workflow assembly, and added the custom workflow activity to your workflow by providing a base date, you can then access the generated offset dates as shown below:
InvariantOffsetDays class uses a set of predefined offset numbers to generate a series of offset dates based on the provided base CRM date. The offset is hard-coded in the class due to the way how workflow activity works. You may change it to any intervals or any combination of offset numbers.
2. VariantOffsetDays class
using System;
using System.Globalization;
using System.Workflow.ComponentModel;
using Microsoft.Crm.Workflow;
using Microsoft.Crm.Sdk;
namespace CrmSpikes.Workflow
{
/// <summary>
/// Calculate a new date using a base date and an offset number (positive or negative).
/// @author Daniel Cai, http://danielcai.blogspot.com/
/// </summary>
[CrmWorkflowActivity("Variant Offset Days", "Custom Workflow")]
public class VariantOffsetDays : SingleActivityBase
{
#region Workflow Parameters
public static DependencyProperty BaseDateProperty =
DependencyProperty.Register("BaseDate", typeof(CrmDateTime), typeof(VariantOffsetDays));
[CrmInput("Base Date")]
public CrmDateTime BaseDate
{
get
{
return (CrmDateTime)GetValue(BaseDateProperty);
}
set
{
SetValue(BaseDateProperty, value);
}
}
public static DependencyProperty OffsetProperty =
DependencyProperty.Register("Offset", typeof(CrmNumber), typeof(VariantOffsetDays));
[CrmInput("Offset (Positive or Negative)")]
public CrmNumber Offset
{
get
{
return (CrmNumber)GetValue(OffsetProperty);
}
set
{
SetValue(OffsetProperty, value);
}
}
public static DependencyProperty ResultDateProperty =
DependencyProperty.Register("ResultDate", typeof(CrmDateTime), typeof(VariantOffsetDays));
[CrmOutput("Result Date")]
public CrmDateTime ResultDate
{
get
{
return (CrmDateTime)GetValue(ResultDateProperty);
}
set
{
SetValue(ResultDateProperty, value);
}
}
#endregion
#region SequenceActivity
protected override void ExecuteBody()
{
DateTime baseDate = BaseDate.UniversalTime;
DateTime resultDate = baseDate.AddDays(Offset.Value);
ResultDate = CrmDateTime.FromUniversal(resultDate);
}
#endregion
}
}VariantOffsetDays class accepts two parameters, which are the base date, and the offset days (int, either positive or negative), as shown below. It’s a more flexible solution than InvariantOffsetDays, the trade-off is it can only generate one offset date at one time.
Both classes can be used to create any type of offset, including month-based offset or year-based offset, which is your call.
The reason that I wrote this blog post was that two persons asked similar questions within a month on
CRM Development Forum and
CRM Forum about how to specify an offset date for a CRM workflow that cannot be done using the native CRM workflow design tool. There doesn't seem to be any available solution on Internet to address this issue, so I decided to write the custom workflow along with
the workflow base class.
Note: Please make sure to include the workflow base class that I created in order to compile the code.
Download the source code and compiled assembly below.
Hope this helps if you ever need to do the same thing.