
Time Duration Calculator
Add, subtract, and convert time durations. Timesheet calculator, multi-duration sum, and time difference tool.
Last reviewed: April 2026New to this tool? Click here for instructions
Enter durations in HH:MM:SS, HH:MM, or seconds. Use + or - operator per row.
Compute the elapsed time between two timestamps, sum or subtract a list of durations, and convert ISO 8601 duration strings to and from human-readable form β all in your browser, with no data sent over the network.
What This Tool Does
The Time Duration Calculator handles three distinct categories of time arithmetic that most general-purpose date pickers conflate. First, it computes the difference between two timestamps and breaks the result down into years, months, weeks, days, hours, minutes, and seconds β including the same elapsed time expressed in each unit independently (so you can see both "1 year, 10 months, 5 days" and "678 days" for the same span). Second, it sums and subtracts duration values entered as HH:MM:SS, decimal hours, or raw seconds, with per-row operator selection so you can chain additions and subtractions in any order. Third, it converts ISO 8601 duration strings like P1Y2M3DT4H5M to and from a human-readable breakdown, which is useful when working with PostgreSQL INTERVAL columns, JSON Schema constraints, or REST API contracts that emit ISO 8601 duration values directly.
Every computation runs client-side. The dates and durations you enter never leave your browser session β no analytics events capture them, no API request is made, and the page works fully offline once cached by the service worker. π
How to Use It
The interface is organized into four mode tabs at the top of the tool. Pick the mode that matches your task, fill in the inputs, and read the breakdown panel that appears below.
Picking a Mode
Start with the mode selector chips. Duration Sum adds and subtracts a list of duration values β use this when you want to total clip lengths, sum benchmark run times, or compute "total time minus break time" in a single pass. Time Difference takes a start time and an end time on the same day (with an Overnight option for cross-midnight spans) and returns the elapsed wall-clock duration. Convert takes a single duration value and shows it expressed in every common unit simultaneously. Timesheet accepts a list of (start, end) pairs β one per work session β and returns the total worked time across all sessions, automatically handling sessions that span midnight.
Entering Inputs
All four modes accept the same set of duration formats: HH:MM:SS (e.g., 01:30:45), HH:MM (e.g., 1:30), plain seconds as an integer (e.g., 5400), or decimal hours with an optional h suffix (e.g., 2.5h or 2.5). Leading zeros are optional β 1:30 and 01:30 parse identically. The Try Example button in each mode pre-loads realistic sample inputs so you can see the expected format at a glance before clearing them and entering your own values.
Reading the Breakdown
Once inputs are valid, the result panel displays the same duration expressed multiple ways: the canonical HH:MM:SS formatted value at the top, a row of unit-by-unit cards showing days/hours/minutes/seconds independently, and a conversion grid showing the duration as total minutes, total seconds, decimal hours, and milliseconds. The Copy Result button writes the canonical formatted value to your clipboard; the Download button saves it as a plain-text file. Both work without leaving the page.
Worked Example: Duration Between Two Timestamps
- Start
- 2023-03-15 09:30:00 UTC
- End
- 2025-01-20 17:45:00 UTC
- Goal
- Compute the elapsed duration and express it in calendar units (years, months, days) and absolute units (seconds, hours, weeks)
- Compute the absolute duration in seconds. The Unix timestamps for these two instants are 1,678,872,600 and 1,737,395,100. Subtracting gives 58,522,500 seconds β this is the unambiguous, calendar-free elapsed time.
- Convert to absolute units. 58,522,500 seconds is exactly 975,375 minutes, 16,256.25 hours, 677.34 days, or 96.76 weeks. These conversions are pure division by 60, 3,600, 86,400, and 604,800 respectively β no calendar logic involved.
- Compute the calendar breakdown. Walking forward from 2023-03-15: 2023-03-15 + 1 year = 2024-03-15 (still before end). 2024-03-15 + 10 months = 2025-01-15 (still before end). 2025-01-15 + 5 days = 2025-01-20 (now we are at the end-date day). The remaining time is the wall-clock difference 17:45:00 minus 09:30:00, which is 8 hours 15 minutes.
- Final calendar form. 1 year, 10 months, 5 days, 8 hours, 15 minutes β anchored to the start date.
- Or expressed as total months plus days. Equivalent to 22 months + 5 days + 8h 15min β same elapsed time, different unit decomposition.
- Or as a pure day count. 678 days, 8 hours, 15 minutes β counting whole calendar days plus the wall-clock remainder.
Why "months" is ambiguous. The calendar form "10 months" in step 3 means ten anchored calendar months, each of which has its own length (March has 31 days, April 30, etc.) β the total elapsed time depends on which months are spanned. If we naively converted "10 months" to "300 days" using a 30-day month approximation, we'd be off by several days. This is why two different applications can both correctly say "the duration between these timestamps is N months and M days" yet disagree on N and M when one uses calendar anchoring and the other uses 30-day approximation. Always pick a convention and document it; never mix.
| Representation | Value | Reference Required? |
|---|---|---|
| Calendar breakdown (anchored) | 1 year, 10 months, 5 days, 8h 15m | Yes β depends on start date |
| Months + days (anchored) | 22 months, 5 days, 8h 15m | Yes β depends on start date |
| Total days + remainder | 678 days, 8h 15m | No |
| Total weeks + remainder | 96 weeks, 6 days, 8h 15m | No |
| Total hours | 16,256.25 hours | No |
| Total seconds | 58,522,500 seconds | No |
| ISO 8601 duration (calendar) | P1Y10M5DT8H15M | Yes β calendar units depend on anchor |
Common Use Cases
Project Timeline Planning
Project managers use duration arithmetic to translate Gantt-chart start dates into end dates, slip dependencies forward when an upstream task slips, and compute the slack between a task's earliest-finish and latest-finish dates. The standard convention in PM software (Microsoft Project, OmniPlan, Asana timelines) is calendar-based duration with explicit business-day rules: "2 weeks" means 10 working days, skipping weekends and the project's holiday calendar. The Date Calculator handles the date-arithmetic side; this tool handles the duration-arithmetic side.
Payroll Period Calculations
Payroll engines compute wages by summing clocked work intervals β each one a (clock-in, clock-out) pair β for each pay period. The Timesheet mode is purpose-built for this: enter every session, see per-session durations as you go, and read the total at the bottom. The tool handles cross-midnight sessions automatically (a session clocking in at 23:30 and out at 07:30 the next morning is correctly totaled as 8 hours). For payroll periods that cross a DST boundary, see the Edge Cases section below β DST can silently subtract or add an hour to a shift if you work in local wall-clock time.
Software Release Cadence Reports
Engineering teams track time-between-releases as a key delivery metric. Subtracting two release timestamps gives raw elapsed time; the Duration Sum mode lets you average across multiple intervals to compute mean time between releases for a quarter. Site Reliability Engineering teams use a similar pattern for Mean Time To Recovery (MTTR) β summing recovery durations across incidents and dividing by incident count.
Age Calculation
"Age" is a duration between a birth date and a reference date (usually today). Conventional age reporting uses calendar years anchored at the birth date β you are 39 from your 39th birthday until the day before your 40th, regardless of whether the intervening year was 365 or 366 days long. Legal age-of-majority checks use the same anchoring rule. For demographic statistics, age in completed years is the standard; for actuarial and insurance calculations, fractional age (years plus the fraction of the current year completed) is used instead.
Scheduling Reminders
Calendar applications and reminder services translate "remind me 30 minutes before the meeting" into a notification timestamp by subtracting a duration from a target instant. The Convert mode is useful here for normalizing reminder offsets that arrive in mixed formats β your input system might accept "30 min", "0.5h", or "1800s" and you need to normalize them to a single canonical form before storage.
Comparing Benchmark Run Times
Performance benchmarking emits durations in microseconds, milliseconds, or seconds depending on the test suite. The Convert mode shows a duration in all standard units simultaneously, making side-by-side comparison straightforward. Combine with the Percentage Calculator to compute relative speed-ups: "the new implementation is X% faster than the baseline."
Edge Cases and Limitations
Date and duration arithmetic is full of subtle traps. The cases below are the ones most likely to bite you, and they are the reason mature production systems use a dedicated library rather than rolling their own with native Date.
Daylight Saving Time Transitions
Not every day is 24 hours long. On "spring forward" day in the United States (the second Sunday of March), local clocks skip from 02:00 directly to 03:00 β that calendar day has only 23 hours of elapsed wall-clock time. On "fall back" day (the first Sunday of November), clocks roll from 02:00 back to 01:00 and that day has 25 hours. Subtracting two local-time wall clocks across a DST boundary produces a misleading answer: 02:30 EST on Mar 9 to 03:30 EDT on the same Mar 9 looks like one hour but represents only thirty minutes of actual elapsed time. The fix is to always work in UTC for duration arithmetic, converting to local wall time only for display. Time zones with no DST observance (UTC, most of Asia, all of Africa except Morocco, all of South America except parts of Chile and Paraguay) sidestep this issue entirely.
Leap Years
Adding "one year" to 2023-02-28 gives 2024-02-28 in libraries that anchor to the same calendar day, even though there are 366 days between them rather than 365. Adding "one year" to 2024-02-29 is more contentious: libraries that use clamp-to-last-day return 2025-02-28; libraries that use rollover return 2025-03-01. The Gregorian leap-year rule is: divisible by 4, except divisible by 100, unless also divisible by 400 β so 2000 was a leap year, 1900 was not, and 2100 will not be.
Month-Length Variation
"One month after January 31" is undefined under naive arithmetic β February has only 28 or 29 days. The two conventions are clamp-to-last-day (Jan 31 + 1 month = Feb 28 or Feb 29, depending on leap year) and rollover (Jan 31 + 1 month = Mar 3 in a non-leap year, treating the extra 3 days as overflow past month-end). JavaScript's native Date uses rollover; date-fns, Luxon, and the Temporal proposal use clamp-to-last-day. This is the most common source of off-by-one bugs in calendar arithmetic. Financial systems that emit monthly invoices on the 31st of each month typically use clamp-to-last-day for non-31-day months, falling back to the last day of the shorter month.
Timezone Confusion
The cardinal rule of duration arithmetic: always work in UTC, convert to local time only for display. A meeting scheduled for "Wednesday 14:00" in New York and "Wednesday 19:00" in London is the same instant β but two systems that store the local wall-clock string instead of the UTC instant will disagree about the meeting time after a DST transition in either zone. The IANA timezone database (also called the tz database or Olson database) is the canonical source for timezone offsets and DST rules; libraries like Luxon and the Temporal proposal use it directly, while older libraries embed snapshot data that goes stale when a country changes its DST rules.
ISO 8601 Weeks
ISO 8601 defines a week-numbering scheme distinct from the U.S. convention. Week 01 of any ISO year is the week containing the first Thursday of January, equivalently the week containing January 4. ISO weeks start on Monday and run through Sunday. This means a date can have an ISO year different from its calendar year: December 31, 2018 falls in ISO week 2019-W01 because the week containing Jan 1, 2019 (a Tuesday) starts on Mon Dec 31, 2018. Financial and scientific reporting in Europe uses ISO weeks; U.S. reporting often uses CDC weeks (epi weeks), which start on Sunday and number differently. Mixing the two conventions in the same dataset is a frequent source of off-by-one bugs.
Julian vs Gregorian for Historical Dates
The Gregorian calendar was introduced by Pope Gregory XIII in October 1582 as a refinement to the Julian calendar (the leap-year rule was tightened to drop three leap days every 400 years). Different countries adopted Gregorian at different times β Catholic countries in 1582, Britain and its American colonies in 1752, Russia in 1918, Greece in 1923. For dates before each region's adoption, the same calendar day can correspond to two different historical dates depending on whether you use Julian or Gregorian. ISO 8601 specifies the proleptic Gregorian calendar β applying Gregorian rules to all dates, including those before 1582 β and this is what JavaScript Date, Python datetime, and most modern libraries implement by default. For genealogical or historical research where primary sources used Julian dates at the time of recording, use a library like js-joda that supports both calendars explicitly. Astronomers use Julian Date (JD), a continuous day count starting at noon UT on Jan 1, 4713 BC proleptic Julian, which sidesteps calendar transitions entirely.
Behind the Scenes
ISO 8601 Duration Format
The ISO 8601 duration grammar is PnYnMnDTnHnMnS, where each n is a non-negative number and the leading P stands for "period." The T separator divides date-side units (years, months, days) from time-side units (hours, minutes, seconds). For example, P1Y2M3DT4H5M6S means 1 year, 2 months, 3 days, 4 hours, 5 minutes, 6 seconds. Weeks have a separate form (PnW) that cannot be combined with other units in the same string. Any unit can be omitted if its value is zero; fractional values are permitted only in the smallest unit present. This format appears in PostgreSQL INTERVAL serialization, JSON Schema duration validators, OpenAPI duration parameters, and the upcoming Temporal.Duration JavaScript built-in.
JavaScript Temporal API
Temporal is a Stage 3 TC39 proposal that adds a modern date-and-time API to JavaScript as a built-in. It separates Temporal.Instant (a specific point on the universal timeline, like a Unix timestamp with nanosecond precision), Temporal.ZonedDateTime (an instant paired with an IANA timezone), Temporal.PlainDate / PlainTime / PlainDateTime (calendar-only or wall-clock-only values with no timezone), and Temporal.Duration (a calendar-aware duration value). The split between Plain and Zoned types eliminates the most common bugs in legacy Date code, where every value was both an instant and a wall-clock time in the local zone, even when only one of those interpretations made sense. The polyfill @js-temporal/polyfill implements the full proposal for use today; native browser support is rolling out through 2026.
date-fns vs moment vs luxon vs dayjs
moment.js dominated client-side date handling for the better part of a decade but has been in maintenance mode since 2020. Its mutable API surface and large bundle size disqualify it from new projects. Luxon was written by a former Moment maintainer as a modern replacement β immutable, full IANA timezone support, built on the browser's Intl API. date-fns takes a different design approach: every operation is a standalone function imported individually, enabling aggressive tree-shaking; typical apps ship 8β15 KB of date-fns even when using dozens of functions. Day.js reimplements Moment's API surface in a fraction of the bundle size (~2 KB core), useful when migrating Moment code that you don't want to rewrite. For new projects in 2026, the recommendation is: Temporal (with polyfill) for new code that can adopt the modern API, Luxon when full IANA timezone work is required, date-fns when bundle size dominates.
The IANA Timezone Database
The IANA Time Zone Database (tzdb) is the authoritative source for historical and future timezone offsets, DST transitions, and political timezone changes. It is maintained by the Internet Assigned Numbers Authority and updated several times per year as countries change DST rules. Each timezone is identified by a Region/City string like America/New_York or Europe/London. Modern JavaScript date libraries query the browser's bundled tzdb via the Intl.DateTimeFormat API; older libraries that embed their own tzdb snapshot must publish a new release every time a country changes its rules. Long-running applications that store future timestamps (calendar events scheduled years out) should store the IANA zone alongside the wall-clock time, not the resolved UTC instant β because if the country changes its DST rules between now and then, only the zone-anchored representation survives the change correctly.
Why Native Date Has Issues with Months
JavaScript's native Date is a thin wrapper around a Unix-timestamp integer plus the host operating system's local timezone, with a mutable API that conflates instant, wall-clock time, and calendar arithmetic. The month-rollover quirk is the most-cited example: new Date(2023, 12, 0) returns December 31, 2023 because month 12 (which would be invalid as January is month 0) is interpreted as "January of the following year" and day 0 as "the day before January 1," giving December 31. This is a documented behavior, not a bug, but it makes naive month addition unreliable: d.setMonth(d.getMonth() + 1) applied to January 31 yields March 3 (rollover convention), not February 28. Every modern library replaces this with explicit clamp-to-last-day or rollover behavior chosen at the call site. Temporal's Temporal.PlainDate.add({months: 1}) defaults to clamp-to-last-day and accepts an overflow: 'reject' option to error out on ambiguous additions instead of silently picking a convention.
Comparison: This Tool vs Wolfram Alpha vs date vs dateutil vs JS Temporal
Several mature tools handle duration arithmetic, each optimized for a different audience and workflow. The table below summarizes when each excels.
| Tool | Strengths | Weaknesses | Best For |
|---|---|---|---|
| This calculator | Browser-only, no install; ISO 8601 in/out; multiple unit decompositions side-by-side; timesheet mode | No timezone-aware date arithmetic; no business-day calendar | Quick lookups, format normalization, payroll-style timesheets, learning the difference between calendar and absolute durations |
| Wolfram Alpha | Natural-language input ("days between July 4 1776 and today"); historical Julian/Gregorian aware; cites astronomy and physics units | Network round-trip per query; rate-limited on free tier; opaque about which convention it chose for ambiguous inputs | One-off queries, historical dates, exotic unit conversions, classroom demonstrations |
Unix date command |
Universally installed; scriptable; supports POSIX %s Unix timestamps directly |
BSD vs GNU flag incompatibility (macOS vs Linux); no built-in ISO 8601 duration parsing | Shell scripting, CI/CD pipelines, server-side timestamp arithmetic |
Python dateutil.relativedelta |
Clean Python API for calendar-aware deltas; handles month-end rollover correctly; integrates with stdlib datetime |
Requires Python install; not browser-runnable; mixes absolute and calendar units in one object | Data analysis notebooks, ETL pipelines, anywhere Python already runs |
JavaScript Temporal |
Modern API design; separates absolute (Instant) from calendar (PlainDate); explicit overflow controls |
Native browser support still rolling out (2026); polyfill adds ~50 KB; learning curve for legacy Date developers |
New JavaScript apps that need correctness, especially around timezones and month arithmetic |
Frequently Asked Questions
Why does adding 1 month to Jan 31 not give Feb 31?
February has only 28 or 29 days, so Feb 31 does not exist as a calendar date. Date libraries handle this overflow in one of two conventions: clamp-to-last-day (Jan 31 + 1 month = Feb 28 or Feb 29) or rollover (Jan 31 + 1 month = Mar 3, treating the extra days as additional days past month-end). JavaScript's native Date object uses rollover; date-fns, Luxon, and the Temporal proposal use clamp-to-last-day. This is the single most common source of off-by-one bugs in calendar arithmetic, and is why financial systems and payroll engines store dates as discrete (year, month, day) tuples and apply explicit business rules rather than relying on naive month addition.
What is the ISO 8601 duration format?
ISO 8601 represents a duration as a string starting with P (period), with year/month/week/day fields before an optional T separator and hour/minute/second fields after it. The full grammar is PnYnMnDTnHnMnS β for example, P1Y2M3DT4H5M6S means 1 year, 2 months, 3 days, 4 hours, 5 minutes, 6 seconds. Weeks are represented exclusively as PnW and cannot be combined with other units in the same string. Fractional values are permitted only in the smallest unit present. The format is used in PostgreSQL interval types, JSON Schema durations, JavaScript Temporal.Duration, and many REST API contracts.
How do leap years affect duration?
A leap year inserts a 29th day in February, making the year 366 days instead of 365. The Gregorian rule is: every year divisible by 4 is a leap year, except century years divisible by 100 are not, except century years divisible by 400 are. So 2000 was a leap year, 1900 was not, and 2100 will not be. Duration arithmetic that crosses a Feb 29 must account for this: subtracting Feb 28 of year N from Mar 1 of year N+1 yields either 365 or 366 days depending on whether year N+1 is a leap year. For "years between two dates" computations, libraries typically count calendar years (anniversary-based) rather than dividing total days by 365.25.
Should I use moment.js?
No. Moment.js has been in maintenance mode since September 2020 β the maintainers explicitly recommend new projects use a modern alternative. Moment's mutable API surface, large bundle size (~70 KB minified for the full locale set), and lack of tree-shaking made it unsuitable for modern web app budgets. Replacement choices, in rough order of recommendation: Temporal (the upcoming JavaScript built-in, Stage 3 proposal, polyfillable today via @js-temporal/polyfill); Luxon (written by a former Moment maintainer, immutable, IANA timezone support); date-fns (modular, function-per-file, excellent tree-shaking, ~12 KB typical use); Day.js (Moment-compatible API with a much smaller footprint, ~2 KB core). For new code in 2026, prefer Temporal directly if you can polyfill, otherwise Luxon for full timezone work or date-fns for tree-shaken builds.
Why does DST mess up duration math?
Daylight Saving Time transitions create days that are not 24 hours long. On "spring forward" day (typically the second Sunday of March in the U.S.), local clocks skip from 02:00 directly to 03:00 β that calendar day has only 23 hours of elapsed wall-clock time. On "fall back" day, clocks roll from 02:00 back to 01:00, and that day has 25 hours. Subtracting two local-time wall clocks across a DST boundary gives a misleading result: the wall-clock difference between Mar 9 at 02:30 EST and Mar 9 at 03:30 EDT looks like one hour but only thirty minutes of actual time elapsed (because the 02:30 instant never occurred in EDT). The fix is to always convert both timestamps to UTC before subtracting, or to use a library that tracks DST offsets per IANA timezone.
What's the difference between calendar and absolute duration?
An absolute duration is a fixed quantity of seconds β it does not depend on a reference date. P1D as absolute duration is exactly 86,400 seconds, full stop. A calendar duration is anchored to a starting date and uses calendar units (years, months) whose length depends on where you start. P1M starting Feb 1 is 28 or 29 days; P1M starting Mar 1 is 31 days. Both are valid "one month" but they measure different total elapsed time. ISO 8601 mixes both kinds in a single string. JavaScript Temporal makes the distinction explicit: Temporal.Duration is calendar-aware and requires a reference point to resolve to seconds, while Temporal.Instant.until() returns an absolute duration in seconds/nanoseconds.
Can I compute business days only?
Yes, but not with naive date subtraction β business-day arithmetic requires skipping weekends and a holiday calendar. The algorithm is straightforward: iterate day-by-day from start to end, increment a counter only when the date's weekday is MonβFri and the date is not in your holiday set. Libraries with built-in support include date-fns (eachWeekendOfInterval, isWeekend), Luxon (no native business-day method but easy via .weekday), and bespoke packages like @bbob/business-day for region-specific holiday calendars. Note that "business days" is jurisdiction-specific: U.S. federal holidays, U.K. bank holidays, and Japanese national holidays differ significantly, and even within one country some industries (banking vs. retail vs. government) observe different holiday sets.
How do I handle pre-Gregorian dates?
The Gregorian calendar was introduced in October 1582 by Pope Gregory XIII as a refinement to the Julian calendar. Different countries adopted it at different times β Catholic countries in 1582, Britain and its American colonies in 1752, Russia in 1918. For dates before adoption, applications typically use one of three conventions. The proleptic Gregorian calendar extends Gregorian rules backward, treating pre-1582 dates as if Gregorian were always in effect; this is what ISO 8601 specifies and what JavaScript Date implements. The Julian calendar uses Julian leap-year rules (every 4 years, no centennial correction). The historical approach uses Julian dates before each region's adoption and Gregorian after, which matches how dates appear in primary historical sources. Astronomers use Julian Date (JD), a continuous day count starting Jan 1, 4713 BC. For genealogy or historical research, libraries like js-joda offer all three conventions; for everyday work, proleptic Gregorian is the safe default.