diff --git a/README.md b/README.md
index 7d34549e..418e7cdd 100644
--- a/README.md
+++ b/README.md
@@ -47,6 +47,7 @@ Now you can use the pipes, see below.
 - [Unit pipe](#unit-pipe)
 - [List pipe](#list-pipe)
 - [Relative Time (timeago) pipe](#relative-time-timeago-pipe)
+- [Duration pipe](#duration-pipe)
 
 ### Date pipe
 
@@ -271,6 +272,27 @@ The following options are supported:
 
 With the `INTL_RELATIVE_TIME_PIPE_DEFAULT_OPTIONS` injection token you can specify default options.
 
+## Duration pipe
+
+Use the duration pipe like the following:
+
+```
+{{ { hours: 2, minutes: 53 } | intlDuration: options }}
+```
+
+The input can be one of the following:
+
+- [duration object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DurationFormat/format#parameters)
+- null
+- undefined
+
+The following options are supported:
+
+- [`style`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DurationFormat/DurationFormat#style)
+- [`fractionalDigits`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DurationFormat/DurationFormat#fractionalDigits)
+
+For each duration unit, there is a style and display option.
+
 ## Browser compatibility
 
 This library supports the latest major version of the following browsers:
@@ -294,6 +316,7 @@ In case you need to support older versions of that browsers, see the below table
 | Unit          | 77     | 78      | 14.1   |
 | List          | 72     | 78      | 14.1   |
 | Relative Time | 71     | 65      | 14     |
+| Duration      | 129    | 136     | 16.4   |
 
 ## Angular compatibility table
 
diff --git a/projects/angular-ecmascript-intl/src/lib/duration/intl-duration-pipe-default-options.ts b/projects/angular-ecmascript-intl/src/lib/duration/intl-duration-pipe-default-options.ts
new file mode 100644
index 00000000..751960d3
--- /dev/null
+++ b/projects/angular-ecmascript-intl/src/lib/duration/intl-duration-pipe-default-options.ts
@@ -0,0 +1,6 @@
+import { InjectionToken } from '@angular/core';
+import { IntlDurationPipeOptions } from './intl-duration.pipe';
+
+export const INTL_DURATION_PIPE_DEFAULT_OPTIONS = new InjectionToken<
+  Omit<IntlDurationPipeOptions, 'locale'>
+>('IntlDurationPipeDefaultOptions');
diff --git a/projects/angular-ecmascript-intl/src/lib/duration/intl-duration.pipe.spec.ts b/projects/angular-ecmascript-intl/src/lib/duration/intl-duration.pipe.spec.ts
new file mode 100644
index 00000000..a21135f4
--- /dev/null
+++ b/projects/angular-ecmascript-intl/src/lib/duration/intl-duration.pipe.spec.ts
@@ -0,0 +1,155 @@
+import { TestBed } from '@angular/core/testing';
+import { INTL_LOCALES } from '../locale';
+import { INTL_DURATION_PIPE_DEFAULT_OPTIONS } from './intl-duration-pipe-default-options';
+import { IntlDurationPipe } from './intl-duration.pipe';
+
+describe('IntlDurationPipe', () => {
+  let testUnit: IntlDurationPipe;
+
+  describe('parsing', () => {
+    beforeEach(() => {
+      TestBed.runInInjectionContext(() => {
+        testUnit = new IntlDurationPipe();
+        Object.defineProperty(testUnit, 'locale', { value: 'en-US' });
+      });
+    });
+
+    it('should create an instance', () => {
+      expect(testUnit).toBeTruthy();
+    });
+
+    it('should handle null values', () => {
+      expect(testUnit.transform(null)).toBeNull();
+    });
+
+    it('should handle undefined values', () => {
+      expect(testUnit.transform(undefined)).toBeNull();
+    });
+
+    it('should transform durations', () => {
+      expect(
+        testUnit.transform({
+          years: 2,
+          months: 11,
+          weeks: 2,
+          days: 1,
+          hours: 0,
+          minutes: 55,
+          seconds: 19,
+          milliseconds: 940,
+          microseconds: 10,
+          nanoseconds: 3,
+        }),
+      ).toEqual(
+        '2 yrs, 11 mths, 2 wks, 1 day, 55 min, 19 sec, 940 ms, 10 μs, 3 ns',
+      );
+    });
+
+    it('should handle missing Intl.NumberFormat browser API', () => {
+      // @ts-expect-error Intl APIs are not expected to be undefined
+      spyOn(Intl, 'DurationFormat').and.returnValue(undefined);
+      const consoleError = spyOn(console, 'error');
+      expect(testUnit.transform({ years: 1 })).toBeNull();
+
+      expect(consoleError).toHaveBeenCalledTimes(1);
+    });
+  });
+
+  describe('internationalization', () => {
+    it('should respect the set locale', () => {
+      TestBed.configureTestingModule({
+        providers: [
+          {
+            provide: INTL_LOCALES,
+            useValue: 'de-DE',
+          },
+        ],
+      });
+      TestBed.runInInjectionContext(() => (testUnit = new IntlDurationPipe()));
+
+      expect(testUnit.transform({ years: 1 })).toEqual('1 J');
+    });
+
+    it('should fall back to the browser default locale', () => {
+      let defaultLanguageTestUnit!: IntlDurationPipe;
+      let browserLanguageTestUnit!: IntlDurationPipe;
+
+      TestBed.runInInjectionContext(() => {
+        defaultLanguageTestUnit = new IntlDurationPipe();
+        browserLanguageTestUnit = new IntlDurationPipe();
+        Object.defineProperty(browserLanguageTestUnit, 'locale', {
+          value: undefined,
+        });
+        Object.defineProperty(defaultLanguageTestUnit, 'locale', {
+          value: navigator.language,
+        });
+      });
+
+      const result1 = browserLanguageTestUnit.transform({ years: 1 });
+      const result2 = defaultLanguageTestUnit.transform({ years: 1 });
+
+      expect(result1).toEqual(result2);
+    });
+  });
+
+  describe('options', () => {
+    it('should respect the setting from default config', () => {
+      TestBed.configureTestingModule({
+        providers: [
+          {
+            provide: INTL_LOCALES,
+            useValue: 'en-US',
+          },
+          {
+            provide: INTL_DURATION_PIPE_DEFAULT_OPTIONS,
+            useValue: {
+              style: 'long',
+            },
+          },
+        ],
+      });
+      TestBed.runInInjectionContext(() => (testUnit = new IntlDurationPipe()));
+
+      expect(testUnit.transform({ years: 1 })).toEqual('1 year');
+    });
+
+    it('should give the user options a higher priority', () => {
+      TestBed.configureTestingModule({
+        providers: [
+          IntlDurationPipe,
+          {
+            provide: INTL_LOCALES,
+            useValue: 'en-US',
+          },
+          {
+            provide: INTL_DURATION_PIPE_DEFAULT_OPTIONS,
+            useValue: {
+              style: 'long',
+            },
+          },
+        ],
+      });
+      TestBed.runInInjectionContext(() => (testUnit = new IntlDurationPipe()));
+
+      expect(testUnit.transform({ years: 1 }, { style: 'narrow' })).toEqual(
+        '1y',
+      );
+    });
+  });
+
+  it('should respect locale option', () => {
+    TestBed.configureTestingModule({
+      providers: [
+        {
+          provide: INTL_LOCALES,
+          useValue: 'en-US',
+        },
+      ],
+    });
+    TestBed.runInInjectionContext(() => (testUnit = new IntlDurationPipe()));
+
+    expect(testUnit.transform({ years: 1 }, { locale: 'de-DE' })).toEqual(
+      '1 J',
+    );
+  });
+});
diff --git a/projects/angular-ecmascript-intl/src/lib/duration/intl-duration.pipe.ts b/projects/angular-ecmascript-intl/src/lib/duration/intl-duration.pipe.ts
new file mode 100644
index 00000000..e50f0e95
--- /dev/null
+++ b/projects/angular-ecmascript-intl/src/lib/duration/intl-duration.pipe.ts
@@ -0,0 +1,90 @@
+import { inject, Pipe, PipeTransform } from '@angular/core';
+import { IntlPipeOptions } from '../intl-pipe-options';
+import { INTL_LOCALES } from '../locale';
+import { INTL_DURATION_PIPE_DEFAULT_OPTIONS } from './intl-duration-pipe-default-options';
+
+// ToDo: remove once TypeScript includes official typings
+// eslint-disable-next-line @typescript-eslint/no-namespace
+declare namespace Intl {
+  export class DurationFormat {
+    constructor(locale?: string[] | string, options?: DurationFormatOptions);
+
+    format(duration: Duration): string;
+  }
+
+  export interface DurationFormatOptions {
+    style?: DurationItemStyle | 'digital';
+    years?: DurationItemStyle;
+    yearsDisplay?: DurationItemDisplay;
+    months?: DurationItemStyle;
+    monthsDisplay?: DurationItemDisplay;
+    weeks?: DurationItemStyle;
+    weeksDisplay?: DurationItemDisplay;
+    days?: DurationItemStyle;
+    daysDisplay?: DurationItemDisplay;
+    hours?: DurationItemStyle | 'numeric' | '2-digit';
+    hoursDisplay?: DurationItemDisplay;
+    minutes?: DurationItemStyle | 'numeric' | '2-digit';
+    minutesDisplay?: DurationItemDisplay;
+    seconds?: DurationItemStyle | 'numeric' | '2-digit';
+    secondsDisplay?: DurationItemDisplay;
+    milliseconds?: DurationItemStyle | 'numeric' | '2-digit';
+    millisecondsDisplay?: DurationItemDisplay;
+    microseconds?: DurationItemStyle | 'numeric';
+    microsecondsDisplay?: DurationItemDisplay;
+    nanoseconds?: DurationItemStyle | 'numeric';
+    nanosecondsDisplay?: DurationItemDisplay;
+    fractionalDigits?: number;
+  }
+
+  export type DurationItemStyle = 'long' | 'short' | 'narrow';
+  export type DurationItemDisplay = 'always' | 'auto';
+
+  export interface Duration {
+    years?: number;
+    months?: number;
+    weeks?: number;
+    days?: number;
+    hours?: number;
+    minutes?: number;
+    seconds?: number;
+    milliseconds?: number;
+    microseconds?: number;
+    nanoseconds?: number;
+  }
+}
+
+export type IntlDurationPipeOptions = Partial<Intl.DurationFormatOptions> &
+  IntlPipeOptions;
+
+@Pipe({
+  name: 'intlDuration',
+  standalone: true,
+})
+export class IntlDurationPipe implements PipeTransform {
+  readonly locale = inject(INTL_LOCALES, { optional: true });
+  readonly defaultOptions = inject(INTL_DURATION_PIPE_DEFAULT_OPTIONS, {
+    optional: true,
+  });
+
+  transform(
+    value: Intl.Duration | null | undefined,
+    options?: IntlDurationPipeOptions,
+  ): string | null {
+    if (!value) {
+      return null;
+    }
+
+    const { locale, ...intlOptions } = options ?? {};
+
+    try {
+      return new Intl.DurationFormat(locale ?? this.locale ?? undefined, {
+        ...this.defaultOptions,
+        ...intlOptions,
+      }).format(value);
+    } catch (e) {
+      console.error('Error while transforming the duration value', e);
+      return null;
+    }
+  }
+}
diff --git a/projects/angular-ecmascript-intl/src/lib/intl.module.ts b/projects/angular-ecmascript-intl/src/lib/intl.module.ts
index 56cb9147..17df0cb7 100644
--- a/projects/angular-ecmascript-intl/src/lib/intl.module.ts
+++ b/projects/angular-ecmascript-intl/src/lib/intl.module.ts
@@ -3,6 +3,7 @@ import { IntlCountryPipe } from './country/intl-country.pipe';
 import { IntlCurrencyPipe } from './currency/intl-currency.pipe';
 import { IntlDatePipe } from './date/intl-date.pipe';
 import { IntlDecimalPipe } from './decimal/intl-decimal.pipe';
+import { IntlDurationPipe } from './duration/intl-duration.pipe';
 import { IntlLanguagePipe } from './language/intl-language.pipe';
 import { IntlListPipe } from './list/intl-list.pipe';
 import { IntlPercentPipe } from './percent/intl-percent.pipe';
@@ -20,6 +21,7 @@ import { IntlUnitPipe } from './unit/intl-unit.pipe';
     IntlUnitPipe,
     IntlListPipe,
     IntlRelativeTimePipe,
+    IntlDurationPipe,
   ],
   exports: [
     IntlDatePipe,
@@ -31,6 +33,7 @@ import { IntlUnitPipe } from './unit/intl-unit.pipe';
     IntlUnitPipe,
     IntlListPipe,
     IntlRelativeTimePipe,
+    IntlDurationPipe,
   ],
 })
 export class IntlModule {}
diff --git a/projects/angular-ecmascript-intl/src/public-api.ts b/projects/angular-ecmascript-intl/src/public-api.ts
index 6d520d86..5be1eaf9 100644
--- a/projects/angular-ecmascript-intl/src/public-api.ts
+++ b/projects/angular-ecmascript-intl/src/public-api.ts
@@ -10,6 +10,8 @@ export * from './lib/date/intl-date-pipe-default-options';
 export * from './lib/date/intl-date.pipe';
 export * from './lib/decimal/intl-decimal-pipe-default-options';
 export * from './lib/decimal/intl-decimal.pipe';
+export * from './lib/duration/intl-duration-pipe-default-options';
+export * from './lib/duration/intl-duration.pipe';
 export * from './lib/intl.module';
 export * from './lib/language/intl-language-pipe-default-options';
 export * from './lib/language/intl-language.pipe';
diff --git a/projects/angular-intl-demo/src/app/pipes/duration/duration.component.html b/projects/angular-intl-demo/src/app/pipes/duration/duration.component.html
new file mode 100644
index 00000000..bbd846c5
--- /dev/null
+++ b/projects/angular-intl-demo/src/app/pipes/duration/duration.component.html
@@ -0,0 +1,76 @@
+<div class="fields-container">
+  <mat-form-field>
+    <mat-label>Years</mat-label>
+    <input matInput type="number" [(ngModel)]="years" />
+  </mat-form-field>
+
+  <mat-form-field>
+    <mat-label>Months</mat-label>
+    <input matInput type="number" [(ngModel)]="months" />
+  </mat-form-field>
+
+  <mat-form-field>
+    <mat-label>Weeks</mat-label>
+    <input matInput type="number" [(ngModel)]="weeks" />
+  </mat-form-field>
+
+  <mat-form-field>
+    <mat-label>Days</mat-label>
+    <input matInput type="number" [(ngModel)]="days" />
+  </mat-form-field>
+
+  <mat-form-field>
+    <mat-label>Hours</mat-label>
+    <input matInput type="number" [(ngModel)]="hours" />
+  </mat-form-field>
+
+  <mat-form-field>
+    <mat-label>Minutes</mat-label>
+    <input matInput type="number" [(ngModel)]="minutes" />
+  </mat-form-field>
+
+  <mat-form-field>
+    <mat-label>Seconds</mat-label>
+    <input matInput type="number" [(ngModel)]="seconds" />
+  </mat-form-field>
+
+  <mat-form-field>
+    <mat-label>Milliseconds</mat-label>
+    <input matInput type="number" [(ngModel)]="milliseconds" />
+  </mat-form-field>
+
+  <mat-form-field>
+    <mat-label>Microseconds</mat-label>
+    <input matInput type="number" [(ngModel)]="microseconds" />
+  </mat-form-field>
+
+  <mat-form-field>
+    <mat-label>Nanoseconds</mat-label>
+    <input matInput type="number" [(ngModel)]="nanoseconds" />
+  </mat-form-field>
+
+  <mat-form-field>
+    <mat-label>Locale</mat-label>
+    <mat-select [(ngModel)]="locale">
+      <mat-option [value]="undefined">Browser default</mat-option>
+      @for (language of languages; track $index) {
+        <mat-option [value]="language">{{ language }}</mat-option>
+      }
+    </mat-select>
+  </mat-form-field>
+
+  <mat-form-field>
+    <mat-label>Style</mat-label>
+    <mat-select [(ngModel)]="style">
+      <mat-option [value]="undefined">Browser default</mat-option>
+      <mat-option [value]="'long'">long</mat-option>
+      <mat-option [value]="'short'">short</mat-option>
+      <mat-option [value]="'narrow'">narrow</mat-option>
+      <mat-option [value]="'digital'">digital</mat-option>
+    </mat-select>
+  </mat-form-field>
+</div>
+
+<p>
+  {{ value() | intlDuration: options() }}
+</p>
diff --git a/projects/angular-intl-demo/src/app/pipes/duration/duration.component.scss b/projects/angular-intl-demo/src/app/pipes/duration/duration.component.scss
new file mode 100644
index 00000000..e6d6435c
--- /dev/null
+++ b/projects/angular-intl-demo/src/app/pipes/duration/duration.component.scss
@@ -0,0 +1,11 @@
+.fields-container {
+  display: flex;
+  gap: 16px;
+  flex-wrap: wrap;
+  align-items: flex-start;
+  margin-bottom: 16px;
+
+  mat-form-field {
+    min-width: 250px;
+  }
+}
diff --git a/projects/angular-intl-demo/src/app/pipes/duration/duration.component.ts b/projects/angular-intl-demo/src/app/pipes/duration/duration.component.ts
new file mode 100644
index 00000000..714ee71a
--- /dev/null
+++ b/projects/angular-intl-demo/src/app/pipes/duration/duration.component.ts
@@ -0,0 +1,55 @@
+import { CommonModule } from '@angular/common';
+import { Component, computed, signal } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { MatFormFieldModule } from '@angular/material/form-field';
+import { MatInputModule } from '@angular/material/input';
+import { MatSelectModule } from '@angular/material/select';
+import {
+  IntlDurationPipe,
+  IntlDurationPipeOptions,
+} from 'angular-ecmascript-intl';
+import { languages } from '../../languages';
+
+@Component({
+  selector: 'app-duration',
+  imports: [
+    CommonModule,
+    MatFormFieldModule,
+    MatSelectModule,
+    IntlDurationPipe,
+    FormsModule,
+    MatInputModule,
+  ],
+  templateUrl: './duration.component.html',
+  styleUrls: ['./duration.component.scss'],
+})
+export class DurationComponent {
+  languages = languages;
+  years = signal(5);
+  months = signal(2);
+  weeks = signal<number | undefined>(undefined);
+  days = signal(23);
+  hours = signal<number | undefined>(undefined);
+  minutes = signal<number | undefined>(undefined);
+  seconds = signal<number | undefined>(undefined);
+  milliseconds = signal<number | undefined>(undefined);
+  microseconds = signal<number | undefined>(undefined);
+  nanoseconds = signal<number | undefined>(undefined);
+  locale = signal<string | undefined>(undefined);
+  style = signal<IntlDurationPipeOptions['style']>(undefined);
+  value = computed(() => ({
+    years: this.years(),
+    months: this.months(),
+    weeks: this.weeks(),
+    days: this.days(),
+    hours: this.hours(),
+    minutes: this.minutes(),
+    seconds: this.seconds(),
+    milliseconds: this.milliseconds(),
+    microseconds: this.microseconds(),
+  }));
+  options = computed<IntlDurationPipeOptions>(() => ({
+    locale: this.locale(),
+    style: this.style(),
+  }));
+}
diff --git a/projects/angular-intl-demo/src/app/pipes/pipes.component.html b/projects/angular-intl-demo/src/app/pipes/pipes.component.html
index e4ae04cd..771ccec1 100644
--- a/projects/angular-intl-demo/src/app/pipes/pipes.component.html
+++ b/projects/angular-intl-demo/src/app/pipes/pipes.component.html
@@ -71,6 +71,14 @@
     routerLinkActive
     >Relative Time</a
   >
+  <a
+    #durationActive="routerLinkActive"
+    [active]="durationActive.isActive"
+    mat-tab-link
+    routerLink="duration"
+    routerLinkActive
+    >Duration</a
+  >
 </nav>
 <mat-tab-nav-panel #tabPanel></mat-tab-nav-panel>
 
diff --git a/projects/angular-intl-demo/src/app/pipes/pipes.routes.ts b/projects/angular-intl-demo/src/app/pipes/pipes.routes.ts
index 7c2eb2fe..593d09bb 100644
--- a/projects/angular-intl-demo/src/app/pipes/pipes.routes.ts
+++ b/projects/angular-intl-demo/src/app/pipes/pipes.routes.ts
@@ -3,6 +3,7 @@ import { CountryComponent } from './country/country.component';
 import { CurrencyComponent } from './currency/currency.component';
 import { DateComponent } from './date/date.component';
 import { DecimalComponent } from './decimal/decimal.component';
+import { DurationComponent } from './duration/duration.component';
 import { LanguageComponent } from './language/language.component';
 import { ListComponent } from './list/list.component';
 import { PercentComponent } from './percent/percent.component';
@@ -51,6 +52,10 @@ const routes: Routes = [
         path: 'relative-time',
         component: RelativeTimeComponent,
       },
+      {
+        path: 'duration',
+        component: DurationComponent,
+      },
       {
         path: '',
         redirectTo: 'date',