anchor.diff:  replace_ast_timestamps(_Mod, {Op, Item1, Item2}) ->
       {Op, Item1, Item2}.
   
  +do_epoch(String, CompleteFun, Exponent) ->
  +    Normal = timestamp_to_normalized(String),
  +    case jam:is_valid(Normal) of
  +        false ->
  +            throw(<<"Invalid date/time string">>);
  +        true ->
  +            ok
  +    end,
  +    Epoch = case jam:is_complete(Normal) of
  +                true ->
  +                    jam:to_epoch(Normal, Exponent);
  +                false ->
  +                    jam:to_epoch(CompleteFun(Normal), Exponent)
  +            end,
  +    case is_atom(Epoch) of
  +        true ->
  +            %% jam returns atoms if processing gives an error
  +            throw(Epoch);
  +        false ->
  +            Epoch
  +    end.
  +
   maybe_convert_to_epoch({'EXIT', _}, Value, _Op) ->
       {binary, Value};
   maybe_convert_to_epoch(timestamp, Value, '>') ->
  
positive.code:     %% date/time strings by one "unit", where the unit is the least
      %% significant value provided by the user. "2016" becomes
      %% "2017". "2016-07-05T11" becomes "2016-07-05T12".
      Normal = timestamp_to_normalized(Value),
      Epoch = case jam:is_complete(Normal) of
                  true ->
                      to_epoch(Normal, 3);
                  false ->
                      to_epoch(jam:expand(jam:increment(Normal, 1), second), 3)
              end,
      case is_atom(Epoch) of
          true ->
              throw(Epoch);
          false ->
              {integer, Epoch}
      end;
  maybe_convert_to_epoch(timestamp, Value, _Op) ->
      Normal = timestamp_to_normalized(Value),
      Epoch = case jam:is_complete(Normal) of
                  true ->
                      to_epoch(Normal, 3);
                  false ->
                      to_epoch(jam:expand(Normal, second), 3)
              end,
      case is_atom(Epoch) of
          true ->
              throw(Epoch);
          false ->
              {integer, Epoch}
      end;
  maybe_convert_to_epoch(_Type, Value, _Op) ->
      {binary, Value}.
  
  %% I haven't investigated why the values are a nested list
  convert_insert_timestamps(Mod, Fields, [Values]) ->
      Types = lists:map(fun({identifier, [Column]}) ->
                                catch Mod:get_field_type([Column])
                        end, Fields),
      TypeMap = lists:zip(Values, Types),
      [lists:map(fun({binary, String}=Value) ->
                         case lists:keyfind(Value, 1, TypeMap) of
                             {Value, timestamp} ->
                                 {integer, timestamp_to_epoch(String)};
                             _ ->
                                 Value
                         end;
  
negative.code:         _ ->
              Normal
      end.
  
  %% Useful key extractors for functions (e.g., in get or delete code
  %% paths) which are agnostic to whether they are dealing with TS or
  