1

Paypal is sending dates to my Rest service in this format 09:30:12 Jan 02, 2022 PST If I use the DateTime.valueOf() function to translate the value to a DateTime field, it fails with an invalid date/time format error.

Is there any built-in functionality in Apex that will help me convert this format to a DateTime field? I am going through the documentation but haven't found anything yet.

The values being sent by Paypal IPN are being sent in the request.params

An example of the params being sent by the IPN.I have captured these in the user debug logs.

USER_DEBUG|[24]|DEBUG|business ==> sb-147na4709042@business.example.com
USER_DEBUG|[24]|DEBUG|payment_status ==> Completed
USER_DEBUG|[24]|DEBUG|mc_currency ==> USD
USER_DEBUG|[24]|DEBUG|shipping_discount ==> 0.00
USER_DEBUG|[24]|DEBUG|txn_type ==> web_accept
USER_DEBUG|[24]|DEBUG|mc_gross ==> 466.78
USER_DEBUG|[24]|DEBUG|ipn_track_id ==> 11eacc648df9b
USER_DEBUG|[24]|DEBUG|payment_date ==> 09:30:12 Jan 02, 2022 PST
7
  • Please can you provide an example of rhe JSON that includes an actual date/time value? The format you show is what would be rendered by JavaScript or that appears in an HTTP timestamp rather than the format that should be sent in JSON. Just edit the question to add this detail please.
    – Phil W
    Jan 2, 2022 at 19:47
  • 1
    @PhilW The values are not being sent in a JSON format. They are being sent in the Request.Params
    – abhi
    Jan 2, 2022 at 20:11
  • Also this
    – abhi
    Jan 2, 2022 at 20:16
  • Can you request to receive in JSON?
    – Phil W
    Jan 2, 2022 at 20:51
  • @PhilW It's PayPal...
    – sfdcfox
    Jan 2, 2022 at 21:10

2 Answers 2

2

There's nothing you can do. Manual parsing is required. This isn't as bad as it sounds though, as you can:

public static DateTime parsePaypalIpnDate(String theDate) {
    String[] months = new String[] { '', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' };
    Pattern ipnDatePattern = Pattern.compile('(\\d+):(\\d+):(\\d+) (\\w+) (\\d+), (\\d+) (\\w+)');
    Matcher dateMatcher = ipnDatePattern.matcher(theDate);
    dateMatcher.find();
    Integer hour = Integer.valueOf(dateMatcher.group(1));
    Integer minute = Integer.valueOf(dateMatcher.group(2));
    Integer second = Integer.valueOf(dateMatcher.group(3));
    Integer month = months.indexOf(dateMatcher.group(4));
    Integer day = Integer.valueOf(dateMatcher.group(5));
    Integer year = Integer.valueOf(dateMatcher.group(6));
    String timeZoneName = dateMatcher.group(7);
    TimeZone paypalTimeZone = TimeZone.getTimeZone(timeZoneName);
    DateTime timeAsGmt = DateTime.newInstanceGMT(year, month, day, hour, minute, second);
    Integer timeZoneOffset = paypalTimeZone.getOffSet(timeAsGMT);
    DateTime timeAsIntended = timeAsGmt.addSeconds(timeZoneOffset/1000);
    return timeAsIntended;
}

Note that this might be an hour off when it's within 24 hours of DST changes, when applicable, as I'm not sure there's a valid indicator for DST changes.

3
  • Thanks for responding @sfdcfox I was kinda hoping to avoid this.
    – abhi
    Jan 2, 2022 at 21:34
  • @abhi The other method I came up with would involve a split/join technique; any way you look at it, you're doing it manually, Salesforce only really supports ISO 8601-style date formats and local specific formats. This format is neither of those.
    – sfdcfox
    Jan 2, 2022 at 21:37
  • Yes, Paypal kinda decided to go their own way. One thing I observed is that other libraries like PHP and C# have taken a different approach. You specify a format and the library will convert the string to date using that format. Perhaps Apex needs to have this feature.
    – abhi
    Jan 2, 2022 at 21:42
0

I actually started coding along similar lines.

String[] monthList = ',Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(',');
string wannabeDate = '09:30:12 Jan 02, 2022 PST';
string timePart = wannabeDate.substring(0,8);
System.Debug(timePart);
string datePart = wannabeDate.substring(9,(9+12));
System.Debug(datePart);
string timeZone = wannabeDate.right(3);
System.Debug(timeZone);
System.Debug(datePart.substring(0,3));
integer month = monthList.indexOf(datePart.substring(0,3));
System.Debug('Month ==> ' + month);
string day = datePart.substring(4,6);
System.Debug('Month ==> ' + day);
string year =datepart.right(4);
System.Debug('Year ==> '+ year);
string formNewDate = year+'-'+ string.valueOf(month).leftPad(2,'0') +'-'+day+' '+timePart;
System.Debug(formNewDate);
DateTime dd = Datetime.valueOf(formNewDate);
System.Debug(dd);
String ddwithTz = dd.format(formnewDate,timeZone);
System.Debug(ddwithTz);

I was kind of hoping to avoid this.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.