You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java实体类中使用GregorianCalendar设置指定日期并在toString()中正确格式化显示的问题咨询

解决Book类中GregorianCalendar的日期创建与格式化问题

先给你捋捋当前代码里的几个小问题,这就是为啥toString输出Date Of Publish=1/2/5这种奇怪结果的原因:

1. 为什么toString显示错误的日期值?

你在toString里用的dateOfPublish.YEAR、dateOfPublish.MONTH、dateOfPublish.DATE其实是Calendar类的静态常量,它们的固定值分别是1、2、5,根本不是你实例里的实际日期!要获取Calendar对象的真实年月日,得用get()方法,比如dateOfPublish.get(Calendar.YEAR)才行。

2. 正确创建包含特定日期的Book对象

首先要注意:GregorianCalendar的月份参数是从0开始的(0对应1月,11对应12月),所以你写的new GregorianCalendar(2018,3,20)实际创建的是2018年4月20日,不是3月哦。如果要创建2018年3月20日,推荐用Calendar的月份常量,可读性更强:

new Book(new GregorianCalendar(2018, Calendar.MARCH, 20));

另外你的setDateOfPublish方法完全没生效,现在的代码只是把参数赋值给自己,得改成这样:

public void setDateOfPublish(int day, int month, int year) {
    // 如果外部传入的月份是1-12(符合日常习惯),这里要转成0起始的Calendar月份
    this.dateOfPublish = new GregorianCalendar(year, month - 1, day);
}

3. 在实体类中使用SimpleDateFormat格式化日期

当然可以用!不过要注意SimpleDateFormat不是线程安全的,所以分两种场景处理:

场景一:单线程/低并发环境

直接在toString里每次创建新的实例就行,简单方便:

@Override
public String toString() {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
    // 把Calendar转成Date对象再格式化
    return "Date Of Publish=" + sdf.format(dateOfPublish.getTime());
}

场景二:多线程环境

用ThreadLocal来封装SimpleDateFormat,避免线程安全问题:

// 静态ThreadLocal,每个线程持有自己的格式化实例
private static final ThreadLocal<SimpleDateFormat> DATE_FORMATTER = ThreadLocal.withInitial(
    () -> new SimpleDateFormat("yyyy/MM/dd")
);

@Override
public String toString() {
    return "Date Of Publish=" + DATE_FORMATTER.get().format(dateOfPublish.getTime());
}

4. 更推荐的日期类:Java 8+的LocalDate

GregorianCalendar和Date都是老旧API,坑特别多(比如月份0起始、对象可变、线程不安全)。Java 8及以后强烈推荐用java.time.LocalDate,这是不可变类,线程安全,API设计更符合直觉:

改造后的Book类示例

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class Book {
    private LocalDate dateOfPublish;

    // 直接接受LocalDate的构造方法
    public Book(LocalDate dateOfPublish) {
        this.dateOfPublish = dateOfPublish;
    }

    // 提供接受年月日的构造方法,月份直接用1-12(符合日常习惯)
    public Book(int year, int month, int day) {
        this.dateOfPublish = LocalDate.of(year, month, day);
    }

    public LocalDate getDateOfPublish() {
        return dateOfPublish;
    }

    public void setDateOfPublish(int day, int month, int year) {
        this.dateOfPublish = LocalDate.of(year, month, day);
    }

    @Override
    public String toString() {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
        return "Date Of Publish=" + dateOfPublish.format(formatter);
    }
}

现在创建对象直接写new Book(2018, 3, 20)就代表2018年3月20日,不用再纠结月份偏移的问题,而且DateTimeFormatter是线程安全的,比SimpleDateFormat靠谱多了。

内容的提问来源于stack exchange,提问作者AhChing11

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 09:37:37