diff --git a/attributes/schema_type_parse.c b/attributes/schema_type_parse.c
index 9de255da6fc5986bb28a4565adb4a9709f05f74a..7b1d221d438ac47603d26b95a8772b142e091f36 100644
--- a/attributes/schema_type_parse.c
+++ b/attributes/schema_type_parse.c
@@ -144,10 +144,11 @@ mstro_stp_val_alloc(enum mstro_stp_val_kind kind)
         case MSTRO_STP_FLOATVAL:
         case MSTRO_STP_DOUBLEVAL:
         case MSTRO_STP_BOOLVAL:
+        case MSTRO_STP_TIMESTAMP:
         break;
 
       default:
-        DEBUG("No default restrictions set for type %d\n", kind);
+        ERR("No default restrictions set for type %d\n", kind);
     }
   }
   return res;
@@ -1213,6 +1214,20 @@ static void pcc_action_builtin_type_name_7(mstro_stp_context_t *__pcc_ctx, pcc_t
 #undef auxil
 }
 
+static void pcc_action_builtin_type_name_8(mstro_stp_context_t *__pcc_ctx, pcc_thunk_t *__pcc_in, pcc_value_t *__pcc_out) {
+#define auxil (__pcc_ctx->auxil)
+#define __ (*__pcc_out)
+#define _0 pcc_get_capture_string(__pcc_ctx, &__pcc_in->data.leaf.capt0)
+#define _0s ((const)__pcc_in->data.leaf.capt0.range.start)
+#define _0e ((const)__pcc_in->data.leaf.capt0.range.end)
+    __ = mstro_stp_val_alloc(MSTRO_STP_TIMESTAMP); DEBUG("found timestamp\n"); 
+#undef _0e
+#undef _0s
+#undef _0
+#undef __
+#undef auxil
+}
+
 static void pcc_action_user_type_name_0(mstro_stp_context_t *__pcc_ctx, pcc_thunk_t *__pcc_in, pcc_value_t *__pcc_out) {
 #define auxil (__pcc_ctx->auxil)
 #define __ (*__pcc_out)
@@ -2169,6 +2184,31 @@ static pcc_thunk_chunk_t *pcc_evaluate_rule_builtin_type_name(mstro_stp_context_
         }
         goto L0001;
     L0009:;
+        ctx->pos = p;
+        pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
+        {
+            if (
+                pcc_refill_buffer(ctx, 9) < 9 ||
+                (ctx->buffer.buf + ctx->pos)[0] != 't' ||
+                (ctx->buffer.buf + ctx->pos)[1] != 'i' ||
+                (ctx->buffer.buf + ctx->pos)[2] != 'm' ||
+                (ctx->buffer.buf + ctx->pos)[3] != 'e' ||
+                (ctx->buffer.buf + ctx->pos)[4] != 's' ||
+                (ctx->buffer.buf + ctx->pos)[5] != 't' ||
+                (ctx->buffer.buf + ctx->pos)[6] != 'a' ||
+                (ctx->buffer.buf + ctx->pos)[7] != 'm' ||
+                (ctx->buffer.buf + ctx->pos)[8] != 'p'
+            ) goto L0010;
+            ctx->pos += 9;
+        }
+        {
+            pcc_thunk_t *const thunk = pcc_thunk__create_leaf(ctx->auxil, pcc_action_builtin_type_name_8, 0, 0);
+            thunk->data.leaf.capt0.range.start = chunk->pos;
+            thunk->data.leaf.capt0.range.end = ctx->pos;
+            pcc_thunk_array__add(ctx->auxil, &chunk->thunks, thunk);
+        }
+        goto L0001;
+    L0010:;
         ctx->pos = p;
         pcc_thunk_array__revert(ctx->auxil, &chunk->thunks, n);
         goto L0000;
@@ -3578,7 +3618,7 @@ void mstro_stp_destroy(mstro_stp_context_t *ctx) {
 
 #define MIN(x,y) ((x)<(y) ? (x) : (y))
 
-#line 561 "schema_type_parse.peg"
+#line 576 "schema_type_parse.peg"
 mstro_status
 mstro_schema_type_parse(const char *string, struct mstro_stp_val **res)
 {
@@ -3587,7 +3627,7 @@ mstro_schema_type_parse(const char *string, struct mstro_stp_val **res)
   if(ctx==NULL)
     return MSTRO_NOMEM;
   int i = mstro_stp_parse(ctx, res);
-  DEBUG("parser result code: %d\n");
+  DEBUG("parser result code: %d\n", i);
   if(in.got_error) {
     *res = NULL;
     /* FIXME: we need to figure out if we leak partial parse results here */
@@ -3631,7 +3671,7 @@ mstro_stp_val_dispose(struct mstro_stp_val *v)
       break;
     case MSTRO_STP_NAME:
       if(v->nameval) 
-        free(v->nameval);
+              free(v->nameval);
       break;
     default:
       break;
@@ -3689,6 +3729,7 @@ mstro_stp_val__describe(const struct mstro_stp_val *v)
     case MSTRO_STP_EXCLSTR:
     case MSTRO_STP_ICASE:
     case MSTRO_STP_NAME:
+    case MSTRO_STP_TIMESTAMP:
       DEBUG("v kind %d, describe unimplemented\n", v->kind);
       break;
 
@@ -3751,23 +3792,28 @@ mstro_stp_val__build_restricted_type(
        struct mstro_stp_val *tmp = args;
        args = args->list_tail;
        tmp->list_tail = NULL;
-
+       
        switch(tmp->list_entry->kind) {
          case MSTRO_STP_MININT: 
-           result->int_min = tmp->list_entry->minintval; break;
+           result->int_min = tmp->list_entry->minintval;
+	   break;
          case MSTRO_STP_MINUINT: 
            if(tmp->list_entry->minuintval>(uint64_t)INT64_MAX) {
              ERR("signed int min %" PRIu64 "exceeds INT64_MAX\n", tmp->list_entry->minuintval);
            }
-           result->int_min = MIN((uint64_t)INT64_MAX,tmp->list_entry->minuintval);
+           result->int_min = (tmp->list_entry->minuintval < INT64_MAX)
+	   		     ? (int64_t)tmp->list_entry->minuintval : INT64_MAX;
            break;
          case MSTRO_STP_MAXINT: 
-           result->int_max = tmp->list_entry->maxintval; break;
+           result->int_max = tmp->list_entry->maxintval;
+	   break;
          case MSTRO_STP_MAXUINT: 
+           DEBUG("int, encountered maxuint arg of %" PRIu64 "\n", tmp->list_entry->maxuintval);
            if(tmp->list_entry->maxuintval>(uint64_t)INT64_MAX) {
              ERR("signed int max %" PRIu64 "exceeds INT64_MAX\n", tmp->list_entry->maxuintval);
            }
-           result->int_min = MIN((uint64_t)INT64_MAX,tmp->list_entry->maxuintval);
+           result->int_max = (tmp->list_entry->maxuintval < INT64_MAX) 
+                             ? (int64_t)tmp->list_entry->maxuintval : INT64_MAX ;
            break;
          default:
            ERR("Illegal type restriction for signed integer: %d\n", tmp->list_entry->kind);
@@ -3978,6 +4024,22 @@ mstro_stp_val__build_restricted_type(
 
       break;
       }
+    case MSTRO_STP_TIMESTAMP: {
+      leftovers = args; /* no args supported */
+      /* construct the regexp */
+      result->kind = MSTRO_STP_REGEX;
+      result->regex_ignorecase = false;
+      result->regex_name = strdup("RFC3339 timestamp");
+      result->regex_numpatterns = 1;
+      result->regex_patterns = malloc(sizeof(char*));
+      char *tmp = strdup(RFC3339_PATTERN);
+      if(result->regex_patterns==NULL || tmp==NULL || result->regex_name==NULL) {
+        ERR("Cannot allocate timestamp regex\n");
+        abort();
+      }
+      result->regex_patterns[0] = tmp;
+      break;
+    }
     default:
       ERR("type parse intermediate kind %d should not be returned\n",
           typename->kind);
diff --git a/attributes/schema_type_parse.h b/attributes/schema_type_parse.h
index ce7f22e3449416de2c03b84eddd9dcec359b454c..e9f5803a3d34817be26f664afadbf446d5066588 100644
--- a/attributes/schema_type_parse.h
+++ b/attributes/schema_type_parse.h
@@ -33,6 +33,7 @@ enum mstro_stp_val_kind {
   MSTRO_STP_ICASE,
   MSTRO_STP_NAME,
   MSTRO_STP_LIST,
+  MSTRO_STP_TIMESTAMP,  /* externally will be converted to RFC3339 regex */
 
   /** user-facing node types */
   MSTRO_STP_BOOL = 64,
@@ -132,6 +133,10 @@ mstro_schema_type_parse(const char *string, struct mstro_stp_val **res);
 mstro_status
 mstro_stp_val_dispose(struct mstro_stp_val *v);
 
+/** User-facing: pattern for RFC3339-timestamp */
+#define RFC3339_PATTERN ("^([0-9]{4})-([0-9]{2})-([0-9]{2})"                     \
+                         "([Tt]([0-9]{2}):([0-9]{2}):([0-9]{2})(\\.[0-9]+)?)?"   \
+                         "(([Zz]|([+-])([0-9]{2}):([0-9]{2})))?")
 
 
 
diff --git a/attributes/schema_type_parse.peg b/attributes/schema_type_parse.peg
index 620a0a594bdade6ebe6f60293281e3ea4da241cc..d7e8a25870692ba8e853d5957d4d4eb4cedec7e7 100644
--- a/attributes/schema_type_parse.peg
+++ b/attributes/schema_type_parse.peg
@@ -130,10 +130,11 @@ mstro_stp_val_alloc(enum mstro_stp_val_kind kind)
 	case MSTRO_STP_FLOATVAL:
 	case MSTRO_STP_DOUBLEVAL:
 	case MSTRO_STP_BOOLVAL:
+	case MSTRO_STP_TIMESTAMP:
 	break;
 	  
       default:
-        DEBUG("No default restrictions set for type %d\n", kind);
+        ERR("No default restrictions set for type %d\n", kind);
     }
   }
   return res;
@@ -194,6 +195,7 @@ enum mstro_stp_val_kind {
   MSTRO_STP_ICASE,
   MSTRO_STP_NAME,
   MSTRO_STP_LIST,
+  MSTRO_STP_TIMESTAMP,  /* externally will be converted to RFC3339 regex */
   
   /** user-facing node types */
   MSTRO_STP_BOOL = 64,
@@ -293,6 +295,10 @@ mstro_schema_type_parse(const char *string, struct mstro_stp_val **res);
 mstro_status
 mstro_stp_val_dispose(struct mstro_stp_val *v);
 
+/** User-facing: pattern for RFC3339-timestamp */
+#define RFC3339_PATTERN ("^([0-9]{4})-([0-9]{2})-([0-9]{2})"                     \
+                         "([Tt]([0-9]{2}):([0-9]{2}):([0-9]{2})(\\.[0-9]+)?)?"   \
+                         "(([Zz]|([+-])([0-9]{2}):([0-9]{2})))?")
 
 
 }
@@ -324,6 +330,7 @@ builtin_type_name <-
 		  / "regex"  { $$ = mstro_stp_val_alloc(MSTRO_STP_REGEX);  DEBUG("found regex\n"); }
 		  / "str"    { $$ = mstro_stp_val_alloc(MSTRO_STP_STR);    DEBUG("found str\n");   }
 		  / "blob"   { $$ = mstro_stp_val_alloc(MSTRO_STP_BLOB);   DEBUG("found blob\n");  }
+		  / "timestamp" { $$ = mstro_stp_val_alloc(MSTRO_STP_TIMESTAMP); DEBUG("found timestamp\n"); }
 
 ## user-defined types are a name suitable for a maestro schema yaml
 ##   attribute key, possibly including (parts of) a namespace prefix
@@ -566,7 +573,7 @@ EOF  <- !.
 
 #define MIN(x,y) ((x)<(y) ? (x) : (y))
 
-#line 561 "schema_type_parse.peg"
+#line 576 "schema_type_parse.peg"
 mstro_status
 mstro_schema_type_parse(const char *string, struct mstro_stp_val **res)
 {
@@ -575,7 +582,7 @@ mstro_schema_type_parse(const char *string, struct mstro_stp_val **res)
   if(ctx==NULL)
     return MSTRO_NOMEM;
   int i = mstro_stp_parse(ctx, res);
-  DEBUG("parser result code: %d\n");
+  DEBUG("parser result code: %d\n", i);
   if(in.got_error) {
     *res = NULL;
     /* FIXME: we need to figure out if we leak partial parse results here */
@@ -619,7 +626,7 @@ mstro_stp_val_dispose(struct mstro_stp_val *v)
       break;
     case MSTRO_STP_NAME:
       if(v->nameval) 
-        free(v->nameval);
+              free(v->nameval);
       break;
     default:
       break;
@@ -677,6 +684,7 @@ mstro_stp_val__describe(const struct mstro_stp_val *v)
     case MSTRO_STP_EXCLSTR:
     case MSTRO_STP_ICASE:
     case MSTRO_STP_NAME:
+    case MSTRO_STP_TIMESTAMP:
       DEBUG("v kind %d, describe unimplemented\n", v->kind);
       break;
 
@@ -739,23 +747,28 @@ mstro_stp_val__build_restricted_type(
        struct mstro_stp_val *tmp = args;
        args = args->list_tail;
        tmp->list_tail = NULL;
-
+       
        switch(tmp->list_entry->kind) {
          case MSTRO_STP_MININT: 
-           result->int_min = tmp->list_entry->minintval; break;
+           result->int_min = tmp->list_entry->minintval;
+	   break;
          case MSTRO_STP_MINUINT: 
            if(tmp->list_entry->minuintval>(uint64_t)INT64_MAX) {
              ERR("signed int min %" PRIu64 "exceeds INT64_MAX\n", tmp->list_entry->minuintval);
            }
-           result->int_min = MIN((uint64_t)INT64_MAX,tmp->list_entry->minuintval);
+           result->int_min = (tmp->list_entry->minuintval < INT64_MAX)
+	   		     ? (int64_t)tmp->list_entry->minuintval : INT64_MAX;
            break;
          case MSTRO_STP_MAXINT: 
-           result->int_max = tmp->list_entry->maxintval; break;
+           result->int_max = tmp->list_entry->maxintval;
+	   break;
          case MSTRO_STP_MAXUINT: 
+           DEBUG("int, encountered maxuint arg of %" PRIu64 "\n", tmp->list_entry->maxuintval);
            if(tmp->list_entry->maxuintval>(uint64_t)INT64_MAX) {
              ERR("signed int max %" PRIu64 "exceeds INT64_MAX\n", tmp->list_entry->maxuintval);
            }
-           result->int_min = MIN((uint64_t)INT64_MAX,tmp->list_entry->maxuintval);
+           result->int_max = (tmp->list_entry->maxuintval < INT64_MAX) 
+                             ? (int64_t)tmp->list_entry->maxuintval : INT64_MAX ;
            break;
          default:
            ERR("Illegal type restriction for signed integer: %d\n", tmp->list_entry->kind);
@@ -966,6 +979,22 @@ mstro_stp_val__build_restricted_type(
 
       break;
       }
+    case MSTRO_STP_TIMESTAMP: {
+      leftovers = args; /* no args supported */
+      /* construct the regexp */
+      result->kind = MSTRO_STP_REGEX;
+      result->regex_ignorecase = false;
+      result->regex_name = strdup("RFC3339 timestamp");
+      result->regex_numpatterns = 1;
+      result->regex_patterns = malloc(sizeof(char*));
+      char *tmp = strdup(RFC3339_PATTERN);
+      if(result->regex_patterns==NULL || tmp==NULL || result->regex_name==NULL) {
+        ERR("Cannot allocate timestamp regex\n");
+        abort();
+      }
+      result->regex_patterns[0] = tmp;
+      break;
+    }
     default:
       ERR("type parse intermediate kind %d should not be returned\n",
           typename->kind);
diff --git a/tests/check_type_parser.c b/tests/check_type_parser.c
index ffe91b09601d68269355ab95a5f9462d86b5eeeb..fb4c898e2d251ea53ec0959cff3863a2262cd14b 100644
--- a/tests/check_type_parser.c
+++ b/tests/check_type_parser.c
@@ -55,6 +55,7 @@ CHEAT_DECLARE(
       /* built-in types, no restrictions */
       "bool()", "uint()", "int()", "float()", "double()",
       "str()", "blob()",
+      "timestamp()",
       /* regex is also built-in but can't be used without args;
        * see below */