diff --git a/handler.go b/handler.go
index 9a302628f6344527499dc2cb5f293173671488f4..3937b2f52003fa828a7d96a3b18f2181a98adb4b 100644
--- a/handler.go
+++ b/handler.go
@@ -24,6 +24,7 @@ import (
 	"reflect"
 	"strings"
 	"sync"
+	"time"
 
 	"tuxpa.in/a/zlog"
 )
@@ -200,7 +201,7 @@ func (h *handler) startCallProc(fn func(*callProc)) {
 // handleImmediate executes non-call messages. It returns false if the message is a
 // call or requires a reply.
 func (h *handler) handleImmediate(msg *jsonrpcMessage) bool {
-	start := NewTimer()
+	start := time.Now()
 	switch {
 	case msg.isNotification():
 		if strings.HasSuffix(msg.Method, notificationMethodSuffix) {
@@ -210,7 +211,7 @@ func (h *handler) handleImmediate(msg *jsonrpcMessage) bool {
 		return false
 	case msg.isResponse():
 		h.handleResponse(msg)
-		h.log.Trace().Str("reqid", string(msg.ID.RawMessage())).Dur("duration", start.Since(start)).Msg("Handled RPC response")
+		h.log.Trace().Str("reqid", string(msg.ID.RawMessage())).Dur("duration", time.Since(start)).Msg("Handled RPC response")
 		return true
 	default:
 		return false
diff --git a/timer.go b/timer.go
deleted file mode 100644
index 689d95564f6dd8f6deb3bc1716fb715766a2e23a..0000000000000000000000000000000000000000
--- a/timer.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package jrpc
-
-import (
-	"time"
-)
-
-type Timer struct {
-	s time.Time
-}
-
-func NewTimer() *Timer {
-	return &Timer{
-		s: time.Now(),
-	}
-}
-
-func (t *Timer) Since(...any) time.Duration {
-	return time.Since(t.s)
-}
-
-func (t *Timer) Until() time.Duration {
-	return time.Until(t.s)
-}