diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 99c7d0f70f09138b9319eab4c2e2e8bb927606a1..d4fb0759644150f814b57ea814a7e763e3159af1 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -1,27 +1,107 @@
 #include <stdio.h>
 #include <string.h>
 #include <time.h>
+#include <ctype.h>
 #include "postgres.h"
 #include "utils/builtins.h"
 
+/* copy the next part of the string into a buffer */
+static const char *
+cpstr(const char *s, char *buf)
+{
+	char in = 0;
+
+	while (isspace(*s))
+		s++;
+
+	for (; *s && !isspace(*s); s++)
+	{
+		if (strchr("-,:/", *s))
+		{
+			buf[in] = 0;
+			return(s + 1);
+		}
+
+		if (in < 16)
+			buf[in++] = tolower(*s);
+	}
+
+	buf[in] = 0;
+	return s;
+}
+
+/* assumes dd/mm/yyyy unless first item is month in word form */
 time_t
 timestamp_in(const char *timestamp_str)
 {
     struct tm input_time;
     int4 result;
+	char buf[18];
+	const char *p;
+	static const char *mstr[] = {
+		"january", "february", "march", "april", "may", "june",
+		"july", "august", "september", "october", "november", "december"
+	};
 
     memset(&input_time, 0, sizeof(input_time));
-    if(sscanf(timestamp_str, "%d%*c%d%*c%d%*c%d%*c%d%*c%d",
-	      &input_time.tm_year, &input_time.tm_mon, &input_time.tm_mday,
-	      &input_time.tm_hour, &input_time.tm_min, &input_time.tm_sec) != 6) {
-	elog(WARN, "timestamp_in: timestamp \"%s\" not of the form yyyy-mm-dd hh:mm:ss",
+	p = cpstr(timestamp_str, buf);
+	if (isdigit(buf[0]))	/* must be dd/mm/yyyy */
+	{
+		input_time.tm_mday = atoi(buf);
+		p = cpstr(p, buf);
+		if (!buf[0])
+			elog(WARN, "timestamp_in: timestamp \"%s\" not a proper date",
+					timestamp_str);
+		if (isdigit(buf[0]))
+		{
+			input_time.tm_mon = atoi(buf) - 1;
+			if (input_time.tm_mon < 0 || input_time.tm_mon > 11)
+				elog(WARN, "timestamp_in: timestamp \"%s\" invalid month",
+					timestamp_str);
+		}
+		else
+		{
+			int i;
+			for (i = 0; i < 12; i++)
+				if (strncmp(mstr[i], buf, strlen(buf)) == 0)
+					break;
+			if (1 > 11)
+				elog(WARN, "timestamp_in: timestamp \"%s\" invalid month",
+						timestamp_str);
+			input_time.tm_mon = i;
+		}
+	}
+	else	/* must be month/dd/yyyy */
+	{
+		int i;
+		for (i = 0; i < 12; i++)
+			if (strncmp(mstr[i], buf, strlen(buf)) == 0)
+				break;
+		if (1 > 11)
+			elog(WARN, "timestamp_in: timestamp \"%s\" invalid month",
+					timestamp_str);
+		input_time.tm_mon = i;
+		p = cpstr(p, buf);
+		input_time.tm_mday = atoi(buf);
+		if (!input_time.tm_mday || input_time.tm_mday > 31)
+			elog(WARN, "timestamp_in: timestamp \"%s\" not a proper date",
 	     timestamp_str);
     }
 
-    /* range checking?  bahahahaha.... */
-
-    input_time.tm_year -= 1900;
-    input_time.tm_mon -= 1;
+	p = cpstr(p, buf);
+	if (!buf[0] || !isdigit(buf[0]))
+		elog(WARN, "timestamp_in: timestamp \"%s\" not a proper date",
+				timestamp_str);
+	if ((input_time.tm_year = atoi(buf)) < 1900)
+		input_time.tm_year += 1900;
+
+	/* now get the time */
+	p = cpstr(p, buf);
+	input_time.tm_hour = atoi(buf);
+	p = cpstr(p, buf);
+	input_time.tm_min = atoi(buf);
+	p = cpstr(p, buf);
+	input_time.tm_sec = atoi(buf);
 
     /* use mktime(), but make this GMT, not local time */
     result = mktime(&input_time);
@@ -35,7 +115,7 @@ timestamp_out(time_t timestamp)
     char *result;
     struct tm *time;
 
-    time = localtime((time_t *)&timestamp);
+    time = localtime(&timestamp);
     result = palloc(20);
     sprintf(result, "%04d-%02d-%02d %02d:%02d:%02d",
 	    time->tm_year+1900, time->tm_mon+1, time->tm_mday,