diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md
index 1aaf81207512d9114917d84b757d5ddb69dc79ba..dce691c47270a5cad705f83f9eb63af859a69eb8 100644
--- a/docs/usage/configuration-options.md
+++ b/docs/usage/configuration-options.md
@@ -1520,14 +1520,14 @@ Change this setting to `true` if you want to use internal Renovate checks toward
 ## internalChecksFilter
 
 This setting determines whether Renovate controls when and how filtering of internal checks are performed, particularly when multiple versions of the same update type are available.
-Currently this applies to the `stabilityDays` check only.
+Currently this applies to the `minimumReleaseAge` check only.
 
 - `none`: No filtering will be performed, and the highest release will be used regardless of whether it's pending or not
 - `strict`: All pending releases will be filtered. PRs will be skipped unless a non-pending version is available
 - `flexible`: Similar to strict, but in the case where all versions are pending then a PR will be created with the highest pending version
 
-The `flexible` mode can result in "flapping" of Pull Requests, where e.g. a pending PR with version `1.0.3` is first released but then downgraded to `1.0.2` once it passes `stabilityDays`.
-We recommend that you use the `strict` mode, and enable the `dependencyDashboard` so that you have visibility into suppressed PRs.
+The `flexible` mode can result in "flapping" of Pull Requests, for example: a pending PR with version `1.0.3` is first released but then downgraded to `1.0.2` once it passes `minimumReleaseAge`.
+We recommend that you use the `strict` mode, and enable the `dependencyDashboard` so that you can see suppressed PRs.
 
 ## java
 
@@ -1610,6 +1610,60 @@ Depending on its running schedule, Renovate may run a few times within that time
 
 Add to this object if you wish to define rules that apply only to major updates.
 
+## minimumReleaseAge
+
+If this is set _and_ an update has a release timestamp header, then Renovate will check if the set duration has passed.
+
+Note: Renovate will wait for the set duration to pass for each **separate** version.
+Renovate does not wait until the package has seen no releases for x time-duration(`minimumReleaseAge`).
+`minimumReleaseAge` is not intended to help with slowing down fast releasing project updates.
+If you want to slow down PRs for a specific package, setup a custom schedule for that package.
+Read [our selective-scheduling help](https://docs.renovatebot.com/noise-reduction/#selective-scheduling) to learn how to set the schedule.
+
+If the time since the release is less than the set `minimumReleaseAge` a "pending" status check is added to the branch.
+If enough days have passed then the "pending" status is removed, and a "passing" status check is added.
+
+Some datasources don't have a release timestamp, in which case this feature is not compatible.
+Other datasources may have a release timestamp, but Renovate does not support it yet, in which case a feature request needs to be implemented.
+
+Maven users: you cannot use `minimumReleaseAge` if a Maven source returns unreliable `last-modified` headers.
+
+<!-- prettier-ignore -->
+!!! note
+    Configuring this option will add a `renovate/stability-days` option to the status checks.
+
+There are a couple of uses for `minimumReleaseAge`:
+
+<!-- markdownlint-disable MD001 -->
+
+#### Suppress branch/PR creation for X days
+
+If you combine `minimumReleaseAge=3 days` and `internalChecksFilter="strict"` then Renovate will hold back from creating branches until 3 or more days have elapsed since the version was released.
+We recommend that you set `dependencyDashboard=true` so you can see these pending PRs.
+
+#### Prevent holding broken npm packages
+
+npm packages less than 72 hours (3 days) old can be unpublished, which could result in a service impact if you have already updated to it.
+Set `minimumReleaseAge` to `3 days` for npm packages to prevent relying on a package that can be removed from the registry:
+
+```json
+{
+  "packageRules": [
+    {
+      "matchDatasources": ["npm"],
+      "minimumReleaseAge": "3 days"
+    }
+  ]
+}
+```
+
+#### Await X time duration before Automerging
+
+If you enabled `automerge` _and_ `minimumReleaseAge`, it means that PRs will be created immediately but automerging will be delayed until the time-duration has passed.
+This works because Renovate will add a "renovate/stability-days" pending status check to each branch/PR and that pending check will prevent the branch going green to automerge.
+
+<!-- markdownlint-enable MD001 -->
+
 ## minor
 
 Add to this object if you wish to define rules that apply only to minor updates.
@@ -2585,7 +2639,7 @@ This is why we configured an upper limit for how long we wait until creating a P
 
 <!-- prettier-ignore -->
 !!! note
-    If the option `stabilityDays` is non-zero then Renovate disables the `prNotPendingHours` functionality.
+    If the option `minimumReleaseAge` is non-zero then Renovate disables the `prNotPendingHours` functionality.
 
 ## prPriority
 
@@ -3194,55 +3248,6 @@ Configure this to `true` if you wish to get one PR for every separate major vers
 e.g. if you are on webpack@v1 currently then default behavior is a PR for upgrading to webpack@v3 and not for webpack@v2.
 If this setting is true then you would get one PR for webpack@v2 and one for webpack@v3.
 
-## stabilityDays
-
-If this is set to a non-zero value, _and_ an update has a release timestamp header, then Renovate will check if the "stability days" have passed.
-
-Note: Renovate will wait for the set number of `stabilityDays` to pass for each **separate** version.
-Renovate does not wait until the package has seen no releases for x `stabilityDays`.
-`stabilityDays` is not intended to help with slowing down fast releasing project updates.
-If you want to slow down PRs for a specific package, setup a custom schedule for that package.
-Read [our selective-scheduling help](https://docs.renovatebot.com/noise-reduction/#selective-scheduling) to learn how to set the schedule.
-
-If the number of days since the release is less than the set `stabilityDays` a "pending" status check is added to the branch.
-If enough days have passed then the "pending" status is removed, and a "passing" status check is added.
-
-Some datasources do not provide a release timestamp (in which case this feature is not compatible), and other datasources may provide a release timestamp but it's not supported by Renovate (in which case a feature request needs to be implemented).
-
-Maven users: you cannot use `stabilityDays` if a Maven source returns unreliable `last-modified` headers.
-
-There are a couple of uses for `stabilityDays`:
-
-<!-- markdownlint-disable MD001 -->
-
-#### Suppress branch/PR creation for X days
-
-If you combine `stabilityDays=3` and `internalChecksFilter="strict"` then Renovate will hold back from creating branches until 3 or more days have elapsed since the version was released.
-It's recommended that you enable `dependencyDashboard=true` so you don't lose visibility of these pending PRs.
-
-#### Prevent holding broken npm packages
-
-npm packages less than 72 hours (3 days) old can be unpublished, which could result in a service impact if you have already updated to it.
-Set `stabilityDays` to 3 for npm packages to prevent relying on a package that can be removed from the registry:
-
-```json
-{
-  "packageRules": [
-    {
-      "matchDatasources": ["npm"],
-      "stabilityDays": 3
-    }
-  ]
-}
-```
-
-#### Await X days before Automerging
-
-If you have both `automerge` as well as `stabilityDays` enabled, it means that PRs will be created immediately but automerging will be delayed until X days have passed.
-This works because Renovate will add a "renovate/stability-days" pending status check to each branch/PR and that pending check will prevent the branch going green to automerge.
-
-<!-- markdownlint-enable MD001 -->
-
 ## stopUpdatingLabel
 
 This feature only works on supported platforms, check the table above.
diff --git a/lib/config/migrations/custom/stability-days-migration.spec.ts b/lib/config/migrations/custom/stability-days-migration.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b13719bb3901ea1ff78d6a9551f4ff87eac98b29
--- /dev/null
+++ b/lib/config/migrations/custom/stability-days-migration.spec.ts
@@ -0,0 +1,30 @@
+import { StabilityDaysMigration } from './stability-days-migration';
+
+describe('config/migrations/custom/stability-days-migration', () => {
+  it('migrates', () => {
+    expect(StabilityDaysMigration).toMigrate(
+      {
+        stabilityDays: 0,
+      },
+      {
+        minimumReleaseAge: null,
+      }
+    );
+    expect(StabilityDaysMigration).toMigrate(
+      {
+        stabilityDays: 2,
+      },
+      {
+        minimumReleaseAge: '2 days',
+      }
+    );
+    expect(StabilityDaysMigration).toMigrate(
+      {
+        stabilityDays: 1,
+      },
+      {
+        minimumReleaseAge: '1 day',
+      }
+    );
+  });
+});
diff --git a/lib/config/migrations/custom/stability-days-migration.ts b/lib/config/migrations/custom/stability-days-migration.ts
new file mode 100644
index 0000000000000000000000000000000000000000..49d86cdabf80ea0e2d5d11719cda522d7fb1fcc0
--- /dev/null
+++ b/lib/config/migrations/custom/stability-days-migration.ts
@@ -0,0 +1,25 @@
+import is from '@sindresorhus/is';
+import { AbstractMigration } from '../base/abstract-migration';
+
+export class StabilityDaysMigration extends AbstractMigration {
+  override readonly deprecated = true;
+  override readonly propertyName = 'stabilityDays';
+
+  override run(value: unknown): void {
+    if (is.integer(value)) {
+      let newValue: null | string;
+      switch (value) {
+        case 0:
+          newValue = null;
+          break;
+        case 1:
+          newValue = '1 day';
+          break;
+        default:
+          newValue = `${value} days`;
+          break;
+      }
+      this.setSafely('minimumReleaseAge', newValue);
+    }
+  }
+}
diff --git a/lib/config/migrations/migrations-service.ts b/lib/config/migrations/migrations-service.ts
index de172fdd7c391bb287313c7bb41068b5aa74579e..08177481823d1f1c0d82592b53b9292fe39b61f6 100644
--- a/lib/config/migrations/migrations-service.ts
+++ b/lib/config/migrations/migrations-service.ts
@@ -47,6 +47,7 @@ import { SemanticCommitsMigration } from './custom/semantic-commits-migration';
 import { SemanticPrefixMigration } from './custom/semantic-prefix-migration';
 import { SeparateMajorReleasesMigration } from './custom/separate-major-release-migration';
 import { SeparateMultipleMajorMigration } from './custom/separate-multiple-major-migration';
+import { StabilityDaysMigration } from './custom/stability-days-migration';
 import { SuppressNotificationsMigration } from './custom/suppress-notifications-migration';
 import { TrustLevelMigration } from './custom/trust-level-migration';
 import { UnpublishSafeMigration } from './custom/unpublish-safe-migration';
@@ -143,6 +144,7 @@ export class MigrationsService {
     SemanticPrefixMigration,
     MatchDatasourcesMigration,
     DatasourceMigration,
+    StabilityDaysMigration,
   ];
 
   static run(originalConfig: RenovateConfig): RenovateConfig {
diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts
index faa0653fd50761802d5bff6e767b7db2ec8c8b62..233ba616f235a997b67c82550c80d71f33953b4a 100644
--- a/lib/config/options/index.ts
+++ b/lib/config/options/index.ts
@@ -1576,16 +1576,15 @@ const options: RenovateOptions[] = [
     supportedPlatforms: ['azure', 'gitea', 'github', 'gitlab'],
   },
   {
-    name: 'stabilityDays',
-    description:
-      'Number of days required before a new release is considered stable.',
-    type: 'integer',
-    default: 0,
+    name: 'minimumReleaseAge',
+    description: 'Time required before a new release is considered stable.',
+    type: 'string',
+    default: null,
   },
   {
     name: 'internalChecksAsSuccess',
     description:
-      'Whether to consider passing internal checks such as stabilityDays when determining branch status.',
+      'Whether to consider passing internal checks such as `minimumReleaseAge` when determining branch status.',
     type: 'boolean',
     default: false,
   },
@@ -1719,7 +1718,7 @@ const options: RenovateOptions[] = [
       groupName: null,
       schedule: [],
       dependencyDashboardApproval: false,
-      stabilityDays: 0,
+      minimumReleaseAge: null,
       rangeStrategy: 'update-lockfile',
       commitMessageSuffix: '[SECURITY]',
       branchTopic: `{{{datasource}}}-{{{depName}}}-vulnerability`,
diff --git a/lib/config/presets/internal/npm.ts b/lib/config/presets/internal/npm.ts
index 57552b194e38e99e479f1bc5ca885764cf90e945..e269bbd8c77072e311ec76684b68e54964ed0099 100644
--- a/lib/config/presets/internal/npm.ts
+++ b/lib/config/presets/internal/npm.ts
@@ -7,7 +7,7 @@ export const presets: Record<string, Preset> = {
     description:
       'Wait until the npm package is three days old before raising the update, this prevents npm unpublishing a package you already upgraded to.',
     npm: {
-      stabilityDays: 3,
+      minimumReleaseAge: '3 days',
     },
   },
 };
diff --git a/lib/util/date.spec.ts b/lib/util/date.spec.ts
index 87d3742ac28923fe005c2cce53e76800936f437a..08d5d102c3889822848d58aa87e1bf9113fd78e7 100644
--- a/lib/util/date.spec.ts
+++ b/lib/util/date.spec.ts
@@ -1,4 +1,9 @@
-import { getElapsedDays, getElapsedHours, getElapsedMinutes } from './date';
+import {
+  getElapsedDays,
+  getElapsedHours,
+  getElapsedMinutes,
+  getElapsedMs,
+} from './date';
 
 const ONE_MINUTE_MS = 60 * 1000;
 const ONE_HOUR_MS = 60 * ONE_MINUTE_MS;
@@ -34,4 +39,11 @@ describe('util/date', () => {
       expect(getElapsedHours(new Date('invalid_date_string'))).toBe(0);
     });
   });
+
+  describe('getElapsedMilliseconds', () => {
+    it('returns elapsed time in milliseconds', () => {
+      const elapsedMs = new Date().getTime() - new Date(Jan1).getTime();
+      expect(getElapsedMs(Jan1.toISOString())).toBe(elapsedMs);
+    });
+  });
 });
diff --git a/lib/util/date.ts b/lib/util/date.ts
index 53d7877da52dc5a983c2dfaa2c00f64466ba9d36..61fbe64b5c8f4069cd95560485eb36a1bfb99ebd 100644
--- a/lib/util/date.ts
+++ b/lib/util/date.ts
@@ -26,3 +26,7 @@ export function getElapsedHours(date: Date | string): number {
   const diff = DateTime.now().diff(pastDate, 'hours');
   return Math.floor(diff.hours);
 }
+
+export function getElapsedMs(timestamp: string): number {
+  return new Date().getTime() - new Date(timestamp).getTime();
+}
diff --git a/lib/util/pretty-time.spec.ts b/lib/util/pretty-time.spec.ts
index a9f291e467a9c6e19e0a9ec85e359b727d82675d..266089e7e03c29d3154acb63d284eb83d98dc818 100644
--- a/lib/util/pretty-time.spec.ts
+++ b/lib/util/pretty-time.spec.ts
@@ -15,6 +15,8 @@ describe('util/pretty-time', () => {
     ${'1h 1 m 1s'}       | ${1 * 60 * 60 * 1000 + 1 * 60 * 1000 + 1000}
     ${'1hour 1 min 1s'}  | ${1 * 60 * 60 * 1000 + 1 * 60 * 1000 + 1000}
     ${'1h 1m 1s 1ms'}    | ${1 * 60 * 60 * 1000 + 1 * 60 * 1000 + 1000 + 1}
+    ${'1d2h3m'}          | ${24 * 60 * 60 * 1000 + 2 * 60 * 60 * 1000 + 3 * 60 * 1000}
+    ${'1 day'}           | ${24 * 60 * 60 * 1000}
     ${'3 days'}          | ${3 * 24 * 60 * 60 * 1000}
     ${'1 week'}          | ${7 * 24 * 60 * 60 * 1000}
     ${'1 month'}         | ${30 * 24 * 60 * 60 * 1000}
diff --git a/lib/workers/repository/init/__snapshots__/vulnerability.spec.ts.snap b/lib/workers/repository/init/__snapshots__/vulnerability.spec.ts.snap
index 990d099897ce2ecdda321c8744aabfd79f2a3b8f..e731e34f30e7455c1605feed6b46db7ccdfed825 100644
--- a/lib/workers/repository/init/__snapshots__/vulnerability.spec.ts.snap
+++ b/lib/workers/repository/init/__snapshots__/vulnerability.spec.ts.snap
@@ -21,10 +21,10 @@ exports[`workers/repository/init/vulnerability detectVulnerabilityAlerts() retur
       "commitMessageSuffix": "[SECURITY]",
       "dependencyDashboardApproval": false,
       "groupName": null,
+      "minimumReleaseAge": null,
       "prCreation": "immediate",
       "rangeStrategy": "update-lockfile",
       "schedule": [],
-      "stabilityDays": 0,
     },
     "isVulnerabilityAlert": true,
     "matchCurrentVersion": "= 1.8.2",
@@ -51,10 +51,10 @@ go",
       "commitMessageSuffix": "[SECURITY]",
       "dependencyDashboardApproval": false,
       "groupName": null,
+      "minimumReleaseAge": null,
       "prCreation": "immediate",
       "rangeStrategy": "update-lockfile",
       "schedule": [],
-      "stabilityDays": 0,
     },
     "isVulnerabilityAlert": true,
     "matchCurrentVersion": "1.8.2",
@@ -81,10 +81,10 @@ actions",
       "commitMessageSuffix": "[SECURITY]",
       "dependencyDashboardApproval": false,
       "groupName": null,
+      "minimumReleaseAge": null,
       "prCreation": "immediate",
       "rangeStrategy": "update-lockfile",
       "schedule": [],
-      "stabilityDays": 0,
     },
     "isVulnerabilityAlert": true,
     "matchCurrentVersion": "== 1.6.7",
@@ -126,10 +126,10 @@ Ansible before versions 2.1.4, 2.2.1 is vulnerable to an improper input validati
       "commitMessageSuffix": "[SECURITY]",
       "dependencyDashboardApproval": false,
       "groupName": null,
+      "minimumReleaseAge": null,
       "prCreation": "immediate",
       "rangeStrategy": "update-lockfile",
       "schedule": [],
-      "stabilityDays": 0,
     },
     "isVulnerabilityAlert": true,
     "matchCurrentVersion": "2.4.2",
diff --git a/lib/workers/repository/process/lookup/__snapshots__/filter-checks.spec.ts.snap b/lib/workers/repository/process/lookup/__snapshots__/filter-checks.spec.ts.snap
index 3c5cc28de8b00349611d6f1d9106bd38bbe4e19a..5bf232ab929a17812ef6c6e3b1604e5d758daf68 100644
--- a/lib/workers/repository/process/lookup/__snapshots__/filter-checks.spec.ts.snap
+++ b/lib/workers/repository/process/lookup/__snapshots__/filter-checks.spec.ts.snap
@@ -24,7 +24,7 @@ exports[`workers/repository/process/lookup/filter-checks .filterInternalChecks()
 }
 `;
 
-exports[`workers/repository/process/lookup/filter-checks .filterInternalChecks() picks up stabilityDays settings from hostRules 1`] = `
+exports[`workers/repository/process/lookup/filter-checks .filterInternalChecks() picks up minimumReleaseAge settings from hostRules 1`] = `
 {
   "pendingChecks": false,
   "pendingReleases": [],
@@ -35,7 +35,7 @@ exports[`workers/repository/process/lookup/filter-checks .filterInternalChecks()
 }
 `;
 
-exports[`workers/repository/process/lookup/filter-checks .filterInternalChecks() picks up stabilityDays settings from updateType 1`] = `
+exports[`workers/repository/process/lookup/filter-checks .filterInternalChecks() picks up minimumReleaseAge settings from updateType 1`] = `
 {
   "pendingChecks": false,
   "pendingReleases": [
diff --git a/lib/workers/repository/process/lookup/filter-checks.spec.ts b/lib/workers/repository/process/lookup/filter-checks.spec.ts
index 5802aced0e1fe6d98f34b773cb4b8a4d998c58b2..8c210db87d65262dcad06b162f18ec5620738678 100644
--- a/lib/workers/repository/process/lookup/filter-checks.spec.ts
+++ b/lib/workers/repository/process/lookup/filter-checks.spec.ts
@@ -4,6 +4,7 @@ import * as allVersioning from '../../../../modules/versioning';
 import { clone } from '../../../../util/clone';
 import * as _dateUtil from '../../../../util/date';
 import * as _mergeConfidence from '../../../../util/merge-confidence';
+import { toMs } from '../../../../util/pretty-time';
 import { filterInternalChecks } from './filter-checks';
 import type { LookupUpdateConfig, UpdateResult } from './types';
 
@@ -44,10 +45,10 @@ describe('workers/repository/process/lookup/filter-checks', () => {
     config.currentVersion = '1.0.0';
     sortedReleases = clone(releases);
     jest.resetAllMocks();
-    dateUtil.getElapsedDays.mockReturnValueOnce(3);
-    dateUtil.getElapsedDays.mockReturnValueOnce(5);
-    dateUtil.getElapsedDays.mockReturnValueOnce(7);
-    dateUtil.getElapsedDays.mockReturnValueOnce(9);
+    dateUtil.getElapsedMs.mockReturnValueOnce(toMs('3 days') ?? 0);
+    dateUtil.getElapsedMs.mockReturnValueOnce(toMs('5 days') ?? 0);
+    dateUtil.getElapsedMs.mockReturnValueOnce(toMs('7 days') ?? 0);
+    dateUtil.getElapsedMs.mockReturnValueOnce(toMs('9 days') ?? 0);
   });
 
   describe('.filterInternalChecks()', () => {
@@ -67,7 +68,7 @@ describe('workers/repository/process/lookup/filter-checks', () => {
 
     it('returns non-pending latest release if internalChecksFilter=flexible and none pass checks', async () => {
       config.internalChecksFilter = 'flexible';
-      config.stabilityDays = 10;
+      config.minimumReleaseAge = '10 days';
       const res = await filterInternalChecks(
         config,
         versioning,
@@ -82,7 +83,7 @@ describe('workers/repository/process/lookup/filter-checks', () => {
 
     it('returns pending latest release if internalChecksFilter=strict and none pass checks', async () => {
       config.internalChecksFilter = 'strict';
-      config.stabilityDays = 10;
+      config.minimumReleaseAge = '10 days';
       const res = await filterInternalChecks(
         config,
         versioning,
@@ -97,7 +98,7 @@ describe('workers/repository/process/lookup/filter-checks', () => {
 
     it('returns non-latest release if internalChecksFilter=strict and some pass checks', async () => {
       config.internalChecksFilter = 'strict';
-      config.stabilityDays = 6;
+      config.minimumReleaseAge = '6 days';
       const res = await filterInternalChecks(
         config,
         versioning,
@@ -112,7 +113,7 @@ describe('workers/repository/process/lookup/filter-checks', () => {
 
     it('returns non-latest release if internalChecksFilter=flexible and some pass checks', async () => {
       config.internalChecksFilter = 'strict';
-      config.stabilityDays = 6;
+      config.minimumReleaseAge = '6 days';
       const res = await filterInternalChecks(
         config,
         versioning,
@@ -125,10 +126,12 @@ describe('workers/repository/process/lookup/filter-checks', () => {
       expect(res.release.version).toBe('1.0.2');
     });
 
-    it('picks up stabilityDays settings from hostRules', async () => {
+    it('picks up minimumReleaseAge settings from hostRules', async () => {
       config.internalChecksFilter = 'strict';
-      config.stabilityDays = 6;
-      config.packageRules = [{ matchUpdateTypes: ['patch'], stabilityDays: 1 }];
+      config.minimumReleaseAge = '6 days';
+      config.packageRules = [
+        { matchUpdateTypes: ['patch'], minimumReleaseAge: '1 day' },
+      ];
       const res = await filterInternalChecks(
         config,
         versioning,
@@ -141,9 +144,9 @@ describe('workers/repository/process/lookup/filter-checks', () => {
       expect(res.release.version).toBe('1.0.4');
     });
 
-    it('picks up stabilityDays settings from updateType', async () => {
+    it('picks up minimumReleaseAge settings from updateType', async () => {
       config.internalChecksFilter = 'strict';
-      config.patch = { stabilityDays: 4 };
+      config.patch = { minimumReleaseAge: '4 days' };
       const res = await filterInternalChecks(
         config,
         versioning,
diff --git a/lib/workers/repository/process/lookup/filter-checks.ts b/lib/workers/repository/process/lookup/filter-checks.ts
index 4cd6ac70f6150dd84aad17669484bda4c4e2efc8..83b625cffdf00f8c0aafe4dc4787b28c38e0db13 100644
--- a/lib/workers/repository/process/lookup/filter-checks.ts
+++ b/lib/workers/repository/process/lookup/filter-checks.ts
@@ -3,13 +3,14 @@ import { mergeChildConfig } from '../../../../config';
 import { logger } from '../../../../logger';
 import type { Release } from '../../../../modules/datasource';
 import type { VersioningApi } from '../../../../modules/versioning';
-import { getElapsedDays } from '../../../../util/date';
+import { getElapsedMs } from '../../../../util/date';
 import {
   getMergeConfidenceLevel,
   isActiveConfidenceLevel,
   satisfiesConfidenceLevel,
 } from '../../../../util/merge-confidence';
 import { applyPackageRules } from '../../../../util/package-rules';
+import { toMs } from '../../../../util/pretty-time';
 import type { LookupUpdateConfig, UpdateResult } from './types';
 import { getUpdateType } from './update-type';
 
@@ -30,7 +31,7 @@ export async function filterInternalChecks(
   let pendingChecks = false;
   let pendingReleases: Release[] = [];
   if (internalChecksFilter === 'none') {
-    // Don't care if stabilityDays or minimumConfidence are unmet
+    // Don't care if minimumReleaseAge or minimumConfidence are unmet
     release = sortedReleases.pop();
   } else {
     // iterate through releases from highest to lowest, looking for the first which will pass checks if present
@@ -51,19 +52,19 @@ export async function filterInternalChecks(
       );
       // Apply packageRules in case any apply to updateType
       releaseConfig = applyPackageRules(releaseConfig);
-      // Now check for a stabilityDays config
+      // Now check for a minimumReleaseAge config
       const {
         minimumConfidence,
-        stabilityDays,
+        minimumReleaseAge,
         releaseTimestamp,
         version: newVersion,
         updateType,
       } = releaseConfig;
-      if (is.integer(stabilityDays) && releaseTimestamp) {
-        if (getElapsedDays(releaseTimestamp) < stabilityDays) {
+      if (is.nonEmptyString(minimumReleaseAge) && releaseTimestamp) {
+        if (getElapsedMs(releaseTimestamp) < (toMs(minimumReleaseAge) ?? 0)) {
           // Skip it if it doesn't pass checks
           logger.trace(
-            { depName, check: 'stabilityDays' },
+            { depName, check: 'minimumReleaseAge' },
             `Release ${candidateRelease.version} is pending status checks`
           );
           pendingReleases.unshift(candidateRelease);
diff --git a/lib/workers/repository/process/lookup/index.spec.ts b/lib/workers/repository/process/lookup/index.spec.ts
index 10c963df82a8f1e0622f637f76f5ee99d3ebf28c..fb91a5467745b3411f5a04722ad77932e6f83c1b 100644
--- a/lib/workers/repository/process/lookup/index.spec.ts
+++ b/lib/workers/repository/process/lookup/index.spec.ts
@@ -1002,7 +1002,7 @@ describe('workers/repository/process/lookup/index', () => {
       config.currentValue = '1.4.4';
       config.packageName = 'some/action';
       config.datasource = GithubReleasesDatasource.id;
-      config.stabilityDays = 14;
+      config.minimumReleaseAge = '14 days';
       config.internalChecksFilter = 'strict';
       const yesterday = new Date();
       yesterday.setDate(yesterday.getDate() - 1);
@@ -1025,7 +1025,7 @@ describe('workers/repository/process/lookup/index', () => {
       config.currentValue = '1.4.4';
       config.packageName = 'some/action';
       config.datasource = GithubReleasesDatasource.id;
-      config.stabilityDays = 3;
+      config.minimumReleaseAge = '3 days';
       config.internalChecksFilter = 'strict';
       const yesterday = new Date();
       yesterday.setDate(yesterday.getDate() - 1);
diff --git a/lib/workers/repository/update/branch/index.spec.ts b/lib/workers/repository/update/branch/index.spec.ts
index 146312255a2e5227c111b3652a9b6088687d3909..0288741eab8ae73b3f966a003fabfc6a9da3332e 100644
--- a/lib/workers/repository/update/branch/index.spec.ts
+++ b/lib/workers/repository/update/branch/index.spec.ts
@@ -162,17 +162,17 @@ describe('workers/repository/update/branch/index', () => {
       });
     });
 
-    it('skips branch for fresh release with stabilityDays', async () => {
+    it('skips branch for fresh release with minimumReleaseAge', async () => {
       schedule.isScheduledNow.mockReturnValueOnce(true);
       config.prCreation = 'not-pending';
       (config.upgrades as Partial<BranchUpgradeConfig>[]) = [
         {
           releaseTimestamp: new Date('2019-01-01').getTime().toString(),
-          stabilityDays: 1,
+          minimumReleaseAge: '1 day',
         },
         {
           releaseTimestamp: new Date().toString(),
-          stabilityDays: 1,
+          minimumReleaseAge: '1 day',
         },
       ];
 
@@ -185,13 +185,13 @@ describe('workers/repository/update/branch/index', () => {
       });
     });
 
-    it('skips branch if not stabilityDays not met', async () => {
+    it('skips branch if minimumReleaseAge not met', async () => {
       schedule.isScheduledNow.mockReturnValueOnce(true);
       config.prCreation = 'not-pending';
       config.upgrades = partial<BranchUpgradeConfig>([
         {
           releaseTimestamp: '2099-12-31',
-          stabilityDays: 1,
+          minimumReleaseAge: '1 day',
         },
       ]);
       const res = await branchWorker.processBranch(config);
diff --git a/lib/workers/repository/update/branch/index.ts b/lib/workers/repository/update/branch/index.ts
index 188e5f31a1a666ea2084c471585a66115c6947b7..077e15eacb9b9b98ff47125f49f39c77ad2742fa 100644
--- a/lib/workers/repository/update/branch/index.ts
+++ b/lib/workers/repository/update/branch/index.ts
@@ -23,7 +23,7 @@ import {
 } from '../../../../modules/platform/comment';
 import { scm } from '../../../../modules/platform/scm';
 import { ExternalHostError } from '../../../../types/errors/external-host-error';
-import { getElapsedDays } from '../../../../util/date';
+import { getElapsedMs } from '../../../../util/date';
 import { emojify } from '../../../../util/emoji';
 import { checkoutBranch } from '../../../../util/git';
 import {
@@ -31,6 +31,7 @@ import {
   isActiveConfidenceLevel,
   satisfiesConfidenceLevel,
 } from '../../../../util/merge-confidence';
+import { toMs } from '../../../../util/pretty-time';
 import * as template from '../../../../util/template';
 import { isLimitReached } from '../../../global/limits';
 import type { BranchConfig, BranchResult, PrBlockedBy } from '../../../types';
@@ -280,25 +281,29 @@ export async function processBranch(
     if (
       config.upgrades.some(
         (upgrade) =>
-          (upgrade.stabilityDays && upgrade.releaseTimestamp) ||
+          (is.nonEmptyString(upgrade.minimumReleaseAge) &&
+            upgrade.releaseTimestamp) ||
           isActiveConfidenceLevel(upgrade.minimumConfidence!)
       )
     ) {
       // Only set a stability status check if one or more of the updates contain
-      // both a stabilityDays setting and a releaseTimestamp
+      // both a minimumReleaseAge setting and a releaseTimestamp
       config.stabilityStatus = 'green';
       // Default to 'success' but set 'pending' if any update is pending
       for (const upgrade of config.upgrades) {
-        if (is.number(upgrade.stabilityDays) && upgrade.releaseTimestamp) {
-          const daysElapsed = getElapsedDays(upgrade.releaseTimestamp);
-          if (daysElapsed < upgrade.stabilityDays) {
+        if (
+          is.nonEmptyString(upgrade.minimumReleaseAge) &&
+          upgrade.releaseTimestamp
+        ) {
+          const timeElapsed = getElapsedMs(upgrade.releaseTimestamp);
+          if (timeElapsed < (toMs(upgrade.minimumReleaseAge) ?? 0)) {
             logger.debug(
               {
                 depName: upgrade.depName,
-                daysElapsed,
-                stabilityDays: upgrade.stabilityDays,
+                timeElapsed,
+                minimumReleaseAge: upgrade.minimumReleaseAge,
               },
-              'Update has not passed stability days'
+              'Update has not passed minimum release age'
             );
             config.stabilityStatus = 'yellow';
             continue;
diff --git a/lib/workers/repository/update/branch/status-checks.ts b/lib/workers/repository/update/branch/status-checks.ts
index a880fc3a9e6e1e3826d25f9d51bfce9ce37ba282..6fe93414f0f6bef8df44e273525cd295e8d266aa 100644
--- a/lib/workers/repository/update/branch/status-checks.ts
+++ b/lib/workers/repository/update/branch/status-checks.ts
@@ -65,8 +65,8 @@ export async function setStability(config: StabilityConfig): Promise<void> {
   const context = `renovate/stability-days`;
   const description =
     config.stabilityStatus === 'green'
-      ? 'Updates have met stability days requirement'
-      : 'Updates have not met stability days requirement';
+      ? 'Updates have met minimum release age requirement'
+      : 'Updates have not met minimum release age requirement';
   await setStatusCheck(
     config.branchName,
     context,