使用date-fns格式化时长出现异常:额外小时问题求助
date-fns格式化时长时小时数异常偏多的问题
我在用date-fns格式化毫秒时长时遇到了异常,代码如下:
function formatDuration(duration) { return duration >= 60000 * 60 ? format(new Date(duration), "hh 'h', mm 'min', ss 'sec'") : duration >= 60000 ? format(new Date(duration), "mm 'min', ss 'sec'") : format(new Date(duration), "ss 'sec'"); }
预期输出:
formatDuration((59 * 60 + 59) * 1000); // '59 min, 59 sec' formatDuration((60 * 60) * 1000); // '01 h 00 min, 00 sec'
实际输出:
formatDuration((59 * 60 + 59) * 1000); // '59 min, 59 sec' formatDuration((60 * 60) * 1000); // '02 h 00 min, 00 sec'
第二种情况莫名多了1小时,求问题原因和解决办法。
问题原因
问题出在时区偏移上。当你用new Date(duration)创建日期对象时,这个时间对应的是1970年1月1日UTC时间加上duration毫秒后的时间点,但format方法默认使用本地时区解析这个日期。
比如你的本地时区是UTC+1(如欧洲中部时间),那么1970-01-01T01:00:00Z(UTC标准时间)对应的本地时间就是1970-01-01T02:00:00+01:00,所以format解析出来的小时数就是2,而非预期的1。
解决办法
有两种可靠的处理方式:
方式一:使用date-fns的utcFormat方法
utcFormat会基于UTC时区解析日期,彻底规避本地时区的影响:
import { utcFormat } from 'date-fns'; function formatDuration(duration) { const formatter = duration >= 60000 * 60 ? utcFormat("hh 'h', mm 'min', ss 'sec'") : duration >= 60000 ? utcFormat("mm 'min', ss 'sec'") : utcFormat("ss 'sec'"); return formatter(new Date(duration)); }
方式二:直接计算时分秒(更推荐)
既然要格式化的是时长而非具体时间点,直接通过数学计算拆分时分秒会更准确,完全避免日期对象的时区问题:
function formatDuration(duration) { const totalSeconds = Math.floor(duration / 1000); const hours = Math.floor(totalSeconds / 3600); const minutes = Math.floor((totalSeconds % 3600) / 60); const seconds = totalSeconds % 60; if (hours > 0) { return `${String(hours).padStart(2, '0')} h, ${String(minutes).padStart(2, '0')} min, ${String(seconds).padStart(2, '0')} sec`; } else if (minutes > 0) { return `${String(minutes).padStart(2, '0')} min, ${String(seconds).padStart(2, '0')} sec`; } else { return `${String(seconds).padStart(2, '0')} sec`; } }
两种方式都能得到预期结果,第二种更适配时长格式化的场景,因为日期对象的核心用途是表示时间点而非时间段。
内容的提问来源于stack exchange,提问作者MathKimRobin
相关产品推荐
相关产品推荐

