diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c
index 951b6554007b2272d917e1e431c084130a7ed6d7..d0d7206ae9307aaaa7bb6a474fbc5b22ca14c871 100644
--- a/src/backend/utils/adt/json.c
+++ b/src/backend/utils/adt/json.c
@@ -32,6 +32,9 @@
 #include "utils/typcache.h"
 #include "utils/syscache.h"
 
+/* String to output for infinite dates and timestamps */
+#define DT_INFINITY "\"infinity\""
+
 /*
  * The context of the parser is maintained by the recursive descent
  * mechanism, but is passed explicitly to the error reporting routine
@@ -1436,20 +1439,18 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
 
 				date = DatumGetDateADT(val);
 
-				/* XSD doesn't support infinite values */
 				if (DATE_NOT_FINITE(date))
-					ereport(ERROR,
-							(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
-							 errmsg("date out of range"),
-							 errdetail("JSON does not support infinite date values.")));
+				{
+					/* we have to format infinity ourselves */
+					appendStringInfoString(result,DT_INFINITY);
+				}
 				else
 				{
 					j2date(date + POSTGRES_EPOCH_JDATE,
 						   &(tm.tm_year), &(tm.tm_mon), &(tm.tm_mday));
 					EncodeDateOnly(&tm, USE_XSD_DATES, buf);
+					appendStringInfo(result, "\"%s\"", buf);
 				}
-
-				appendStringInfo(result, "\"%s\"", buf);
 			}
 			break;
 		case JSONTYPE_TIMESTAMP:
@@ -1461,20 +1462,20 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
 
 				timestamp = DatumGetTimestamp(val);
 
-				/* XSD doesn't support infinite values */
 				if (TIMESTAMP_NOT_FINITE(timestamp))
-					ereport(ERROR,
-							(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
-							 errmsg("timestamp out of range"),
-							 errdetail("JSON does not support infinite timestamp values.")));
+				{
+					/* we have to format infinity ourselves */
+					appendStringInfoString(result,DT_INFINITY);
+				}
 				else if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, NULL) == 0)
+				{
 					EncodeDateTime(&tm, fsec, false, 0, NULL, USE_XSD_DATES, buf);
+					appendStringInfo(result, "\"%s\"", buf);
+				}
 				else
 					ereport(ERROR,
 							(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
 							 errmsg("timestamp out of range")));
-
-				appendStringInfo(result, "\"%s\"", buf);
 			}
 			break;
 		case JSONTYPE_TIMESTAMPTZ:
@@ -1488,20 +1489,20 @@ datum_to_json(Datum val, bool is_null, StringInfo result,
 
 				timestamp = DatumGetTimestamp(val);
 
-				/* XSD doesn't support infinite values */
 				if (TIMESTAMP_NOT_FINITE(timestamp))
-					ereport(ERROR,
-							(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
-							 errmsg("timestamp out of range"),
-							 errdetail("JSON does not support infinite timestamp values.")));
+				{
+					/* we have to format infinity ourselves */
+					appendStringInfoString(result,DT_INFINITY);
+				}
 				else if (timestamp2tm(timestamp, &tz, &tm, &fsec, &tzn, NULL) == 0)
+				{
 					EncodeDateTime(&tm, fsec, true, tz, tzn, USE_XSD_DATES, buf);
+					appendStringInfo(result, "\"%s\"", buf);
+				}
 				else
 					ereport(ERROR,
 							(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
 							 errmsg("timestamp out of range")));
-
-				appendStringInfo(result, "\"%s\"", buf);
 			}
 			break;
 		case JSONTYPE_JSON:
diff --git a/src/backend/utils/adt/jsonb.c b/src/backend/utils/adt/jsonb.c
index 644ea6d9414758d7fce4b83038b7081d9c188f19..aac97565f959867181ac0445417b251f67342e7b 100644
--- a/src/backend/utils/adt/jsonb.c
+++ b/src/backend/utils/adt/jsonb.c
@@ -28,6 +28,14 @@
 #include "utils/syscache.h"
 #include "utils/typcache.h"
 
+/*
+ * String to output for infinite dates and timestamps.
+ * Note the we don't use embedded quotes, unlike for json, because
+ * we store jsonb strings dequoted.
+ */
+
+#define DT_INFINITY "infinity"
+
 typedef struct JsonbInState
 {
 	JsonbParseState *parseState;
@@ -714,23 +722,21 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
 				char		buf[MAXDATELEN + 1];
 
 				date = DatumGetDateADT(val);
+				jb.type = jbvString;
 
-				/* XSD doesn't support infinite values */
 				if (DATE_NOT_FINITE(date))
-					ereport(ERROR,
-							(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
-							 errmsg("date out of range"),
-							 errdetail("JSON does not support infinite date values.")));
+				{
+					jb.val.string.len = strlen(DT_INFINITY);
+					jb.val.string.val = pstrdup(DT_INFINITY);
+				}
 				else
 				{
 					j2date(date + POSTGRES_EPOCH_JDATE,
 						   &(tm.tm_year), &(tm.tm_mon), &(tm.tm_mday));
 					EncodeDateOnly(&tm, USE_XSD_DATES, buf);
+					jb.val.string.len = strlen(buf);
+					jb.val.string.val = pstrdup(buf);
 				}
-
-				jb.type = jbvString;
-				jb.val.string.len = strlen(buf);
-				jb.val.string.val = pstrdup(buf);
 			}
 			break;
 			case JSONBTYPE_TIMESTAMP:
@@ -741,23 +747,24 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
 					char		buf[MAXDATELEN + 1];
 
 					timestamp = DatumGetTimestamp(val);
+					jb.type = jbvString;
 
-					/* XSD doesn't support infinite values */
 					if (TIMESTAMP_NOT_FINITE(timestamp))
-						ereport(ERROR,
-								(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
-								 errmsg("timestamp out of range"),
-								 errdetail("JSON does not support infinite timestamp values.")));
+					{
+						jb.val.string.len = strlen(DT_INFINITY);
+						jb.val.string.val = pstrdup(DT_INFINITY);
+					}
 					else if (timestamp2tm(timestamp, NULL, &tm, &fsec, NULL, NULL) == 0)
+					{
+
 						EncodeDateTime(&tm, fsec, false, 0, NULL, USE_XSD_DATES, buf);
+						jb.val.string.len = strlen(buf);
+						jb.val.string.val = pstrdup(buf);
+					}
 					else
 						ereport(ERROR,
 								(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
 								 errmsg("timestamp out of range")));
-
-					jb.type = jbvString;
-					jb.val.string.len = strlen(buf);
-					jb.val.string.val = pstrdup(buf);
 				}
 				break;
 			case JSONBTYPE_TIMESTAMPTZ:
@@ -770,23 +777,23 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
 					char		buf[MAXDATELEN + 1];
 
 					timestamp = DatumGetTimestamp(val);
+					jb.type = jbvString;
 
-					/* XSD doesn't support infinite values */
 					if (TIMESTAMP_NOT_FINITE(timestamp))
-						ereport(ERROR,
-								(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
-								 errmsg("timestamp out of range"),
-								 errdetail("JSON does not support infinite timestamp values.")));
+					{
+						jb.val.string.len = strlen(DT_INFINITY);
+						jb.val.string.val = pstrdup(DT_INFINITY);
+					}
 					else if (timestamp2tm(timestamp, &tz, &tm, &fsec, &tzn, NULL) == 0)
+					{
 						EncodeDateTime(&tm, fsec, true, tz, tzn, USE_XSD_DATES, buf);
+						jb.val.string.len = strlen(buf);
+						jb.val.string.val = pstrdup(buf);
+					}
 					else
 						ereport(ERROR,
 								(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
 								 errmsg("timestamp out of range")));
-
-					jb.type = jbvString;
-					jb.val.string.len = strlen(buf);
-					jb.val.string.val = pstrdup(buf);
 				}
 				break;
 			case JSONBTYPE_JSONCAST:
diff --git a/src/test/regress/expected/json.out b/src/test/regress/expected/json.out
index 16704363dc62b9ccfedab1b124f574821f5c936b..3942c3bee91065d323a6b684a6ee8fdbb2e47638 100644
--- a/src/test/regress/expected/json.out
+++ b/src/test/regress/expected/json.out
@@ -426,6 +426,30 @@ select to_json(timestamptz '2014-05-28 12:22:35.614298-04');
 (1 row)
 
 COMMIT;
+select to_json(date '2014-05-28');
+   to_json    
+--------------
+ "2014-05-28"
+(1 row)
+
+select to_json(date 'Infinity');
+  to_json   
+------------
+ "infinity"
+(1 row)
+
+select to_json(timestamp 'Infinity');
+  to_json   
+------------
+ "infinity"
+(1 row)
+
+select to_json(timestamptz 'Infinity');
+  to_json   
+------------
+ "infinity"
+(1 row)
+
 --json_agg
 SELECT json_agg(q)
   FROM ( SELECT $$a$$ || x AS b, y AS c,
diff --git a/src/test/regress/expected/json_1.out b/src/test/regress/expected/json_1.out
index 807814641dd897f6e47c3b5eb8141c21f3269714..38f15262883b057719544b9bcd52ebd567a6ced2 100644
--- a/src/test/regress/expected/json_1.out
+++ b/src/test/regress/expected/json_1.out
@@ -426,6 +426,30 @@ select to_json(timestamptz '2014-05-28 12:22:35.614298-04');
 (1 row)
 
 COMMIT;
+select to_json(date '2014-05-28');
+   to_json    
+--------------
+ "2014-05-28"
+(1 row)
+
+select to_json(date 'Infinity');
+  to_json   
+------------
+ "infinity"
+(1 row)
+
+select to_json(timestamp 'Infinity');
+  to_json   
+------------
+ "infinity"
+(1 row)
+
+select to_json(timestamptz 'Infinity');
+  to_json   
+------------
+ "infinity"
+(1 row)
+
 --json_agg
 SELECT json_agg(q)
   FROM ( SELECT $$a$$ || x AS b, y AS c,
diff --git a/src/test/regress/expected/jsonb.out b/src/test/regress/expected/jsonb.out
index 6c6ed950f0830c8323d48134618e57ed0c0fc9de..0d558901e9d84302077c8ce1856d0549b6ea7dc1 100644
--- a/src/test/regress/expected/jsonb.out
+++ b/src/test/regress/expected/jsonb.out
@@ -330,6 +330,30 @@ select to_jsonb(timestamptz '2014-05-28 12:22:35.614298-04');
 (1 row)
 
 COMMIT;
+select to_jsonb(date '2014-05-28');
+   to_jsonb   
+--------------
+ "2014-05-28"
+(1 row)
+
+select to_jsonb(date 'Infinity');
+  to_jsonb  
+------------
+ "infinity"
+(1 row)
+
+select to_jsonb(timestamp 'Infinity');
+  to_jsonb  
+------------
+ "infinity"
+(1 row)
+
+select to_jsonb(timestamptz 'Infinity');
+  to_jsonb  
+------------
+ "infinity"
+(1 row)
+
 --jsonb_agg
 CREATE TEMP TABLE rows AS
 SELECT x, 'txt' || x as y
diff --git a/src/test/regress/expected/jsonb_1.out b/src/test/regress/expected/jsonb_1.out
index f30148d51c1bdc232266ca5a6998237b67f39de0..694b6ea5f5caf8169d5fbaa5854a3e0c4101c912 100644
--- a/src/test/regress/expected/jsonb_1.out
+++ b/src/test/regress/expected/jsonb_1.out
@@ -330,6 +330,30 @@ select to_jsonb(timestamptz '2014-05-28 12:22:35.614298-04');
 (1 row)
 
 COMMIT;
+select to_jsonb(date '2014-05-28');
+   to_jsonb   
+--------------
+ "2014-05-28"
+(1 row)
+
+select to_jsonb(date 'Infinity');
+  to_jsonb  
+------------
+ "infinity"
+(1 row)
+
+select to_jsonb(timestamp 'Infinity');
+  to_jsonb  
+------------
+ "infinity"
+(1 row)
+
+select to_jsonb(timestamptz 'Infinity');
+  to_jsonb  
+------------
+ "infinity"
+(1 row)
+
 --jsonb_agg
 CREATE TEMP TABLE rows AS
 SELECT x, 'txt' || x as y
diff --git a/src/test/regress/sql/json.sql b/src/test/regress/sql/json.sql
index 53a37a88439171127c220470f5319dcdc172239d..53832a01fa18f99db163c96333891f4d91b0a4b9 100644
--- a/src/test/regress/sql/json.sql
+++ b/src/test/regress/sql/json.sql
@@ -111,6 +111,12 @@ SET LOCAL TIME ZONE -8;
 select to_json(timestamptz '2014-05-28 12:22:35.614298-04');
 COMMIT;
 
+select to_json(date '2014-05-28');
+
+select to_json(date 'Infinity');
+select to_json(timestamp 'Infinity');
+select to_json(timestamptz 'Infinity');
+
 --json_agg
 
 SELECT json_agg(q)
diff --git a/src/test/regress/sql/jsonb.sql b/src/test/regress/sql/jsonb.sql
index 53cc2393c626c01d8303a3b9bb63293a1b50593b..676e1a7d4c93767602b96bdfc6a39a13f020cc45 100644
--- a/src/test/regress/sql/jsonb.sql
+++ b/src/test/regress/sql/jsonb.sql
@@ -74,6 +74,12 @@ SET LOCAL TIME ZONE -8;
 select to_jsonb(timestamptz '2014-05-28 12:22:35.614298-04');
 COMMIT;
 
+select to_jsonb(date '2014-05-28');
+
+select to_jsonb(date 'Infinity');
+select to_jsonb(timestamp 'Infinity');
+select to_jsonb(timestamptz 'Infinity');
+
 --jsonb_agg
 
 CREATE TEMP TABLE rows AS