This is realistically impossible. The reason why, of course, is Governor Limits. The way your code is written, if a governor limit hits you, you're dead in the water, indefinitely, until someone creates a new job to start over.
Your best bet would be to simply schedule four jobs that run hourly, 15 minutes apart from each other. While that does seem kind of greedy, it does offer some modicum of reliability, because you're guaranteed to pick up correctly on the next 15 minute window.
That said, if you want maximum reliability, this is one of those times where you probably want to catch Exception (but, make sure you report the errors somewhere!).
The approximate pseudocode for resilient scheduling would look like the following.
public void execute(SchedulableContext context) {
try {
executeBatchJob();
} catch(Exception e) {
reportException(e);
}
try {
rescheduleIn15Minutes(context);
} catch(Exception e) {
reportException(e);
}
}
Instead of creating a cron job string that only works for the next run, instead schedule it to run with wildcards, like this:
String cronString = '0 '+ nextRun.minute()+' * * * ?';
This means that, even with a governor limit halt, your code will be delayed for an hour instead of dying off never to come back again.
As a further concept, perhaps you could simply create a job that runs hourly, and leverages scheduleBatch instead:
public void execute(SchedulableContext context) {
try {
abcbatch batch = new abcbatch();
Database.executeBatch(batch);
System.scheduleBatch(batch, 'Now+15', 15);
System.scheduleBatch(batch, 'Now+30', 30);
System.scheduleBatch(batch, 'Now+45', 45);
} catch(Exception e) {
}
}
Which will allow you to at least kick off the jobs, and the scheduler will simply remain scheduled hourly using the cron string "0 0 * * * ?".
The only "schedule X from now" is for Batchable:
System.scheduleBatch(new BatchClassImpl(), 'Near Future', 5);
This would schedule a job five minutes from now to run the batch job.
For anything else, you would indeed want to build your own cron string, which shouldn't be more than a dozen lines of code in most cases; you could even write a utility method if this is a common design across multiple Schedulable classes.
You could also technically use a Flow with a Pause element then call some Apex, or use Process Builder, but that involves metadata configuration instead of "just" Apex.
Best Answer
The chron string you have works to run on the first of the month, every 3 months. The catch is, it starts on the first of the month, 3 months from when you schedule it. So if you ran that in January, it would start on April 1. I just tried to run it now, in February, and the first run is scheduled for May 1.
You can adjust the chron string to specify the exact months that represent your quarter starts, for example, if your quarters are jan 1 - March 31st, and so on, then you could use
This will run at 5:00am in the first of January, April, July, and October. It will schedule it correctly regardless of when you schedule it