使用org.threeten.bp格式化API日期字符串,当前方案是否最优?
问题分析与优化方案
首先得说,你当前的代码有个核心逻辑错误:用LocalDate.parse的时候,第二个参数是用来匹配输入字符串格式的,但你把输出用的DAY_MONTH_YEAR_DISPLAY_FORMATTER传进去了——输入的2022-11-23是标准ISO日期格式,和dd MMMM yyyy完全不匹配,这会直接抛出异常,导致函数返回空字符串,根本达不到你要的效果。
另外,你写的buildDate()方法完全是多余的,DateTimeFormatter本身就可以直接输出你想要的格式,没必要手动拼接字符串。
最优实现方式
基于org.threeten.bp库,正确的做法应该是先正确解析原始日期,再用目标格式输出:
简化代码示例
// 注意要指定英文Locale,不然月份会显示成系统语言(比如中文) val TARGET_DATE_FORMATTER = DateTimeFormatter.ofPattern("dd MMMM yyyy", Locale.ENGLISH) fun formatAsFullMonthDisplayDate(localDateTimeStr: String): String { return try { // 直接解析完整的日期时间字符串,再转成日期部分 LocalDateTime.parse(localDateTimeStr) .toLocalDate() .format(TARGET_DATE_FORMATTER) } catch (e: Exception) { // 异常时返回原字符串,比空字符串更友好,可根据业务需求调整 localDateTimeStr } }
关键说明
- 不用手动截断时间:
LocalDateTime.parse默认就能解析yyyy-MM-dd HH:mm:ss这种ISO标准格式的字符串,调用toLocalDate()就能提取出日期部分,省掉substringBefore的操作。 - 必须指定英文Locale:如果系统默认不是英文,
MMMM会输出本地语言的月份(比如“十一月”),显式设为Locale.ENGLISH才能得到November。 - 异常处理更合理:返回原字符串比空字符串更稳妥,避免界面出现空白,你也可以根据业务需求改成其他默认值。
另一种可选实现(直接解析日期部分)
要是你确定原始字符串的日期部分固定是yyyy-MM-dd格式,也可以直接截断后解析,这种方式也没问题:
fun formatAsFullMonthDisplayDate(localDateTimeStr: String): String { return try { val datePart = localDateTimeStr.substringBefore(" ") // LocalDate默认就能解析ISO格式的日期字符串,不用额外指定格式 LocalDate.parse(datePart) .format(TARGET_DATE_FORMATTER) } catch (e: Exception) { localDateTimeStr } }
这种方式和你最初的思路接近,但解析时用了LocalDate的默认解析规则,不会像你原来那样因为格式不匹配抛异常。
总结
你的当前方案既存在逻辑错误(无法正确解析日期),又有冗余代码。上面两种实现都是更优的选择,代码更简洁,逻辑也更严谨。
内容的提问来源于stack exchange,提问作者ant2009
相关产品推荐
相关产品推荐

