How do I write code with the correct syntax to run a pattern grouping match within a string, then replace the pattern groups found in the result so that they follow a desired pattern? I've never done this before so could use some assistance with the proper code usage in APEX. The documentation just doesn't seem to be doing it for me. The scenario I'm working with follows below.

I'm working on a trigger that creates an event from an opportunity after update. One of the opportunity fields is a 10 digit text string that contains the time the event occurs as entered by the owner of opportunity. There are no validation rules on the text string field, so it can be formatted as 7pm, 7:00PM, 7:00 PM, etc. I need to do a pattern match and replace the results so it's in the proper DateTime format to allow me to append it to the end of the Event Date (opp.CloseDate) in an acceptable DateTime format as required in the StartDateTime Event Field when I create the new Event.

Having looked at pattern matching sites, it appeared that I'd want to use something like: ((^[0-9])|(^[0-1][0-9]))(\x3A?)([05][09]{2}?)([AP][M])$& for the pattern. But, when I started attempting to use the pattern compile function, it didn't like the brackets and only wanted parenthesis!

It also didn't like backslashes in certain places and seemed to want to only do one grouping at a time. That told me I might want to change things to look something more like:

([0-9])|([10-12]) for the first grouping (not certain if it will take the double digits as shown or if I'd need to do something like: ([1][0-2]) for the 2nd part of the boolean. I'm also guessing the ([0-9]) needs a look-ahead to check to make certain there's no [0-2] that follows it?

Then there'd be the optional (\x3A?) for the second group to represent the colon which may or may not be there. Am guessing there's a unicode (ISO8601) equivalent to the ASCII x3A?

Next group would be a ([0-5]) for minutesx10 followed by a ([0-9]) for single digit minutes, both of which may or may not be in the string.

Finally it seems I need to get the AM & PM using ([AP]|[ap]) along with ([Mm]) as the last two groups. It seems I could first use a string operation though to set everything to either upper or lower case to avoid the "OR" operation.

Assuming I have the correct Regular Expressions (any confirmation of what I've come up with or suggested improvements would be appreciated), what's the proper syntax to get the groupings from the string variable? Once I have them, what's the syntax to then place them in an 'hh:mm aaa' format so I can later append them to a date that's been formatted as an 'MM/dd/yyyy' string for DateTime parsing that would look like: 'MM/dd/yyyy h:mm aaa'? (I've discovered the "aaa" prevents a colon from appearing after AM or PM for seconds).

Thank you for any assistance on how to set up the pattern matching/replacement. Were this entirely up to me, I'd simply require the users to input the time in a standardized method and probably give them a drop-down box with 15 min increments. But instead, looks like I get to do this for them.

  • 3
    No matter what you come up with, some user will find a way to enter it so your matcher doesn't work. I'm sure you have good reason to do it this way, but without some kind of validation, this is going to be difficult and imperfect. Commented Jan 30, 2013 at 21:48
  • @JeremyNottingham. You were correct that this was difficult to implement. I did come up with a solution posted below. Ultimately, even after initially implementing a workflow rule, the architect recognized that a picklist was the simplest and most reliable way to go to solve this issue.
    – crmprogdev
    Commented Apr 5, 2013 at 14:26

1 Answer 1


Ultimately, the code I came up with for validation looked something like what's below:

list<Event> ToInsert = new list<Event>();
Date ClosDt;
Integer ClsDay; 
Integer ClsMnth;
Integer ClsYear; 
String sClsDay; 
String sClsMnth;
String sClsYear; 
String StrtTmDt;
Integer plnMns;
String endTm;
String endDtTm;
String notes;
Pattern TimePttrn = Pattern.compile('((([1])([0-2])|(([0])([1-9])))(\\u003A)(([0-5])([0-9]))(\\s)(([AP])([M])))'); // hh:mm a

// The initial section below is to use Event_Notes__c to track any error messages 
// related to the start time and return them for correction while allowing 
// successful creation of the event. It existed before we went to a picklist.

    If (opp.Event_Notes__c == null) notes = 'None';

    }catch(NullPointerException e){

    notes = 'None';


    notes = opp.Event_Notes__c;


    }catch(NullPointerException e){

        if (notes == 'None') {

            notes = 'Error A1 processing Start Time!!! Check for correct time and resubmit form.';

            opp.Event_Start_Time_Pik__c = '12:00 AM';

        } else{

            notes = 'Error A2 processing Start Time!!! Check for correct time and resubmit form.'+ notes;

            opp.Event_Start_Time_Pik__c = '12:00 AM'; 


    } // End try/catch block

// Do time pattern and match validation

Matcher m = TimePttrn.matcher(opp.Event_Start_Time_Pik__c);
boolean hasMatch = m.matches();
strtTm = m.group(0);

opp.Event_Notes__c = notes;

// Assemble StartTimeDate and Calculate Planned Mins

ClosDt = opp.CloseDate;
ClsDay = ClosDt.day();

if(ClsDay >= 1 && ClsDay <= 9){ 

sClsDay = '0' + String.ValueOf(ClsDay);

} else {

sClsDay = String.ValueOf(ClsDay);


ClsMnth = ClosDt.month();

if(ClsMnth >=0 && ClsMnth <= 9){ 

   sClsMnth = '0' + String.ValueOf(ClsMnth);

   } else {

   sClsMnth = String.ValueOf(ClsMnth);


ClsYear = ClosDt.year();

sClsYear = String.ValueOf(ClsYear);    

StrtTmDt = sClsMnth + '/' + sClsDay + '/' + sClsYear + ' ' + strtTm;

Later in the code when creating the event:

Event e = New Event(StartDateTime = DateTime.parse(StrtTmDt), ActivityDateTime = DateTime.parse(StrtTmDt), EndDateTime = (DateTime.parse(StrtTmDt)).addMinutes(plnMns), DurationInMinutes = plnMns, Subject = EvtSubjct, OwnerId = opp.Owner.Id, WhatId = opp.Id, WhoId = opp.Customer_Contact__r.Id, Description = Descr1 + Descr2 + Descr3 + Descr5 + Descr6 + Descr7 );

I wound up doing a lot of string method and regex testing bits of code in the Developer Console and creating some string test classes before I managed to get all of this to work satisfactorily. I learned a great deal in the process. I hope others find this of use as until there's a "true" Time method other than the Salesforce System Time, this will continue to be an issue we'll all need to deal with on occasion.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .