首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 計算時間差工具類:毫秒精度轉換為人類可讀格式

     編輯:Java 相關知識

業務常需計算兩個時間點的差值並以「時:分:秒」格式顯示。本文提供健壯、可複用的工具類實作,處理邊界條件、格式化細節與效能考量。

核心實作

import java.util.Date;
import java.text.MessageFormat;

public class TimeUtils {
    /**
     * 計算時間差,返回 "HH:mm:ss" 或 "mm:ss" 或 "ss" 格式
     * @param begin 開始時間
     * @param end 結束時間
     * @return 格式化時間差字符串
     */
    public static String getTimeDifference(Date begin, Date end) {
        if (begin == null || end == null) {
            throw new IllegalArgumentException("時間參數不能為 null");
        }
        if (end.before(begin)) {
            throw new IllegalArgumentException("結束時間不能早於開始時間");
        }
        
        long diffMillis = end.getTime() - begin.getTime();
        long totalSeconds = diffMillis / 1000;
        
        long hours = totalSeconds / 3600;
        long minutes = (totalSeconds % 3600) / 60;
        long seconds = totalSeconds % 60;
        
        StringBuilder sb = new StringBuilder();
        
        if (hours > 0) {
            sb.append(hours).append(':');
            // 分鐘、秒雙位數補零
            sb.append(String.format("%02d:%02d", minutes, seconds));
        } else if (minutes > 0) {
            sb.append(minutes).append(':');
            sb.append(String.format("%02d", seconds));
        } else {
            sb.append(seconds);
        }
        
        return sb.toString();
    }
    
    /**
     * 通用版本:支援天、時、分、秒、毫秒
     */
    public static String formatDuration(long millis) {
        if (millis < 0) throw new IllegalArgumentException("毫秒數不能為負");
        
        long days = millis / (24 * 3600 * 1000);
        millis %= 24 * 3600 * 1000;
        long hours = millis / (3600 * 1000);
        millis %= 3600 * 1000;
        long minutes = millis / (60 * 1000);
        millis %= 60 * 1000;
        long seconds = millis / 1000;
        long ms = millis % 1000;
        
        StringBuilder sb = new StringBuilder();
        if (days > 0) sb.append(days).append("天");
        if (hours > 0) sb.append(hours).append("時");
        if (minutes > 0) sb.append(minutes).append("分");
        if (seconds > 0) sb.append(seconds).append("秒");
        if (ms > 0 || sb.length() == 0) sb.append(ms).append("毫秒");
        
        return sb.toString();
    }
    
    /**
     * Java 8+ 現代寫法:Duration API
     */
    public static String formatDurationModern(java.time.Duration duration) {
        long seconds = duration.getSeconds();
        long hours = seconds / 3600;
        long minutes = (seconds % 3600) / 60;
        long secs = seconds % 60;
        int nanos = duration.getNano();
        
        return String.format("%02d:%02d:%02d.%03d", hours, minutes, secs, nanos / 1_000_000);
    }
}

單元測試驗證

public class TimeUtilsTest {
    @Test
    public void testBasic() {
        Date start = new Date(1000 * 60 * 60); // 1小時
        Date end = new Date(1000 * 60 * 60 * 2 + 1000 * 30 + 1000 * 15); // 2小時30分15秒
        assertEquals("1:30:15", TimeUtils.getTimeDifference(start, end));
    }
    
    @Test
    public void testLessThanHour() {
        Date start = new Date(0);
        Date end = new Date(1000 * 45 + 500); // 45.5秒
        assertEquals("45", TimeUtils.getTimeDifference(start, end)); // 僅秒
    }
    
    @Test
    public void testFormatDuration() {
        assertEquals("1天2時3分4秒500毫秒", 
            TimeUtils.formatDuration(1*24*3600*1000 + 2*3600*1000 + 3*60*1000 + 4*1000 + 500));
    }
}

常見陷阱與最佳實踐

陷阱後果修正
直接用 Date 相減得到毫秒數,非直觀封裝工具方法
忽略時區影響跨天/跨 DST 計算錯誤使用 Instant/ZonedDateTime
手動拼接字符串易漏補零、格式不一致String.format/DateTimeFormatter
不驗證參數順序負值導致邏輯錯誤前置檢查拋出異常

Java 8+ 推薦寫法

import java.time.*;
import java.time.temporal.ChronoUnit;

public class ModernTimeUtils {
    public static String between(Instant start, Instant end) {
        Duration d = Duration.between(start, end);
        return formatDuration(d);
    }
    
    public static String between(LocalDateTime start, LocalDateTime end, ZoneId zone) {
        Duration d = Duration.between(start.atZone(zone), end.atZone(zone));
        return formatDuration(d);
    }
    
    private static String formatDuration(Duration d) {
        long hours = d.toHours();
        long minutes = d.toMinutesPart(); // Java 9+
        long seconds = d.toSecondsPart(); // Java 9+
        int millis = d.toMillisPart();    // Java 9+
        
        if (hours > 0) return String.format("%d:%02d:%02d.%03d", hours, minutes, seconds, millis);
        if (minutes > 0) return String.format("%d:%02d.%03d", minutes, seconds, millis);
        return String.format("%d.%03d秒", seconds, millis);
    }
}

應用場景

  • API 響應時間記錄與監控告警
  • 批次任務執行耗時統計
  • 用戶行為分析:停留時間、轉化漏斗步驟耗時
  • 效能分析:方法執行時間、GC 停頓時間
  • 日誌系統:相對時間顯示(如「5分鐘前」)

時間差計算看似簡單,格式化細節、邊界條件、時區處理卻是 Bug 高發區。封裝通用工具類、編寫完整測試、優先使用 java.time,是避坑關鍵。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved