Math.trunc()

ES6+

Returns the integer part of a number by removing all fractional digits, always rounding toward zero: Math.trunc(4.9) is 4 and Math.trunc(-4.9) is -4. Added in ES2015, it differs from Math.floor() only for negative inputs, and unlike bitwise tricks it works across the full double range.

Syntax

Math.trunc(x)

Parameters

x number

A number

Return Value

number

The integer part of the given number

Examples

JavaScript
console.log(Math.trunc(4.7));
console.log(Math.trunc(-4.7));
console.log(Math.trunc(0.123));
Output:
// 4 -4 0

📌 When to Use

Use Math.trunc() when "just drop the decimals" is genuinely the requirement, symmetric around zero: extracting the whole-unit part of signed quantities such as hours from fractional hours, whole dollars from a signed balance, or complete intervals from an elapsed-time difference that might be negative (a countdown that can pass zero). Because it rounds toward zero for both signs, trunc keeps magnitude relationships intuitive where floor would step negatives away from zero: splitting -3.7 hours into parts should give -3 hours and -42 minutes, which trunc-based decomposition delivers. It is also the honest replacement for two widespread hacks: parseInt(x) used on numbers (which stringifies its argument first, with famous failure modes) and (x | 0) (which silently wraps beyond 32-bit range). Reach for floor instead when doing bucket or index math on values that can be negative, tile coordinates, pagination of signed offsets, because buckets are floor-shaped by definition; and reach for round or ceil when the requirement is nearest or never-under. In duration formatting, trunc pairs with modulo to peel off units: total seconds to whole minutes and remaining seconds, as in the video-timestamp example below.

⚠️ Common Mistakes

Using parseInt() to truncate numbers: parseInt converts its argument to a string first, so parseInt(1e21) parses "1e+21" and returns 1, and parseInt(0.0000001) parses "1e-7" and returns 1 as well. parseInt is for parsing strings with a radix; Math.trunc is for numbers.

Confusing trunc with floor on negatives: Math.trunc(-4.7) is -4 while Math.floor(-4.7) is -5. Bucket math done with trunc double-counts the bucket around zero (indexes -0.9 through 0.9 all truncate to 0), a subtle bias in histogram and tile code that only negative data exposes.

Relying on (x | 0) or ~~x as "fast trunc": bitwise operators coerce to 32-bit integers, so (2 ** 31 | 0) is -2147483648 and 4294967296.5 | 0 is 0. Any value beyond ±2^31, timestamps, byte counts, view counts, wraps or zeroes silently.

Expecting an integer type out: the result is still a double, and beyond 2^53 (Number.MAX_SAFE_INTEGER) it may not even be the mathematically correct integer because the input itself could not represent one. Big magnitudes belong in BigInt.

Forgetting trunc preserves negative zero: Math.trunc(-0.5) is -0, which stringifies as "0" but fails Object.is(x, 0) and yields -Infinity under 1/x. Normalize with x + 0 (IEEE addition turns -0 into +0) if exact-zero identity matters downstream.

Truncating float artifacts: Math.trunc(4.35 * 100) is 434 because 4.35 * 100 is 434.99999999999994. Like every rounding-family function, trunc faithfully processes the error already present; scale in exact integers when decimals are involved.

✅ Best Practices

State intent with the function name: trunc for symmetric decimal-stripping, floor for bucketing, ceil for capacity, round for nearest. Reviewers should be able to infer the negative-value behavior you wanted from the call alone.

Decompose durations with trunc plus modulo: hours = Math.trunc(s / 3600), minutes = Math.trunc((s % 3600) / 60), seconds = Math.trunc(s % 60); the pattern extends to days and milliseconds and behaves sanely for negative countdowns.

Replace legacy parseInt-on-number and bitwise-truncation code during refactors; Math.trunc has none of their range or stringification traps and is equally fast in modern engines.

Guard the safe-integer boundary in data pipelines: Number.isSafeInteger(Math.trunc(x)) tells you whether the truncated value is trustworthy; beyond it, switch to BigInt for exact integer arithmetic.

When only display needs the integer part, consider Intl.NumberFormat with maximumFractionDigits: 0 instead of mutating the value, keeping state precise and formatting concerns at the edge.

⚡ Performance Notes

Math.trunc() is a single hardware round-toward-zero instruction once JIT-compiled, indistinguishable in cost from floor, ceil, and round; it allocates nothing and can run in the hottest loops, audio sample processing, per-pixel work, without registering in a profile. The historical motivation for (x | 0), meaningful speed on pre-2015 engines, no longer holds: engines inline Math.trunc to the same machine code while preserving full double range, so the bitwise form is now purely a correctness liability outside proven-int32 inner kernels (where it can still help the JIT keep values in integer registers). parseInt, by contrast, is dramatically slower on numbers because of the number-to-string-to-number round trip, in addition to being wrong at the extremes; eliminating it from numeric paths is both a correctness and a performance cleanup.

🌍 Real World Example

Video Timestamp Formatter

Media players display 3725.84 seconds as 1:02:05, and this example performs that conversion with the standard trunc-and-modulo cascade: whole hours, then remaining whole minutes, then remaining whole seconds, each padded for display. Truncation (not rounding) is correct here because a player at 4.9 seconds is still in second 4; rounding would make the clock jump early. The identical decomposition formats workout timers, call durations, and estimated time remaining in upload progress bars.

function formatDuration(totalSeconds) {
  const hours = Math.trunc(totalSeconds / 3600);
  const minutes = Math.trunc((totalSeconds % 3600) / 60);
  const seconds = Math.trunc(totalSeconds % 60);

  const pad = (n) => String(n).padStart(2, '0');

  if (hours > 0) {
    return `${hours}:${pad(minutes)}:${pad(seconds)}`;
  }
  return `${minutes}:${pad(seconds)}`;
}

console.log(formatDuration(3725.8)); // "1:02:05"
console.log(formatDuration(185.4));  // "3:05"

Related Methods