Friday 14 September 2012

Human readable cron expressions using JavaScript

So I was faced with the task of presenting cron expression (like '3 * * * *') on a web page in human readable format. I figured there would be plenty of scripts available to do just that, ready for use.
With the limitations to using JavaScript, I found nothing! Either it is hidden away somewhere or no one have published a script to convert cron expression in to human readable format.

After a little soul searching I decided to write my own implementation.
The final result looks like this:
Cron expression: 15 3,8,10,12,14,16,18 16 * *
Human readable: Every 15th minute past the 3, 8, 10, 12, 14, 16 and 18th hour on the 16th every month
Next run: Sunday at 3:15 AM

Cron expression: 30 * * * *
Human readable: Every 30th minute past every hour
Next run: Today at 1:30 AM

Cron expression: 0 * * * *
Human readable: Every hour, on the hour
Next run: Today at 2:00 AM

Cron expression: * 8,10,12,14,16,18,20 * * *
Human readable: Every minute of 8, 10, 12, 14, 16, 18 and 20th hour
Next run: Today at 8:00 AM

Cron expression: 2 8,10,12,14,16,18 * 4 0,3
Human readable: Every 2nd minute past the 8, 10, 12, 14, 16 and 18th hour in Apr on Sun and Thu
Next run: 04/07/2013

Dependencies

First download the dependencies:
moment.min.js - Credit Moment.js
later.min.js - Credit bunkat
prettycron.js - Credit myself

How to use

Copy the dependencies above to the web server.
In the same directory, create a new basic HTML file called prettycron.html.
Include the dependencies in prettycron.html:
    <script src="later.min.js" type="text/javascript"></script>
    <script src="moment.min.js" type="text/javascript"></script>
    <script src="prettycron.js" type="text/javascript"></script>

Add this in the body of prettycron.html:
document.write(getPrettyCron(cronParser().parse('0 * * * *', false)));

Open the page in a web browser and you should see the following output:
Every minute

That is it, just replace '0 * * * *' with any basic cron expression to see it in human readable format.


Full example

Please find the full example below to produce the example from introduction:
<html>
  <head>
    <title>Human readable cron schedule</title>
    <script src="later.min.js" type="text/javascript"></script>
    <script src="moment.min.js" type="text/javascript"></script>
    <script src="prettycron.js" type="text/javascript"></script>
  </head>
<body>
<script type="text/javascript">
function printCron(cron) {
    var s1 = cronParser().parse(cron, false);
    document.write('<b>Cron expression: </b>' + cron + '<br/>');
    document.write('<b>Human readable: </b>' + getPrettyCron(s1['schedules'][0]) + '<br/>');
    document.write('<b>Next run: </b>' + moment(later(60,true).getNext(s1)).calendar() + '<br/><br/>');
}
printCron('15 3,8,10,12,14,16,18 16 * *');
printCron('30 * * * *');
printCron('0 * * * *');
printCron('* 8,10,12,14,16,18,20 * * * ');
printCron('2 8,10,12,14,16,18 * 4 0,3 ');
</script>
</body>


Internet Explorer pre-9

Only in Internet Explorer 9 support came for Array.indexOf. The scripts depends heavily on this method so to make it work in Internet Explorer 6-8, perform the following steps:
1. Create ielt9.js containing the code from "Compatibility" section of:
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/indexOf

2. Inside <head></head> add:
<!--[if lt IE 9]><script src="js/ltie9.js" type="text/javascript" charset="UTF-8"></script><![endif]-->

Sunday 9 September 2012

My first Android app

I just finished writing my first Android app Screensaver Photo Frame:
During this project I hit a few gotchas which I wanted to share. Below I listed the most critical things to remember while starting developing for Android.

1. Exceptions = Force close

Whenever the application throws an exception, it will cause Android to force close the application. So to avoid frustration for the users, catch any potential exception and handle them properly.

2. Database locking issues

As you might already noticed, multi-threading is critical for any Android application. The issue with multi-threading and built in database is however that you are destined to run into SQLiteDatabaseLockedException by following most getting started guides.
The trick is to use SQLiteOpenHelper as a singleton and let SQLite manage the synchronization.
In the cut-down example below, two threads can call addSomething() simultaneously and SQLite will handle the synchronization within itself preventing lock exception.
DBAdapter:
public class DBAdapter {
    private static SQLiteDatabase db = null;
    public static synchronized DBAdapter getInstance(Context ctx)
    {
        if (db == null ) {
            DatabaseHelper DBHelper = new DatabaseHelper(ctx);
            db = DBHelper.getWritableDatabase();
        }
        return new DBAdapter();
    }
    public void addSomething(String something) {
        ContentValues initialValues = new ContentValues();
        initialValues.put(KEY_SOMETHING, something);
        db.insertWithOnConflict(DATABASE_SOMETHING_TABLE, null, initialValues,
                SQLiteDatabase.CONFLICT_REPLACE);
    }
    private static class DatabaseHelper extends SQLiteOpenHelper
    {
        ...
    }
}
Activity:
public class MainActivity extends Activity {
    private DBAdapter database;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        database = DBAdapter.getInstance(getApplicationContext());
        database.addSomething("something");
    }
}


3. Multi-row SQL execution

Since Android 4-ish it is not possible to run queries separated by semi-colon anymore.
So instead of executing SQL as:
db.execSQL("CREATE TABLE A ...; CREATE TABLE B ...;");
Split it up into multiple executions:
db.execSQL("CREATE TABLE A ...;");
db.execSQL("CREATE TABLE B ...;");