使用 java.time 包将字符串转换为 Date 类型

使用 java.time 包将字符串转换为 Date 类型

1. 完整的转换方法

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;

public class StringToDateConverter {
    
    public static void main(String[] args) {
        // 目标字符串
        String dateString = "2025-12-17 10:56:42.031";
        
        // 方法1:完整转换步骤
        Date date1 = convertStringToDate(dateString);
        System.out.println("方法1结果: " + date1);
        
        // 方法2:使用工具方法
        Date date2 = parseToDate(dateString);
        System.out.println("方法2结果: " + date2);
        
        // 方法3:指定时区
        Date date3 = parseToDateWithZone(dateString, "Asia/Shanghai");
        System.out.println("方法3结果(上海时区): " + date3);
        
        // 验证转换准确性
        System.out.println("\n验证转换:");
        System.out.println("原始字符串: " + dateString);
        System.out.println("转换后Date: " + date1);
        
        // 反向验证:将Date转回字符串
        String formatted = formatDateToString(date1);
        System.out.println("Date转回字符串: " + formatted);
    }
    
    /**
     * 方法1:将字符串转换为 Date(使用默认时区)
     */
    public static Date convertStringToDate(String dateString) {
        try {
            // 1. 创建格式化器,匹配字符串格式
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
            
            // 2. 解析字符串为 LocalDateTime
            LocalDateTime localDateTime = LocalDateTime.parse(dateString, formatter);
            
            // 3. 将 LocalDateTime 转换为 Instant(需要时区信息)
            //    使用系统默认时区
            java.time.Instant instant = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
            
            // 4. 将 Instant 转换为 Date
            return Date.from(instant);
        } catch (Exception e) {
            throw new RuntimeException("日期格式转换失败: " + dateString, e);
        }
    }
    
    /**
     * 方法2:使用预定义格式化器的工具方法
     */
    private static final DateTimeFormatter DEFAULT_FORMATTER = 
        DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
    
    public static Date parseToDate(String dateString) {
        LocalDateTime localDateTime = LocalDateTime.parse(dateString, DEFAULT_FORMATTER);
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }
    
    /**
     * 方法3:指定特定时区
     */
    public static Date parseToDateWithZone(String dateString, String zoneId) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
        LocalDateTime localDateTime = LocalDateTime.parse(dateString, formatter);
        
        // 使用指定的时区
        ZoneId zone = ZoneId.of(zoneId);
        return Date.from(localDateTime.atZone(zone).toInstant());
    }
    
    /**
     * 将 Date 转换回字符串格式
     */
    public static String formatDateToString(Date date) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
        
        // 将 Date 转换为 LocalDateTime
        LocalDateTime localDateTime = date.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime();
        
        return localDateTime.format(formatter);
    }
}

2. 灵活的转换工具类

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class DateTimeConverter {
    
    // 预定义的常用格式
    public static final String PATTERN_ISO = "yyyy-MM-dd HH:mm:ss.SSS";
    public static final String PATTERN_DATE_ONLY = "yyyy-MM-dd";
    public static final String PATTERN_TIME_ONLY = "HH:mm:ss.SSS";
    public static final String PATTERN_COMPACT = "yyyyMMddHHmmssSSS";
    public static final String PATTERN_SLASH = "yyyy/MM/dd HH:mm:ss.SSS";
    
    private static final Map<String, DateTimeFormatter> FORMATTER_CACHE = new HashMap<>();
    
    static {
        // 初始化常用格式化器缓存
        cacheFormatter(PATTERN_ISO);
        cacheFormatter(PATTERN_DATE_ONLY);
        cacheFormatter(PATTERN_TIME_ONLY);
        cacheFormatter(PATTERN_COMPACT);
        cacheFormatter(PATTERN_SLASH);
    }
    
    private static void cacheFormatter(String pattern) {
        FORMATTER_CACHE.put(pattern, DateTimeFormatter.ofPattern(pattern));
    }
    
    /**
     * 将字符串转换为 Date(自动检测格式)
     */
    public static Date stringToDate(String dateString) {
        // 尝试多种格式
        String[] patterns = {
            "yyyy-MM-dd HH:mm:ss.SSS",
            "yyyy-MM-dd HH:mm:ss",
            "yyyy-MM-dd HH:mm",
            "yyyy-MM-dd",
            "yyyy/MM/dd HH:mm:ss.SSS",
            "yyyy/MM/dd HH:mm:ss",
            "yyyy.MM.dd HH:mm:ss.SSS"
        };
        
        for (String pattern : patterns) {
            try {
                return parseWithPattern(dateString, pattern);
            } catch (DateTimeParseException e) {
                // 尝试下一个格式
                continue;
            }
        }
        
        throw new IllegalArgumentException("无法解析日期字符串: " + dateString);
    }
    
    /**
     * 使用指定格式将字符串转换为 Date
     */
    public static Date parseWithPattern(String dateString, String pattern) {
        DateTimeFormatter formatter = FORMATTER_CACHE.computeIfAbsent(
            pattern, DateTimeFormatter::ofPattern
        );
        
        // 判断字符串是否包含时间部分
        if (pattern.contains("HH") || pattern.contains("mm") || pattern.contains("ss")) {
            // 包含时间部分
            if (pattern.contains("HH:mm:ss.SSS")) {
                // 包含毫秒
                LocalDateTime localDateTime = LocalDateTime.parse(dateString, formatter);
                return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
            } else {
                // 不包含毫秒
                LocalDateTime localDateTime = LocalDateTime.parse(dateString, formatter);
                return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
            }
        } else {
            // 只有日期部分
            LocalDate localDate = LocalDate.parse(dateString, formatter);
            return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
        }
    }
    
    /**
     * 将字符串转换为 Date(指定时区)
     */
    public static Date stringToDate(String dateString, String pattern, String zoneId) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
        ZoneId zone = ZoneId.of(zoneId);
        
        if (pattern.contains("HH:mm:ss.SSS")) {
            LocalDateTime localDateTime = LocalDateTime.parse(dateString, formatter);
            return Date.from(localDateTime.atZone(zone).toInstant());
        } else if (pattern.contains("HH:mm:ss")) {
            LocalDateTime localDateTime = LocalDateTime.parse(dateString, formatter);
            return Date.from(localDateTime.atZone(zone).toInstant());
        } else {
            LocalDate localDate = LocalDate.parse(dateString, formatter);
            return Date.from(localDate.atStartOfDay(zone).toInstant());
        }
    }
    
    /**
     * 将 Date 转换为指定格式的字符串
     */
    public static String dateToString(Date date, String pattern) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
        LocalDateTime localDateTime = date.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime();
        
        return localDateTime.format(formatter);
    }
    
    /**
     * 获取 Date 的各个部分
     */
    public static void printDateComponents(Date date) {
        LocalDateTime localDateTime = date.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime();
        
        System.out.println("年: " + localDateTime.getYear());
        System.out.println("月: " + localDateTime.getMonthValue());
        System.out.println("日: " + localDateTime.getDayOfMonth());
        System.out.println("时: " + localDateTime.getHour());
        System.out.println("分: " + localDateTime.getMinute());
        System.out.println("秒: " + localDateTime.getSecond());
        System.out.println("毫秒: " + localDateTime.getNano() / 1_000_000);
        System.out.println("星期: " + localDateTime.getDayOfWeek());
    }
    
    public static void main(String[] args) {
        // 测试各种格式
        String dateString1 = "2025-12-17 10:56:42.031";
        String dateString2 = "2025-12-17 10:56:42";
        String dateString3 = "2025-12-17";
        
        System.out.println("=== 转换测试 ===");
        
        // 转换带毫秒的字符串
        Date date1 = parseWithPattern(dateString1, PATTERN_ISO);
        System.out.println("带毫秒: " + date1);
        System.out.println("格式化为字符串: " + dateToString(date1, PATTERN_ISO));
        
        // 转换不带毫秒的字符串
        Date date2 = parseWithPattern(dateString2, "yyyy-MM-dd HH:mm:ss");
        System.out.println("\n不带毫秒: " + date2);
        
        // 转换只有日期的字符串
        Date date3 = parseWithPattern(dateString3, PATTERN_DATE_ONLY);
        System.out.println("\n只有日期: " + date3);
        System.out.println("格式化为日期: " + dateToString(date3, PATTERN_DATE_ONLY));
        
        // 自动检测格式
        System.out.println("\n=== 自动检测格式 ===");
        Date autoDate = stringToDate("2025/12/17 10:56:42.031");
        System.out.println("自动检测结果: " + autoDate);
        
        // 显示日期组成部分
        System.out.println("\n=== 日期组成部分 ===");
        printDateComponents(date1);
    }
}

3. 处理时区问题的转换

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.TimeZone;

public class TimeZoneConverter {
    
    /**
     * 将字符串转换为 Date,考虑时区偏移
     */
    public static Date convertWithTimeZone(String dateString, String sourceZone, String targetZone) {
        // 解析字符串,假设字符串时间是在sourceZone时区
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
        LocalDateTime localDateTime = LocalDateTime.parse(dateString, formatter);
        
        // 创建源时区的时间
        ZonedDateTime sourceZonedDateTime = localDateTime.atZone(ZoneId.of(sourceZone));
        
        // 转换为目标时区
        ZonedDateTime targetZonedDateTime = sourceZonedDateTime.withZoneSameInstant(ZoneId.of(targetZone));
        
        // 转换为 Date(Date 内部存储的是 UTC 时间戳)
        return Date.from(targetZonedDateTime.toInstant());
    }
    
    /**
     * 显示不同时区的同一时间
     */
    public static void showInDifferentTimeZones(Date date) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
        
        String[] zones = {
            "UTC",
            "Asia/Shanghai",
            "America/New_York",
            "Europe/London",
            "Asia/Tokyo"
        };
        
        System.out.println("同一时间在不同时区的表示:");
        for (String zone : zones) {
            ZonedDateTime zonedDateTime = date.toInstant().atZone(ZoneId.of(zone));
            System.out.printf("%-20s: %s%n", zone, zonedDateTime.format(formatter));
        }
    }
    
    public static void main(String[] args) {
        String dateString = "2025-12-17 10:56:42.031";
        
        System.out.println("原始字符串: " + dateString);
        System.out.println("假设这个时间是北京时间");
        
        // 将北京时间转换为Date
        Date date = convertWithTimeZone(dateString, "Asia/Shanghai", "UTC");
        System.out.println("\n转换为Date (UTC内部存储): " + date);
        
        // 显示在不同时区
        showInDifferentTimeZones(date);
        
        // 验证:将Date转换回北京时间字符串
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
        ZonedDateTime beijingTime = date.toInstant().atZone(ZoneId.of("Asia/Shanghai"));
        System.out.println("\n转换回北京时间: " + beijingTime.format(formatter));
    }
}

4. 批量转换和处理异常

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class BatchDateConverter {
    
    /**
     * 批量转换字符串为Date
     */
    public static List<Date> batchConvert(List<String> dateStrings, String pattern) {
        List<Date> results = new ArrayList<>();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
        
        for (int i = 0; i < dateStrings.size(); i++) {
            try {
                LocalDateTime localDateTime = LocalDateTime.parse(dateStrings.get(i), formatter);
                Date date = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
                results.add(date);
            } catch (DateTimeParseException e) {
                System.err.printf("第 %d 个字符串解析失败: %s (原因: %s)%n", 
                    i + 1, dateStrings.get(i), e.getMessage());
                // 可以选择返回null或抛出异常
                results.add(null);
            }
        }
        
        return results;
    }
    
    /**
     * 转换并验证日期范围
     */
    public static Date convertWithValidation(String dateString, String pattern, 
                                             LocalDateTime minDate, LocalDateTime maxDate) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
        LocalDateTime localDateTime = LocalDateTime.parse(dateString, formatter);
        
        // 验证日期范围
        if (localDateTime.isBefore(minDate)) {
            throw new IllegalArgumentException("日期不能早于 " + minDate);
        }
        if (localDateTime.isAfter(maxDate)) {
            throw new IllegalArgumentException("日期不能晚于 " + maxDate);
        }
        
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }
    
    public static void main(String[] args) {
        // 批量转换示例
        List<String> dateStrings = new ArrayList<>();
        dateStrings.add("2025-12-17 10:56:42.031");
        dateStrings.add("2025-12-18 14:30:00.500");
        dateStrings.add("invalid-date"); // 无效日期
        dateStrings.add("2025-12-19 23:59:59.999");
        
        System.out.println("=== 批量转换 ===");
        List<Date> dates = batchConvert(dateStrings, "yyyy-MM-dd HH:mm:ss.SSS");
        
        for (int i = 0; i < dates.size(); i++) {
            System.out.printf("字符串: %-25s -> Date: %s%n", 
                dateStrings.get(i), dates.get(i));
        }
        
        // 带验证的转换
        System.out.println("\n=== 带验证的转换 ===");
        try {
            LocalDateTime minDate = LocalDateTime.of(2025, 1, 1, 0, 0);
            LocalDateTime maxDate = LocalDateTime.of(2025, 12, 31, 23, 59);
            
            Date validDate = convertWithValidation(
                "2025-12-17 10:56:42.031", 
                "yyyy-MM-dd HH:mm:ss.SSS",
                minDate, maxDate
            );
            System.out.println("验证通过的日期: " + validDate);
            
            // 这会抛出异常
            Date invalidDate = convertWithValidation(
                "2026-01-01 00:00:00.000",
                "yyyy-MM-dd HH:mm:ss.SSS",
                minDate, maxDate
            );
        } catch (IllegalArgumentException e) {
            System.out.println("验证失败: " + e.getMessage());
        }
    }
}

5. 实际应用示例

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;

public class PracticalExample {
    
    // 数据库中的日期格式
    private static final String DB_DATE_PATTERN = "yyyy-MM-dd HH:mm:ss.SSS";
    
    /**
     * 模拟从数据库读取字符串并转换为Date
     */
    public static Date readFromDatabase(String dbDateString) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DB_DATE_PATTERN);
        LocalDateTime localDateTime = LocalDateTime.parse(dbDateString, formatter);
        return Date.from(localDateTime.atZone(ZoneId.of("UTC")).toInstant());
    }
    
    /**
     * 准备写入数据库的Date转换
     */
    public static String prepareForDatabase(Date date) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DB_DATE_PATTERN);
        LocalDateTime localDateTime = date.toInstant()
                .atZone(ZoneId.of("UTC"))
                .toLocalDateTime();
        return localDateTime.format(formatter);
    }
    
    /**
     * 生成日志时间戳
     */
    public static String createLogTimestamp() {
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
        return now.format(formatter);
    }
    
    /**
     * 解析日志时间戳为Date
     */
    public static Date parseLogTimestamp(String logTimestamp) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
        LocalDateTime localDateTime = LocalDateTime.parse(logTimestamp, formatter);
        return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
    }
    
    public static void main(String[] args) {
        System.out.println("=== 数据库操作示例 ===");
        
        // 模拟数据库日期字符串
        String dbDateStr = "2025-12-17 10:56:42.031";
        
        // 读取并转换为Date
        Date dateFromDB = readFromDatabase(dbDateStr);
        System.out.println("从数据库读取: " + dbDateStr);
        System.out.println("转换为Date: " + dateFromDB);
        
        // 处理业务逻辑后写回数据库
        Date processedDate = new Date(dateFromDB.getTime() + 3600000); // 加1小时
        String dbWriteStr = prepareForDatabase(processedDate);
        System.out.println("处理后写回数据库: " + dbWriteStr);
        
        System.out.println("\n=== 日志处理示例 ===");
        
        // 生成日志时间戳
        String logTime = createLogTimestamp();
        System.out.println("日志时间戳: " + logTime);
        
        // 解析日志时间戳
        Date logDate = parseLogTimestamp(logTime);
        System.out.println("解析为Date: " + logDate);
        
        // 计算时间差
        long diff = System.currentTimeMillis() - logDate.getTime();
        System.out.println("距离现在: " + diff + " 毫秒");
    }
}

关键要点总结

  1. 核心转换步骤

    // 1. 定义格式化器
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
    
    // 2. 解析为LocalDateTime
    LocalDateTime localDateTime = LocalDateTime.parse(dateString, formatter);
    
    // 3. 转换为Instant(需要时区)
    Instant instant = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
    
    // 4. 转换为Date
    Date date = Date.from(instant);
    
  2. 时区注意事项

    • 明确你的字符串表示的是哪个时区的时间
    • 数据库通常使用UTC时间
    • 显示给用户时需要转换为本地时区
  3. 最佳实践

    • 使用常量定义日期格式模式
    • 缓存DateTimeFormatter对象(线程安全)
    • 总是处理DateTimeParseException异常
    • 在团队中统一日期处理规范
  4. 性能优化

    • 复用DateTimeFormatter对象
    • 使用预定义的ISO格式器(如DateTimeFormatter.ISO_LOCAL_DATE_TIME

根据你的具体需求选择合适的方法。如果需要处理大量日期转换,建议使用工具类并缓存格式化器。

posted @ 2025-12-18 09:46  dirgo  阅读(3)  评论(0)    收藏  举报