求助:使用DateComponentsFormatter计算日期差无法获取毫秒值
解决DateComponentsFormatter无法显示毫秒的问题
我懂你遇到的困扰——DateComponentsFormatter确实没办法直接帮你输出毫秒级的倒计时,原因很简单:它没有专门的「毫秒」单位选项,而且你设置的.nanosecond只会显示成纳秒(数值会是很大的数字,比如1毫秒=1e6纳秒),根本不符合你想要的“X毫秒”格式。
下面给你两种可行的解决方案,按需选择:
方案一:基于DateComponentsFormatter扩展,拼接毫秒部分
这个方案保留Formatter处理年、月、日等大单位的便捷性,只手动补充毫秒部分:
extension DateComponentsFormatter { func differenceWithMilliseconds(from fromDate: Date, to toDate: Date) -> String? { // 先让Formatter处理到秒的部分,忽略纳秒 self.allowedUnits = [.year, .month, .day, .hour, .minute, .second] self.maximumUnitCount = 6 self.unitsStyle = .full self.zeroFormattingBehavior = .dropAll // 自动隐藏值为0的单位 guard let secondsPart = self.string(from: fromDate, to: toDate) else { return nil } // 计算两个日期之间的毫秒差:取时间间隔的小数部分乘以1000 let timeInterval = toDate.timeIntervalSince(fromDate) let milliseconds = Int((timeInterval.truncatingRemainder(dividingBy: 1)) * 1000) // 拼接成最终的倒计时字符串 return "\(secondsPart) \(milliseconds)毫秒" } }
使用示例:
let formatter = DateComponentsFormatter() let now = Date() let nextGame = now.addingTimeInterval(365*24*3600 + 2*30*24*3600 + 6*24*3600 + 23*60 +24 + 0.005) if let countdown = formatter.differenceWithMilliseconds(from: now, to: nextGame) { print("距离下一场比赛还有\(countdown)") // 输出:距离下一场比赛还有1年2个月6天23分钟24秒 5毫秒 }
方案二:完全自定义格式化逻辑(精确控制所有单位)
如果你想更灵活地控制显示格式(比如隐藏值为0的单位、自定义单位名称),可以直接通过Calendar计算日期组件,再手动计算毫秒:
func preciseCountdownString(from fromDate: Date, to toDate: Date) -> String { guard toDate > fromDate else { return "比赛已开始" } let calendar = Calendar.current // 获取精确的年、月、日、时、分、秒组件 let components = calendar.dateComponents( [.year, .month, .day, .hour, .minute, .second], from: fromDate, to: toDate ) // 计算毫秒部分 let timeInterval = toDate.timeIntervalSince(fromDate) let milliseconds = Int((timeInterval.truncatingRemainder(dividingBy: 1)) * 1000) // 组装所有需要显示的单位 var parts = [String]() if let year = components.year, year > 0 { parts.append("\(year)年") } if let month = components.month, month > 0 { parts.append("\(month)个月") } if let day = components.day, day > 0 { parts.append("\(day)天") } if let hour = components.hour, hour > 0 { parts.append("\(hour)小时") } if let minute = components.minute, minute > 0 { parts.append("\(minute)分") } if let second = components.second, second > 0 { parts.append("\(second)秒") } parts.append("\(milliseconds)毫秒") return "距离下一场比赛还有" + parts.joined(separator: " ") }
这个方案的优势是:用Calendar计算的月、日都是精确符合实际日历的(不会像用固定30天算月份那样有误差),而且你可以完全控制哪些单位显示、怎么显示。
为什么你的原代码不行?
你原代码里设置了.nanosecond,但DateComponentsFormatter的.full单位样式会把它显示为“纳秒”,而且1毫秒等于1,000,000纳秒,所以显示出来的数值会非常大,完全不是你想要的毫秒格式。另外,Formatter默认会隐藏值为0的单位,但如果前面的单位已经占满了maximumUnitCount,小单位也可能被截断,导致纳秒根本不显示。
内容的提问来源于stack exchange,提问作者Govind Rakholiya
相关产品推荐
相关产品推荐

