Java日期格式化如何避免YYYY引发的时间异常

 更新时间:2023年11月16日 10:31:15   作者:myprince003  
在编程中,日期格式化是一个常见的任务,使用不同的格式化选项可能会导致一些意外的结果,下面我们就来学习一下Java如何避免YYYY引发的时间异常吧

在编程中,日期格式化是一个常见的任务。使用不同的格式化选项可能会导致一些意外的结果。最近遇到一个问题,就是使用YYYY格式化选项会导致时间异常。

public static void main(String[] args) throws ParseException {

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    SimpleDateFormat sdf2 = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
   
    String time = "2023-12-31 23:59:59";
    System.out.printf("yyyy-MM-dd HH:mm:ss: %s\n",sdf.format(sdf.parse(time)));
    System.out.printf("YYYY-MM-dd HH:mm:ss: %s\n",sdf2.format(sdf2.parse(time)));

    System.out.println("======================================");
    String time2 = "2023-11-31 23:59:59"; //11月没有31号
    System.out.printf("yyyy-MM-dd HH:mm:ss: %s\n",sdf.format(sdf.parse(time2)));
    System.out.printf("YYYY-MM-dd HH:mm:ss: %s\n",sdf2.format(sdf2.parse(time2)));

    System.out.println("======================================");
    String time3 = "2023-10-31 23:59:59";
    System.out.printf("yyyy-MM-dd HH:mm:ss: %s\n",sdf.format(sdf.parse(time3)));
    System.out.printf("YYYY-MM-dd HH:mm:ss: %s\n",sdf2.format(sdf2.parse(time3)));
}

输出结果

yyyy-MM-dd HH:mm:ss: 2023-12-31 23:59:59
YYYY-MM-dd HH:mm:ss: 2023-01-01 23:59:59
======================================
yyyy-MM-dd HH:mm:ss: 2023-12-01 23:59:59
YYYY-MM-dd HH:mm:ss: 2023-01-01 23:59:59
======================================
yyyy-MM-dd HH:mm:ss: 2023-10-31 23:59:59
YYYY-MM-dd HH:mm:ss: 2023-01-01 23:59:59

网上查阅说大写的YYYY表示一个基于周的年份,它是根据周计算的年份,而不是基于日历的年份。通常情况下,两者的结果是相同的,但在跨年的第一周或最后一周可能会有差异。但这里发现无论怎么调整时间,YYYY-MM-dd HH:mm:ss格式化后一直是2023-01-01 23:59:59,不仅仅是在跨年的时候出现问题,具体原因尚不清楚

如何避免

定义通用的格式类,所有使用日期格式的地方都引用这个类,这个类中就定义好yyyy-MM-dd格式即可,这样就不会出现有人手误给大家埋雷了。

public class LocalDateUtils {

    /**
     * 显示年月日时分秒,例如 2023-10-31 09:51:53.
     */
    public static final String DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";

    /**
     * 仅显示年月日,例如 2023-10-31.
     */
    public static final String DATE_PATTERN = "yyyy-MM-dd";

    private static final String YEAR = "year";
    private static final String MONTH = "month";
    private static final String WEEK = "week";
    private static final String DAY = "day";

    /**
     * 将日期转换为字符串,格式为:yyyy-MM-dd HH:mm:ss
     */
    public static String getLocalDateTimeStr(LocalDateTime localDateTime) {
        return format(localDateTime, DATETIME_PATTERN);
    }

    /**
     * 将日期转换为字符串,格式为:yyyy-MM-dd
     */
    public static String getLocalDateStr(LocalDateTime localDateTime) {
        return format(localDateTime, DATE_PATTERN);
    }


    /**
     * 将字符串转换为日期,格式为:yyyy-MM-dd HH:mm:ss
     */
    public static LocalDateTime parseLocalDateTime(String localDateTimeStr) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATETIME_PATTERN);
        return LocalDateTime.parse(localDateTimeStr, dateTimeFormatter);
    }

    /**
     * 将字符串转换为日期,格式为:yyyy-MM-dd
     */
    public static LocalDate parseLocalDate(String localDateStr) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATE_PATTERN);
        return LocalDate.parse(localDateStr, dateTimeFormatter);
    }


    /**
     * 将字符串转日期成Long类型的时间戳
     */
    public static Long convertLocalDateTimeToLong(String time) {
        LocalDateTime parse = parse(time, DATETIME_PATTERN);
        return LocalDateTime.from(parse).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    /**
     * 将字符串转日期成Long类型的时间戳
     */
    public static Long convertLocalDateToLong(String time) {
        LocalDateTime parse = parse(time, DATE_PATTERN);
        return LocalDateTime.from(parse).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    public static LocalDateTime parse(String time, String pattern) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
        return LocalDateTime.parse(time, dateTimeFormatter);
    }


    /**
     * 将Long类型的时间戳转换成String 类型的时间格式
     */
    public static String getLocalDateTimeStr(Long time) {
        return format(LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneId.systemDefault()), DATETIME_PATTERN);
    }

    /**
     * 将Long类型的时间戳转换成String 类型的时间格式,时间格式为:yyyy-MM-dd
     */
    public static String getLocalDateStr(Long time) {
        return format(LocalDateTime.ofInstant(Instant.ofEpochMilli(time), ZoneId.systemDefault()), DATE_PATTERN);
    }

    /**
     * 获取日期时间字符串
     */
    public static String format(TemporalAccessor temporal, String pattern) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
        return dateTimeFormatter.format(temporal);
    }


    /**
     * 取本月第一天
     */
    public static LocalDate firstDayOfThisMonth() {
        LocalDate today = LocalDate.now();
        return today.with(TemporalAdjusters.firstDayOfMonth());
    }

    /**
     * 取本月第N天
     */
    public static LocalDate dayOfThisMonth(int n) {
        LocalDate today = LocalDate.now();
        return today.withDayOfMonth(n);
    }

    /**
     * 取本月最后一天
     */
    public static LocalDate lastDayOfThisMonth() {
        LocalDate today = LocalDate.now();
        return today.with(TemporalAdjusters.lastDayOfMonth());
    }


    /**
     * 获取指定日期时间加上指定数量日期时间单位之后的日期时间.
     */
    public static LocalDateTime plus(LocalDateTime localDateTime, int num, ChronoUnit chronoUnit) {
        return localDateTime.plus(num, chronoUnit);
    }

    /**
     * 获取指定日期时间减去指定数量日期时间单位之后的日期时间.
     */
    public static LocalDateTime minus(LocalDateTime localDateTime, int num, ChronoUnit chronoUnit) {
        return localDateTime.minus(num, chronoUnit);
    }

    /**
     * 根据ChronoUnit计算两个日期时间之间相隔日期时间
     */
    public static long getChronoUnitBetween(LocalDateTime start, LocalDateTime end, ChronoUnit chronoUnit) {
        return Math.abs(start.until(end, chronoUnit));
    }

    /**
     * 根据ChronoUnit计算两个日期之间相隔年数或月数或天数
     */
    public static long getChronoUnitBetween(LocalDate start, LocalDate end, ChronoUnit chronoUnit) {
        return Math.abs(start.until(end, chronoUnit));
    }


    /**
     * 切割日期。按照周期切割成小段日期段。例如: <br>
     *
     * @param startDate 开始日期(yyyy-MM-dd)
     * @param endDate   结束日期(yyyy-MM-dd)
     * @param period    周期(天,周,月,年)
     * @return 切割之后的日期集合
     * <li>startDate="2023-10-27",endDate="2023-10-31",period="day"</li>
     * <li>结果为:[2023-10-27, 2023-10-28, 2023-10-29, 2023-10-03,2023-10-31]</li><br>
     * <li>startDate="2023-10-27",endDate="2023-10-31",period="week"</li>
     * <li>结果为:[2023-10-27,2023-10-31]</li><br>
     * <li>startDate="2023-10-27",endDate="2023-10-31",period="month"</li>
     * <li>结果为:[2023-10-27,2023-10-31]</li><br>
     * <li>startDate="2023-10-27",endDate="2023-10-31",period="year"</li>
     * <li>结果为:[2023-10-27,2023-10-31]</li><br>
     */
    public static List<String> listDateStrs(String startDate, String endDate, String period) {
        List<String> result = new ArrayList<>();
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATE_PATTERN);
        LocalDate end = LocalDate.parse(endDate, dateTimeFormatter);
        LocalDate start = LocalDate.parse(startDate, dateTimeFormatter);
        LocalDate tmp = start;
        switch (period) {
            case DAY:
                while (start.isBefore(end) || start.isEqual(end)) {
                    result.add(start.toString());
                    start = start.plusDays(1);
                }
                break;
            case WEEK:
                while (tmp.isBefore(end) || tmp.isEqual(end)) {
                    if (tmp.plusDays(6).isAfter(end)) {
                        result.add(tmp.toString() + "," + end);
                    } else {
                        result.add(tmp.toString() + "," + tmp.plusDays(6));
                    }
                    tmp = tmp.plusDays(7);
                }
                break;
            case MONTH:
                while (tmp.isBefore(end) || tmp.isEqual(end)) {
                    LocalDate lastDayOfMonth = tmp.with(TemporalAdjusters.lastDayOfMonth());
                    if (lastDayOfMonth.isAfter(end)) {
                        result.add(tmp.toString() + "," + end);
                    } else {
                        result.add(tmp.toString() + "," + lastDayOfMonth);
                    }
                    tmp = lastDayOfMonth.plusDays(1);
                }
                break;
            case YEAR:
                while (tmp.isBefore(end) || tmp.isEqual(end)) {
                    LocalDate lastDayOfYear = tmp.with(TemporalAdjusters.lastDayOfYear());
                    if (lastDayOfYear.isAfter(end)) {
                        result.add(tmp.toString() + "," + end);
                    } else {
                        result.add(tmp.toString() + "," + lastDayOfYear);
                    }
                    tmp = lastDayOfYear.plusDays(1);
                }
                break;
            default:
                break;
        }
        return result;
    }
}

以上就是Java日期格式化如何避免YYYY引发的时间异常的详细内容,更多关于Java日期格式化的资料请关注脚本之家其它相关文章!

相关文章

  • SpringBoot使用TraceId日志链路追踪的代码实现

    SpringBoot使用TraceId日志链路追踪的代码实现

    有时候一个业务调用链场景,很长,调了各种各样的方法,看日志的时候,各个接口的日志穿插,确实让人头大,为了解决这个痛点,就使用了TraceId,根据TraceId关键字进入服务器查询日志中是否有这个TraceId, 本文给大家介绍了SpringBoot使用TraceId日志链路追踪的方法
    2025-07-07
  • 浅谈springMVC接收前端json数据的总结

    浅谈springMVC接收前端json数据的总结

    下面小编就为大家分享一篇浅谈springMVC接收前端json数据的总结,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-03-03
  • Java中的读写锁ReentrantReadWriteLock源码分析

    Java中的读写锁ReentrantReadWriteLock源码分析

    这篇文章主要介绍了Java中的读写锁ReentrantReadWriteLock源码分析,ReentrantReadWriteLock 分为读锁和写锁两个实例,读锁是共享锁,可被多个线程同时使用,写锁是独占锁,持有写锁的线程可以继续获取读锁,反之不行,需要的朋友可以参考下
    2023-12-12
  • SpringBoot中实现订单30分钟自动取消的项目实践

    SpringBoot中实现订单30分钟自动取消的项目实践

    现在电子商务平台上订单创建成功,等待支付,一般会给30分钟的时间,本文主要介绍了SpringBoot中实现订单30分钟自动取消的项目实践,具有一定的参考价值,感兴趣的可以了解一下
    2023-10-10
  • mybatis之调用带输出参数的存储过程(Oracle)

    mybatis之调用带输出参数的存储过程(Oracle)

    这篇文章主要介绍了mybatis调用带输出参数的存储过程(Oracle),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • Java实现将彩色PDF转为灰度PDF的示例代码

    Java实现将彩色PDF转为灰度PDF的示例代码

    本文以Java代码为例介绍如何实现将彩色PDF文件转为灰度(黑白)的PDF文件,文中的示例代码讲解详细,感兴趣的小伙伴快跟随小编一起学习一下吧
    2022-03-03
  • Java中Map集合(接口)的基本方法程序演示

    Java中Map集合(接口)的基本方法程序演示

    这篇文章主要为大家详细介绍了Java中Map集合的基本方法程序演示,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-08-08
  • SpringBoot实体多层嵌套判空字段的方式

    SpringBoot实体多层嵌套判空字段的方式

    这篇文章主要介绍了SpringBoot实体多层嵌套如何判空字段,最近在公司了接了个需求:需要开发一个中间系统,进行三方联调,文中通过代码示例介绍的非常详细,需要的朋友可以参考下
    2024-09-09
  • 利用Java编写个"不贪吃蛇"小游戏

    利用Java编写个"不贪吃蛇"小游戏

    贪吃蛇大家一定有玩过了吧,今天小编给大家带来点不一样的。本文将用Java编写一个"不贪吃蛇"小游戏,感兴趣的小伙伴可以动手尝试一下
    2022-08-08
  • Java通俗易懂讲解泛型

    Java通俗易懂讲解泛型

    在正式进入内容之前说明一下:泛型的内容太多,也太复杂。这里因为Java中写数据结构的时候会使用到,所以加上。关于泛型我找了挺多文章,再结合自己的理解,尽可能将其讲清楚。不求会使用泛型,只要求后面数据结构出现泛型的时候能够知道是在干什么即可
    2022-05-05

最新评论