Java 日期字符串格式转换:从 "yyyy-MM-dd" 到 "dd-MM-yyyy" 并保留纳秒精度
日期格式转换是 Java 日常开发中非常常见的需求。然而,看似简单的操作一旦忽略了细节,就容易埋下隐患。本文主要介绍如何将类似 "2023-03-13 12:00:02" 的字符串,转换为 "13-03-2023 12:00:02.000000000" 这种带有纳秒(9 位小数秒)的格式,并提供完整可用的代码示例。

核心实现思路只有两步:先将原始字符串解析为 Date 对象,再按照目标格式重新格式化。不过,Java 原生的 SimpleDateFormat 存在一个明显局限——它最多只能处理毫秒(SSS),对于纳秒(9 位小数秒)则无能为力。因此,一旦目标格式要求输出 9 个零(即 .000000000),就必须借助额外手段。
下面提供一个相对健壮、可读性较好的实现方案(兼容 Java 8 及以下版本):
import ja va.text.ParseException;
import ja va.text.SimpleDateFormat;
import ja va.util.Date;
public class DateFormatExample {
// ✅ 推荐:使用 SimpleDateFormat(适用于 Java < 8 或需兼容旧环境)
static String formatoFechaFinBd(String dateService) throws ParseException {
// 1. 解析输入字符串:注意原始格式不含 'T' 和 'Z',不应使用 "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateService);
// 2. 格式化为 dd-MM-yyyy HH:mm:ss + 补零的9位纳秒(因 SimpleDateFormat 不支持纳秒,此处默认补 "000000000")
String baseFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss").format(date);
return baseFormat + ".000000000"; // 纳秒部分固定补零(若需真实纳秒,请用 ja va.time)
}
}
以下几个容易踩坑的细节,务必重点留意:
- 很多人习惯将模式写成 "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",但输入字符串 "2023-03-13 12:00:02" 中根本没有 'T' 和 'Z',这样解析必然抛出
ParseException。 - 注意区分 hh 与 HH。hh 表示 12 小时制(01–12),而 HH 才是 24 小时制(00–23)。一旦用错,转换后的时间就会完全错乱。
- Ka 是无效的模式字母,属于常见的误写。而 SSSSSSSSS 在 SimpleDateFormat 中会被自动截断为 SSS,只保留前三位,根本无法输出纳秒。如果业务真的要求纳秒精度(例如数据库字段为 TIMESTAMP(9)),就必须改用
java.timeAPI。
既然提到了 java.time,下面给出基于新 API 的实现方式,更加现代、线程安全,且天然支持纳秒处理:
import ja va.time.LocalDateTime;
import ja va.time.format.DateTimeFormatter;
// ✅ 更现代、线程安全、支持纳秒的方案(Java 8+)
static String formatoFechaFinBdModern(String dateService) {
LocalDateTime dt = LocalDateTime.parse(dateService, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
// 注意:LocalDateTime.parse() 无法直接解析纳秒,原始字符串无纳秒信息,故补零是合理默认行为
return dt.format(DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss")) + ".000000000";
}
结论非常清晰:
- 从兼容性与长期维护角度出发,更推荐的做法是:优先使用
java.time(LocalDateTime+DateTimeFormatter),替代已过时且非线程安全的SimpleDateFormat。 - 解析模式必须与输入字符串完全一致,包括空格、分隔符以及大小写敏感字符,任何细微差别都会导致解析失败。
- 纳秒级的格式处理,关键在于数据来源。如果原始字符串本身不含纳秒信息,那么补零是最安全、最合理的默认行为。若业务需要动态纳秒值,则应从
Instant或LocalDateTime.now()获取完整时间戳后再进行格式化。
