diff --git a/archive.c b/archive.c
index 1c2ca78e52..5cdafc9b56 100644
--- a/archive.c
+++ b/archive.c
@@ -472,7 +472,7 @@ static void parse_treeish_arg(const char **argv,
 		archive_time = commit->date;
 	} else {
 		commit_oid = NULL;
-		archive_time = time(NULL);
+		archive_time = time_now();
 	}
 	if (ar_args->mtime_option)
 		archive_time = approxidate(ar_args->mtime_option);
diff --git a/blame.c b/blame.c
index e45d8a3bf9..df14c1dfe4 100644
--- a/blame.c
+++ b/blame.c
@@ -192,7 +192,7 @@ static struct commit *fake_working_tree_commit(struct repository *r,
 	struct strbuf msg = STRBUF_INIT;
 
 	repo_read_index(r);
-	time(&now);
+	now = time_now();
 	commit = alloc_commit_node(r);
 	commit->object.parsed = 1;
 	commit->date = now;
diff --git a/builtin/bugreport.c b/builtin/bugreport.c
index 5bc254be80..bba5820787 100644
--- a/builtin/bugreport.c
+++ b/builtin/bugreport.c
@@ -98,7 +98,7 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
 	struct strbuf buffer = STRBUF_INIT;
 	struct strbuf report_path = STRBUF_INIT;
 	int report = -1;
-	time_t now = time(NULL);
+	time_t now = time_now();
 	struct tm tm;
 	enum diagnose_mode diagnose = DIAGNOSE_NONE;
 	char *option_output = NULL;
diff --git a/builtin/credential-cache--daemon.c b/builtin/credential-cache--daemon.c
index 6e509d02c3..7a87df16d2 100644
--- a/builtin/credential-cache--daemon.c
+++ b/builtin/credential-cache--daemon.c
@@ -27,7 +27,7 @@ static void cache_credential(struct credential *c, int timeout)
 	/* take ownership of pointers */
 	memcpy(&e->item, c, sizeof(*c));
 	memset(c, 0, sizeof(*c));
-	e->expiration = time(NULL) + timeout;
+	e->expiration = time_now() + timeout;
 }
 
 static struct credential_cache_entry *lookup_credential(const struct credential *c)
@@ -54,7 +54,7 @@ static timestamp_t check_expirations(void)
 {
 	static timestamp_t wait_for_entry_until;
 	int i = 0;
-	timestamp_t now = time(NULL);
+	timestamp_t now = time_now();
 	timestamp_t next = TIME_MAX;
 
 	/*
diff --git a/builtin/diagnose.c b/builtin/diagnose.c
index d52015c67a..c502096e6c 100644
--- a/builtin/diagnose.c
+++ b/builtin/diagnose.c
@@ -11,7 +11,7 @@ static const char * const diagnose_usage[] = {
 int cmd_diagnose(int argc, const char **argv, const char *prefix)
 {
 	struct strbuf zip_path = STRBUF_INIT;
-	time_t now = time(NULL);
+	time_t now = time_now();
 	struct tm tm;
 	enum diagnose_mode mode = DIAGNOSE_STATS;
 	char *option_output = NULL;
diff --git a/builtin/fast-import.c b/builtin/fast-import.c
index f7548ff4a3..9096f52075 100644
--- a/builtin/fast-import.c
+++ b/builtin/fast-import.c
@@ -335,7 +335,7 @@ static void write_crash_report(const char *err)
 	fprintf(rpt, "fast-import crash report:\n");
 	fprintf(rpt, "    fast-import process: %"PRIuMAX"\n", (uintmax_t) getpid());
 	fprintf(rpt, "    parent process     : %"PRIuMAX"\n", (uintmax_t) getppid());
-	fprintf(rpt, "    at %s\n", show_date(time(NULL), 0, DATE_MODE(ISO8601)));
+	fprintf(rpt, "    at %s\n", show_date(time_now(), 0, DATE_MODE(ISO8601)));
 	fputc('\n', rpt);
 
 	fputs("fatal: ", rpt);
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index cae804a190..45cc8134cc 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -415,7 +415,7 @@ static struct fsmonitor_token_data *fsmonitor_new_token_data(void)
 	 * events to accumulate.
 	 */
 	if (test_env_value)
-		batch->pinned_time = time(NULL);
+		batch->pinned_time = time_now();
 
 	return token;
 }
@@ -772,7 +772,7 @@ static int do_handle_client(struct fsmonitor_daemon_state *state,
 	 */
 	token_data = state->current_token_data;
 	batch_head = token_data->batch_head;
-	((struct fsmonitor_batch *)batch_head)->pinned_time = time(NULL);
+	((struct fsmonitor_batch *)batch_head)->pinned_time = time_now();
 
 	/*
 	 * FSMonitor Protocol V2 requires that we send a response header
diff --git a/builtin/gc.c b/builtin/gc.c
index c58fe8c936..029bd2ba5c 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -450,7 +450,7 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
 			 * after the user verifies that no gc is
 			 * running.
 			 */
-			time(NULL) - st.st_mtime <= 12 * 3600 &&
+			time_now() - st.st_mtime <= 12 * 3600 &&
 			fscanf(fp, scan_fmt, &pid, locking_host) == 2 &&
 			/* be gentle to concurrent "gc" on remote hosts */
 			(strcmp(locking_host, my_host) || !kill(pid, 0) || errno == EPERM);
diff --git a/builtin/log.c b/builtin/log.c
index b62e629ba8..bdc62d9b9e 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -1168,7 +1168,7 @@ static void gen_message_id(struct rev_info *info, char *base)
 {
 	struct strbuf buf = STRBUF_INIT;
 	strbuf_addf(&buf, "%s.%"PRItime".git.%s", base,
-		    (timestamp_t) time(NULL),
+		    (timestamp_t) time_now(),
 		    git_committer_info(IDENT_NO_NAME|IDENT_NO_DATE|IDENT_STRICT));
 	info->message_id = strbuf_detach(&buf, NULL);
 }
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index fe68c79ee3..3fedeea65c 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -2504,7 +2504,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
 
 	git_config(receive_pack_config, NULL);
 	if (cert_nonce_seed)
-		push_cert_nonce = prepare_push_cert_nonce(service_dir, time(NULL));
+		push_cert_nonce = prepare_push_cert_nonce(service_dir, time_now());
 
 	if (0 <= transfer_unpack_limit)
 		unpack_limit = transfer_unpack_limit;
diff --git a/builtin/reflog.c b/builtin/reflog.c
index 270681dcdf..013673e768 100644
--- a/builtin/reflog.c
+++ b/builtin/reflog.c
@@ -237,7 +237,7 @@ static int cmd_reflog_show(int argc, const char **argv, const char *prefix)
 static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
 {
 	struct cmd_reflog_expire_cb cmd = { 0 };
-	timestamp_t now = time(NULL);
+	timestamp_t now = time_now();
 	int i, status, do_all, all_worktrees = 1;
 	unsigned int flags = 0;
 	int verbose = 0;
diff --git a/commit-graph.c b/commit-graph.c
index 5e6098ff35..4c75d96fc4 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -2196,7 +2196,7 @@ static void merge_commit_graphs(struct write_commit_graph_context *ctx)
 static void mark_commit_graphs(struct write_commit_graph_context *ctx)
 {
 	uint32_t i;
-	time_t now = time(NULL);
+	time_t now = time_now();
 
 	for (i = ctx->num_commit_graphs_after - 1; i < ctx->num_commit_graphs_before; i++) {
 		struct stat st;
@@ -2217,7 +2217,7 @@ static void expire_commit_graphs(struct write_commit_graph_context *ctx)
 	DIR *dir;
 	struct dirent *de;
 	size_t dirnamelen;
-	timestamp_t expire_time = time(NULL);
+	timestamp_t expire_time = time_now();
 
 	if (ctx->opts && ctx->opts->expire_time)
 		expire_time = ctx->opts->expire_time;
diff --git a/compat/nedmalloc/malloc.c.h b/compat/nedmalloc/malloc.c.h
index 814845d4b3..4c30a49e60 100644
--- a/compat/nedmalloc/malloc.c.h
+++ b/compat/nedmalloc/malloc.c.h
@@ -3085,7 +3085,7 @@ static int init_mparams(void) {
 #ifdef WIN32
 	magic = (size_t)(GetTickCount() ^ (size_t)0x55555555U);
 #else
-      magic = (size_t)(time(0) ^ (size_t)0x55555555U);
+      magic = (size_t)(time_now() ^ (size_t)0x55555555U);
 #endif
       magic |= (size_t)8U;    /* ensure nonzero */
       magic &= ~(size_t)7U;   /* improve chances of fault for bad values */
diff --git a/credential.c b/credential.c
index ea40a2a410..dc750fa502 100644
--- a/credential.c
+++ b/credential.c
@@ -356,7 +356,7 @@ void credential_fill(struct credential *c)
 
 	for (i = 0; i < c->helpers.nr; i++) {
 		credential_do(c, c->helpers.items[i].string, "get");
-		if (c->password_expiry_utc < time(NULL)) {
+		if (c->password_expiry_utc < time_now()) {
 			/* Discard expired password */
 			FREE_AND_NULL(c->password);
 			/* Reset expiry to maintain consistency */
@@ -380,7 +380,7 @@ void credential_approve(struct credential *c)
 
 	if (c->approved)
 		return;
-	if (!c->username || !c->password || c->password_expiry_utc < time(NULL))
+	if (!c->username || !c->password || c->password_expiry_utc < time_now())
 		return;
 
 	credential_apply_config(c);
diff --git a/date.c b/date.c
index 6f45eeb356..16717be397 100644
--- a/date.c
+++ b/date.c
@@ -597,7 +597,7 @@ static int match_multi_number(timestamp_t num, char c, const char *date,
 	case '/':
 	case '.':
 		if (!now)
-			now = time(NULL);
+			now = time_now();
 		refuse_future = NULL;
 		if (gmtime_r(&now, &now_tm))
 			refuse_future = &now_tm;
@@ -712,7 +712,7 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt
 		unsigned int num2 = (num % 10000) / 100;
 		unsigned int num3 = num % 100;
 		if (n == 8)
-			set_date(num1, num2, num3, NULL, time(NULL), tm);
+			set_date(num1, num2, num3, NULL, time_now(), tm);
 		else if (n == 6 && set_time(num1, num2, num3, tm) == 0 &&
 			 *end == '.' && isdigit(end[1]))
 			strtoul(end + 1, &end, 10);
@@ -1041,7 +1041,7 @@ void datestamp(struct strbuf *out)
 	int offset;
 	struct tm tm = { 0 };
 
-	time(&now);
+	now = time_now();
 
 	offset = tm_to_time_t(localtime_r(&now, &tm)) - now;
 	offset /= 60;
diff --git a/git-compat-util.h b/git-compat-util.h
index 1e6592624d..d05f4bac22 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -339,6 +339,11 @@ static inline const char *precompose_string_if_needed(const char *in)
 int compat_mkdir_wo_trailing_slash(const char*, mode_t);
 #endif
 
+static inline time_t time_now(void)
+{
+	return time(NULL);
+}
+
 #ifdef NO_STRUCT_ITIMERVAL
 struct itimerval {
 	struct timeval it_interval;
diff --git a/http-backend.c b/http-backend.c
index 9cfc6f2541..d533989e32 100644
--- a/http-backend.c
+++ b/http-backend.c
@@ -113,7 +113,7 @@ static void hdr_nocache(struct strbuf *hdr)
 
 static void hdr_cache_forever(struct strbuf *hdr)
 {
-	timestamp_t now = time(NULL);
+	timestamp_t now = time_now();
 	hdr_date(hdr, "Date", now);
 	hdr_date(hdr, "Expires", now + 31536000);
 	hdr_str(hdr, "Cache-Control", "public, max-age=31536000");
diff --git a/http-push.c b/http-push.c
index 88aa045ecb..d8158667a0 100644
--- a/http-push.c
+++ b/http-push.c
@@ -459,7 +459,7 @@ static int refresh_lock(struct remote_lock *lock)
 			fprintf(stderr, "LOCK HTTP error %ld\n",
 				results.http_code);
 		} else {
-			lock->start_time = time(NULL);
+			lock->start_time = time_now();
 			rc = 1;
 		}
 	}
@@ -473,7 +473,7 @@ static int refresh_lock(struct remote_lock *lock)
 static void check_locks(void)
 {
 	struct remote_lock *lock = repo->locks;
-	time_t current_time = time(NULL);
+	time_t current_time = time_now();
 	int time_remaining;
 
 	while (lock) {
@@ -933,7 +933,7 @@ static struct remote_lock *lock_remote(const char *path, long timeout)
 		FREE_AND_NULL(lock);
 	} else {
 		lock->url = url;
-		lock->start_time = time(NULL);
+		lock->start_time = time_now();
 		lock->next = repo->locks;
 		repo->locks = lock;
 	}
diff --git a/rerere.c b/rerere.c
index a67abaab07..ac36a9c234 100644
--- a/rerere.c
+++ b/rerere.c
@@ -1179,7 +1179,7 @@ void rerere_gc(struct repository *r, struct string_list *rr)
 	DIR *dir;
 	struct dirent *e;
 	int i;
-	timestamp_t now = time(NULL);
+	timestamp_t now = time_now();
 	timestamp_t cutoff_noresolve = now - 15 * 86400;
 	timestamp_t cutoff_resolve = now - 60 * 86400;
 
diff --git a/run-command.c b/run-command.c
index ba617655b2..fbf9afdb27 100644
--- a/run-command.c
+++ b/run-command.c
@@ -1864,7 +1864,7 @@ enum start_bg_result start_bg_command(struct child_process *cmd,
 		goto done;
 	}
 
-	time(&time_limit);
+	time_limit = time_now();
 	time_limit += timeout_sec;
 
 wait:
@@ -1891,7 +1891,7 @@ enum start_bg_result start_bg_command(struct child_process *cmd,
 			 */
 			time_t now;
 
-			time(&now);
+			now = time_now();
 			if (now < time_limit)
 				goto wait;
 
diff --git a/t/helper/test-chmtime.c b/t/helper/test-chmtime.c
index dc28890a18..f48a07f6f7 100644
--- a/t/helper/test-chmtime.c
+++ b/t/helper/test-chmtime.c
@@ -7,7 +7,7 @@
  *
  *	test-tool chmtime =<seconds> file...
  *
- * Relative to the current time as returned by time(3):
+ * Relative to the current time as returned by time_now():
  *
  *	test-tool chmtime =+<seconds> (or =-<seconds>) file...
  *
@@ -60,7 +60,7 @@ static int timespec_arg(const char *arg, long int *set_time, int *set_eq)
 		return 0;
 	}
 	if ((*set_eq && *set_time < 0) || *set_eq == 2) {
-		time_t now = time(NULL);
+		time_t now = time_now();
 		*set_time += now;
 	}
 	return 1;
diff --git a/t/helper/test-simple-ipc.c b/t/helper/test-simple-ipc.c
index 3d1436da59..2267cd9fac 100644
--- a/t/helper/test-simple-ipc.c
+++ b/t/helper/test-simple-ipc.c
@@ -411,7 +411,7 @@ static int client__stop_server(void)
 	time_t time_limit, now;
 	enum ipc_active_state s;
 
-	time(&time_limit);
+	time_limit = time_now();
 	time_limit += cl_args.max_wait_sec;
 
 	cl_args.token = "quit";
@@ -434,7 +434,7 @@ static int client__stop_server(void)
 			return 0;
 		}
 
-		time(&now);
+		now = time_now();
 		if (now > time_limit)
 			return error("daemon has not shutdown yet");
 	}
