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

Java 獲取當前日期時間完整指南:從基礎到進階

     編輯:關於JSP

核心類對比 (Java 8 前 vs 後)

場景舊 API (java.util/Date)新 API (java.time)線程安全
當前時間點new Date()Instant.now()新 ✓ / 舊 ✗
日期時間 (帶時區)Calendar.getInstance()ZonedDateTime.now()新 ✓ / 舊 ✗
本地日期 (無時區)無直接對應LocalDate.now()新 ✓
本地時間無直接對應LocalTime.now()新 ✓
格式化/解析SimpleDateFormatDateTimeFormatter新 ✓ / 舊 ✗
數據庫交互java.sql.Date/Time/TimestampLocalDateTime → Timestamp-

Java 8+ 新 API 推薦用法 (主流標準)

1. 獲取當前日期時間

// 本地日期時間(無時區,適合業務邏輯)
LocalDateTime now = LocalDateTime.now();        // 2024-01-15T14:30:45.123
LocalDate today = LocalDate.now();              // 2024-01-15
LocalTime time = LocalTime.now();               // 14:30:45.123

// 帶時區(準確時間點)
ZonedDateTime zdt = ZonedDateTime.now();        // 2024-01-15T14:30:45.123+08:00[Asia/Shanghai]
Instant instant = Instant.now();                // 2024-01-15T06:30:45.123Z (UTC)

// 指定時區
LocalDateTime shanghai = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));

2. 格式化輸出

DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formatted = now.format(fmt);  // "2024-01-15 14:30:45"

// 內建格式器
String iso = now.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME); // "2024-01-15T14:30:45.123"
String chinese = now.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH時mm分ss秒", Locale.CHINESE));

3. 解析字符串

String str = "2024-01-15 14:30:45";
LocalDateTime parsed = LocalDateTime.parse(str, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

// 容錯解析:多格式嘗試
public LocalDateTime parseFlexible(String str) {
    DateTimeFormatter[] formatters = {
        DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"),
        DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"),
        DateTimeFormatter.ISO_LOCAL_DATE_TIME
    };
    for (DateTimeFormatter f : formatters) {
        try { return LocalDateTime.parse(str, f); } catch (DateTimeParseException ignored) {}
    }
    throw new IllegalArgumentException("無法解析: " + str);
}

4. 日期計算與調整

LocalDate date = LocalDate.now();

// 加減操作(不可變,返回新對象)
LocalDate tomorrow = date.plusDays(1);
LocalDate nextMonth = date.plusMonths(1);
LocalDate lastYear = date.minusYears(1);

// TemporalAdjusters 複雜調整
LocalDate firstDayOfMonth = date.with(TemporalAdjusters.firstDayOfMonth());
LocalDate lastDayOfMonth = date.with(TemporalAdjusters.lastDayOfMonth());
LocalDate nextMonday = date.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
LocalDate firstDayOfYear = date.withDayOfYear(1);

// 兩日期間隔
long daysBetween = ChronoUnit.DAYS.between(startDate, endDate);
long monthsBetween = ChronoUnit.MONTHS.between(start, end);

5. 舊 API 互操作 (數據庫/JDBC)


// LocalDateTime → Timestamp
Timestamp ts = Timestamp.valueOf(localDateTime);

// Timestamp → LocalDateTime
LocalDateTime ldt = timestamp.toLocalDateTime();

// Instant → Date
Date date = Date.from(instant);

// Date → Instant
Instant ins = date.toInstant();

舊 API (java.util.Date/Calendar) 維護代碼指南

若項目仍使用舊 API,請遵循以下規範:

1. 線程安全:SimpleDateFormat 非線程安全

// 錯誤:共享實例導致並發錯誤
static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd");

// 正確:ThreadLocal 隔離
static final ThreadLocal SDF_THREAD_LOCAL = 
    ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));

public String format(Date date) {
    return SDF_THREAD_LOCAL.get().format(date);
}

2. 常用操作模板

// 獲取當前時間毫秒數 (三種等價方式)
long ms1 = System.currentTimeMillis();
long ms2 = new Date().getTime();
long ms3 = Calendar.getInstance().getTimeInMillis();

// 格式化輸出
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String str = sdf.format(new Date());

// 解析
Date date = sdf.parse("2024-01-15 14:30:45");

// Calendar 字段操作
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH) + 1; // 0-based!
int day = cal.get(Calendar.DAY_OF_MONTH);
cal.add(Calendar.DAY_OF_MONTH, -7); // 一周前
Date weekAgo = cal.getTime();

實用工具類封裝 (生產級)


public final class DateUtils {
    private DateUtils() {}

    // 線程安全格式器緩存
    private static final Map> FORMATTER_CACHE = new ConcurrentHashMap<>();

    public static DateTimeFormatter getFormatter(String pattern) {
        return FORMATTER_CACHE.computeIfAbsent(pattern, 
            p -> ThreadLocal.withInitial(() -> DateTimeFormatter.ofPattern(p)))
            .get();
    }

    // 格式化
    public static String format(LocalDateTime ldt, String pattern) {
        return ldt.format(getFormatter(pattern));
    }

    public static String format(Date date, String pattern) {
        return format(date.toInstant()
            .atZone(ZoneId.systemDefault())
            .toLocalDateTime(), pattern);
    }

    // 解析
    public static LocalDateTime parse(String str, String pattern) {
        return LocalDateTime.parse(str, getFormatter(pattern));
    }

    // 相對時間描述
    public static String relativeTime(LocalDateTime target) {
        Duration dur = Duration.between(target, LocalDateTime.now());
        long seconds = dur.getSeconds();
        if (seconds < 60) return "剛剛";
        if (seconds < 3600) return seconds / 60 + "分鐘前";
        if (seconds < 86400) return seconds / 3600 + "小時前";
        if (seconds < 604800) return seconds / 86400 + "天前";
        return format(target, "yyyy-MM-dd");
    }
}

常見陷阱總結

陷阱錯誤代碼正確做法
月份 0-basedcal.get(Calendar.MONTH) // 0=1月+1 顯示,或用 Month enum
SimpleDateFormat 共享static final SDF = new ...ThreadLocal 或新 API
時區假設new Date() 認為是本地時間Date 無時區,用 ZonedDateTime
夏令時跳躍plusDays(1) 跨夏令時用 LocalDate 而非 Instant 計算天
數據庫時區不一致存 UTC 讀本地統一用 UTC 存儲,顯示時轉換
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved