To make the set of answers complete. Use rules.
First we will create the service function to be able to raise exceptions from SQL statements:
create or replace function public.fn_raise(msg text, cond boolean = true)
returns bool
immutable
language plpgsql
as $$
begin
if cond then
raise exception '%', msg;
end if;
return false;
end $$;
Next lets create the test table:
create table t(i int, d timestamptz not null default current_timestamp);
And, finally, rule:
create or replace rule rul_t_insert as on insert to t
where new.d <> current_timestamp
do also
select fn_raise(format('Can not insert %s into table t', new.d), new.d <> current_timestamp);
Lets test it:
postgres=# insert into t(i) values(1) returning *;
┌───┬───────────────────────────────┐
│ i │ d │
╞═══╪═══════════════════════════════╡
│ 1 │ 2017-07-28 12:31:37.255392+03 │
└───┴───────────────────────────────┘
postgres=# insert into t(i,d) values(1,null) returning *;
ERROR: null value in column "d" violates not-null constraint
DETAIL: Failing row contains (1, null).
postgres=# insert into t(i,d) values(2,'2000-10-10') returning *;
ERROR: Can not insert 2000-10-10 00:00:00+03 into table t
I the question mentioned only insert but if you also want to block updates of this field, you could to create another rule:
create or replace rule rul_t_update as on update to t
where new.d <> old.d
do also
select fn_raise(format('Can not change t.d to %s', new.d), new.d <> old.d);
Test:
postgres=# update t set i = 3 where i = 1 returning *;
┌───┬───────────────────────────────┐
│ i │ d │
╞═══╪═══════════════════════════════╡
│ 3 │ 2017-07-28 12:31:37.255392+03 │
└───┴───────────────────────────────┘
postgres=# update t set i = 4, d = current_timestamp where i = 3 returning *;
ERROR: Can not change t.d to 2017-07-28 12:39:18.963852+03