Parsing dates and times in Flex / AS3

28 05 2009

I’m in the process of writing my fourth employee time tracking and scheduling system.  And while the business logic of this app is more complicated than ever before, coding the client side has never been so easy. Because this time I am coding the client in Flex.

I am an absolute convert to Adobe Flex. I never again want to code a user interface only to find out that this Javascript or that CSS is totally broken on a particular browser/platform (typically IE).  I’m convinced that if you are going to write a GUI application, there is no better tool anywhere than Adobe Flex/Air.

And yet even on Flex, working with date/time is problematic. Flex gives us a nice DateField control, has a nice DateFormatter class and does a reasonable job parsing dates. But if you want to work with time instead of dates, you are on your own. Well you used to be.  Here’s how to make it easy.

What we really need is an  custom input control made to read and write time. In this series, we are going to make two controls, TimeInput and DecimalTimeInput. But before we can create the controls, we’ll need to make some utilities to aid in parsing and formatting time.

We are going to follow Adobe’s lead and create a utility class packed full of static functions and constants to make our lives easier. After all, the best programmers are what I like to call “constructively lazy.” I’ll call my class DateUtils.

One shortcoming of the Adobe delivered functionality is that it can not parse ISO encoded date/times. So we’ll fix that by removing the parts that it chokes on.

public static function parseDate(value:String):Date
{
    var dateStr:String = value;
    dateStr = dateStr.replace(/-/g, "/");
    dateStr = dateStr.replace("T", " ");
    dateStr = dateStr.replace("Z", " GMT-0000");
    return new Date(Date.parse(dateStr));
}

It would also be great to be able to format date/time’s without instantiating DateFormatters everywhere so we’ll create a static format function. (_df is a DateFormatter)

public static function format(value:Object, format:String = null):String
{
	var ret:String = '';
	if(value == null) {
		return ret;
	}
	_df.formatString = (format == null) ? format : DateUtils.FMT_ISO_DATE_TIME;
	ret = _df.format(value);
	if(ret.length == 0) {
		ret = _df.format(parseDate(value.toString()));
	}
	return ret;
}

The last major part of our DateUtils class is to parse time using regular expressions. I want it to be pretty forgiving about what it can interpret. So ‘5’, ‘5P’, ‘5:00’, ‘5:00 PM’, ‘5:00:00 PM’, ’17’, ’17:00′, ’17:00:00′ and ‘1700’ would all be valid inputs.

public static function parseTime(value:String, guessAMPM:Boolean = true):Date
{
	value = value.toUpperCase();
	var dt:Date = new Date(2000,0,1);
	var time:Object;
	var isMil:Boolean = false;
	//standard time regex
	var matches:Array;
	var reg:RegExp = /^(1[012]|[1-9])(:[0-5]\d)?(:[0-5]\d)?(\ ?[AaPp][Mm]?)?$/;
	matches = reg.exec(value);
	if(!matches) {
		//military time regex
		reg = /^(2[0-4]|1\d|0?\d)(:?[0-5]\d)?(:?[0-5]\d)?$/;
		isMil = true;
		matches = reg.exec(value);
	}
	if(!matches) {
		//could not parse
		return null;
	}
	time = {
		hours: Number(matches[1]),
		minutes: matches[2] ? Number(String(matches[2]).replace(':','')) : 0,
		seconds: matches[3] ? Number(String(matches[3]).replace(':','')) : 0,
		ampm: null
	};
	if(isMil) {
		//processing military format
		dt.setHours(time.hours, time.minutes, time.seconds);
	} else {
		//processing common format
		if(matches[4]) {
			//user indicated AM/PM
			if(String(matches[4]).indexOf('P') != -1) {
				//PM
				time.hours = time.hours == 12 ? 12 : time.hours + 12;
			} else if (time.hours == 12){
				time.hours = 0;
			}
		} else if (guessAMPM) {
			//will guess PM if <= 6
			time.hours = time.hours <= 6 ? time.hours + 12 : time.hours;
		}
	}
	dt.setHours(time.hours, time.minutes, time.seconds);
	return dt;
}

We’ll round our class with a few other functions to get the total number of hours, minutes or seconds in a time; get the day of year and define some date and time formats.

*UPDATE*

I added another article on implementing the TimeInput control.  The sample application for that has the complete source for the DateUtils class as well as the TimeInput control.

Advertisements

Actions

Information

6 responses

30 05 2009
Steven C. Buttgereit

First, let me say thanks for posting this. I’ve had ‘casual’ encounters with Flex in the past, but am doing more with it now. I recalled date parsing (especially ISO) being a bit of a pain… but had to learn all those lessons over! Your posting helped speed that process up (and validate my memory).

I think the code in your word doc has a problem though. in the “format” function and the “toSeconds” function you make reference to a “parseIso” function. I’m guessing that’s suppose to be the parseDate function?

30 05 2009
Steven C. Buttgereit

Just saw it… In your blog posting you do call parseDate instead of parseIso in the format function; the word doc version missed some refactoring.

30 05 2009
Scott Bailey

Thanks Steven good catch. I’ve updated the file.

19 06 2009
Adobe Flex TimeInput Control « Flex and Specs()

[…] Flex TimeInput Control June 19, 2009 Posted by Scott Bailey in Flex. trackback So in a previous article I explained why working with time is difficult in Flex (but you probably already know that if you […]

27 01 2010
David Wolever

Awesome – thanks a lot. This is exactly what I was looking for.

15 03 2010
Jack

Hi. Thanx for this – it’s great. Just wanted to know…is there an easy way to add/subtract times using this component…say i wanted to figure out what the time will be in 8 hours from 21:45…cheers!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s




%d bloggers like this: