Java日期格式化中的“YYYY”陷阱:为什么跨年周会让你的年份突然+1?

结论先行

在Java中使用 YYYY-MM-dd 格式化日期时,若日期所在的周跨年,年份可能会被错误计算为下一年(如2021年12月26日显示为2022年)。而使用 yyyy-MM-dd 会始终返回正确的年份。问题的根源是 YYYYyyyy 对年份的定义不同:YYYY 是「基于周的年份」,而 yyyy 是「自然年份」。

文章持续更新,可以微信搜一搜「 半个脑袋儿 」第一时间阅读


问题复现

尝试用以下代码格式化 2021-12-26

java 复制代码
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateFormatDemo {
    public static void main(String[] args) {
        SimpleDateFormat sdf1 = new SimpleDateFormat("YYYY-MM-dd");
        SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd");
        
        Date date = new Date(121, 11, 26); // 2021年12月26日
        
        System.out.println(sdf1.format(date)); // 输出:2022-12-26
        System.out.println(sdf2.format(date)); // 输出:2021-12-26
    }
}

结果差异明显,YYYY 的年份跳到了2022年。


原因解析

1. YYYY 是「基于周的年份」
  • 定义YYYY 遵循 ISO 8601 标准,表示「日期所在周所属的年份」。
  • 周的计算规则
    • 默认一周从 周日开始 ,到 周六结束 (可通过 Locale 调整,如某些地区从周一开始)。
    • 若某周跨年(即该周包含新年的第一天),则这一周会被归属到新年所在的年份。

2021年12月26日 为例:

  • 该周为 2021年12月26日(周日)至2022年1月1日(周六)
  • 由于这一周的大部分天数(4天)属于2022年,因此 YYYY 会将其归属到2022年。
2. yyyy 是「自然年份」
  • 定义yyyy 直接表示日期所在的自然年份,与周无关。
  • 无论日期是否跨周或跨月,始终返回实际年份。

如何避免踩坑?

  1. 优先使用 yyyy

    除非明确需要基于周的年份计算,否则格式化日期时应使用 yyyy

  2. 理解业务场景

    • 财务系统、周报统计等可能需要 YYYY(如按周生成报表)。
    • 普通日期场景(如订单时间、日志记录)应使用 yyyy
  3. 注意 Locale 的影响

    • 不同地区的周起始日不同(如美国默认周日开始,欧洲多从周一开始)。
    • 可通过 SimpleDateFormat.setLocale()DateTimeFormatter.withLocale() 指定区域。
  4. Java 8+ 的替代方案

    使用 DateTimeFormatter 时,yyyy 对应 Yu 的行为更清晰:

    java 复制代码
    LocalDate date = LocalDate.of(2021, 12, 26);
    DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("YYYY-MM-dd");
    DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    
    System.out.println(date.format(formatter1)); // 2022-12-26
    System.out.println(date.format(formatter2)); // 2021-12-26

总结

  • YYYYyyyy 的区别:基于周的年份 vs 自然年份。
  • 根本原因 :跨年周的归属规则导致 YYYY 的年份偏移。
  • 最佳实践 :若无特殊需求,始终使用 yyyy-MM-dd 格式化日期。

一个小小的格式字符差异,可能导致跨年时的严重逻辑错误。切记:日期格式化无小事!

相关推荐
武子康31 分钟前
Java-80 深入浅出 RPC Dubbo 动态服务降级:从雪崩防护到配置中心秒级生效
java·分布式·后端·spring·微服务·rpc·dubbo
舒一笑1 小时前
我的开源项目-PandaCoder迎来史诗级大更新啦
后端·程序员·intellij idea
@昵称不存在2 小时前
Flask input 和datalist结合
后端·python·flask
zhuyasen2 小时前
Go 分布式任务和定时任务太难?sasynq 让异步任务从未如此简单
后端·go
东林牧之3 小时前
Django+celery异步:拿来即用,可移植性高
后端·python·django
YuTaoShao3 小时前
【LeetCode 热题 100】131. 分割回文串——回溯
java·算法·leetcode·深度优先
源码_V_saaskw3 小时前
JAVA图文短视频交友+自营商城系统源码支持小程序+Android+IOS+H5
java·微信小程序·小程序·uni-app·音视频·交友
超浪的晨4 小时前
Java UDP 通信详解:从基础到实战,彻底掌握无连接网络编程
java·开发语言·后端·学习·个人开发
AntBlack4 小时前
从小不学好 ,影刀 + ddddocr 实现图片验证码认证自动化
后端·python·计算机视觉
Pomelo_刘金4 小时前
Clean Architecture 整洁架构:借一只闹钟讲明白「整洁架构」的来龙去脉
后端·架构·rust