Java时间处理核心要点:Calendar、Date与格式化实战
掌握Java时间处理的核心在于熟练使用 java.util.Calendar 和 java.text.SimpleDateFormat 类。本文总结从基础的时间格式化和类型转换,到复杂的日期间隔计算及数据库时间适配等实用操作。
获取特定月份的最大天数
在开发中,经常需要动态判断某年某月有多少天(例如区分闰年二月是28还是29天)。利用 Calendar 类的 getActualMaximum 方法可以准确获取指定月份的天数。
第1步:初始化并设置目标年月
目的:清除系统默认时间的干扰,设定具体的查询年份和月份。
- 入口:
Calendar.getInstance() - 动作: 调用
clear()清理缓存,使用set设置年、月。注意Calendar.MONTH的值是从0开始计算的(0代表一月)。 - 参数示例: year设为整数型,month为 i-1(假设i为用户输入的1-12月份的数值)。
Calendar time = Calendar.getInstance();
time.clear(); // 必须先清空,否则继承当前系统时间
time.set(Calendar.YEAR, year);
time.set(Calendar.MONTH, i - 1);
int day = time.getActualMaximum(Calendar.DAY_OF_MONTH); // 获取本月最大天数
Date 与 Calendar 的类型转换
Date 和 Calendar 是Java中最基础的两个时间类,两者之间的相互转换非常频繁。
第2步:Calendar 转化为 Date
通过 getTime() 方法将日历对象提取为标准Date对象。
Calendar cal = Calendar.getInstance();
Date date = cal.getTime();
第3步:Date 转化为 Calendar
使用 setTime() 方法将Date对象填入日历实例中。
Date date = new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(date);
日期时间的格式化输出
使用 SimpleDateFormat 类可以实现日期的字符串化显示或反向解析。这是日常日志记录、前端展示最常用功能。
第4步:定义格式化模板并执行
目的:将Date对象按照指定样式(如“年-月-日 时:分:秒”)转换为字符串。
- 模式说明: yyyy代表四位年份,MM代表两位月份,dd代表日期,hh:mm:ss代表时分秒。
- 代码实现:
Date date = new Date();
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String timeStr = df.format(date);
System.out.println(timeStr);
星期相关运算
在处理排期或考勤系统时,常需计算某一天是一年中的第几周,或者反推某个周的日期。
第5步:计算特定日期是一年中的第几周
设置好年月日后,直接调用 WEEK_OF_YEAR 属性即可获取。
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, 2006);
cal.set(Calendar.MONTH, 8); // 实际上是9月
cal.set(Calendar.DAY_OF_MONTH, 3);
int weekNo = cal.get(Calendar.WEEK_OF_YEAR);
第6步:根据年和周号推算具体日期
若已知某年第1周且想要找出该周周一是哪天:
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, 2006);
cal.set(Calendar.WEEK_OF_YEAR, 1);
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
System.out.println(df.format(cal.getTime())); // 输出示例:2006-01-02
时间加减法:add() 与 roll() 的区别
虽然不常用,但在某些特定业务逻辑下二者区别明显。关键在于是否引发上级单位(如月、年)的进位变化。
第7步:测试 add() 的全局进位特性
add(field, amount) 会对指定的时间字段进行加减,并会向上进位或借位。
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
Calendar cal = Calendar.getInstance();
cal.set(2006, Calendar.SEPTEMBER, 3);
cal.add(Calendar.DATE, -4);
System.out.println(df.format(cal.getTime())); // 结果:2006-08-30 (跨越了月份)
cal.add(Calendar.DATE, 4);
System.out.println(df.format(cal.getTime())); // 恢复:2006-09-03
第8步:测试 roll() 的本级循环特性
roll(field, amount) 仅在当前字段内循环,不会改变比它大的字段值。
// 接上例环境,重置回9月3日
cal.set(2006, Calendar.SEPTEMBER, 3);
cal.roll(Calendar.DATE, -4);
// 如果原日期是9月3日,减4天后不会变成8月底,而是在当月循环
date = cal.getTime();
System.out.println(df.format(date));
cal.roll(Calendar.DATE, 4);
date = cal.getTime();
System.out.println(df.format(date));
// 可见roll()用于不需要改变年月的大小时
建议: 除非有特殊需求,一般日期计算优先使用 add()。
计算两个时间段的间隔天数
计算日期间隔是常见需求,以下是三种常见的实现方式,精度依次递增。
第9步:基于毫秒差计算(简单但可能有误差)
适用于粗略计算,直接相减后除以一天的毫秒数(1000 * 60 * 60 * 24)。为防止start晚于end,应先做交换处理。
public int getIntervalDays(Calendar startday, Calendar endday) {
if (startday.after(endday)) {
Calendar cal = startday;
startday = endday;
endday = cal;
}
long sl = startday.getTimeInMillis();
long el = endday.getTimeInMillis();
long ei = el - sl;
return (int) (ei / (1000 * 60 * 60 * 24));
}
第10步:传入 Date 对象的同名方法
逻辑同上,只是获取时间戳的方式改为 getTime()。
public int getIntervalDays(Date startday, Date endday) {
if (startday.after(endday)) {
Date cal = startday;
startday = endday;
endday = cal;
}
long sl = startday.getTime();
long el = endday.getTime();
long ei = el - sl;
return (int) (ei / (1000 * 60 * 60 * 24));
}
第11步:改进的精确跨天计算(处理跨年多天问题)
上述方法直接用毫秒除可能会因为夏令时或微小时差产生1天的误差。更严谨的做法是利用 DAY_OF_YEAR 累加每年的天数来处理跨年情况。
public int getDaysBetween(Calendar d1, Calendar d2) {
if (d1.after(d2)) {
java.util.Calendar swap = d1;
d1 = d2;
d2 = swap;
}
int days = d2.get(Calendar.DAY_OF_YEAR) - d1.get(Calendar.DAY_OF_YEAR);
int y2 = d2.get(Calendar.YEAR);
if (d1.get(Calendar.YEAR) != y2) {
d1 = (Calendar) d1.clone();
do {
days += d1.getActualMaximum(Calendar.DAY_OF_YEAR);
d1.add(Calendar.YEAR, 1);
} while (d1.get(Calendar.YEAR) != y2);
}
return days;
}
日期与其他类型的相互转换
在实际应用中,往往涉及到 String、Long 和 SQL Date 之间的转换。
第12步:String 转为 Date 再转 Long
用于从文本中提取时间进行跨度比较。注意 parse 抛出的异常需在外部处理。
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("M/dd/yyyy hh:mm:ss a", java.util.Locale.US);
java.util.Date d = sdf.parse("5/13/2003 10:31:37 AM");
long dvalue = d.getTime();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String mDateTime1 = formatter.format(d);
第13步:数据库专用日期类型转换(SQL Date & Timestamp)
JDBC编程中,Oracle的DATE只需年月日,对应 java.sql.Date;SQL Server的DateTime含时分秒,对应 java.sql.Timestamp。
A. 字符串转 java.sql.Date
public final static java.sql.Date string2Date(String dateString) throws Exception {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH);
dateFormat.setLenient(false); // 严格校验
java.util.Date timeDate = dateFormat.parse(dateString);
java.sql.Date dateTime = new java.sql.Date(timeDate.getTime());
return dateTime;
}
B. 字符串转 java.sql.Timestamp
public final static java.sql.Timestamp string2Time(String dateString) throws Exception {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd kk:mm:ss.SSS", Locale.ENGLISH);
dateFormat.setLenient(false);
java.util.Date timeDate = dateFormat.parse(dateString);
java.sql.Timestamp dateTime = new java.sql.Timestamp(timeDate.getTime());
return dateTime;
}
C. Date 直接转 Timestamp
// 方法一:利用getTime
Timestamp t = new Timestamp(new Date().getTime());
// 方法二:逐个获取日历字段构造
Timestamp tt = new Timestamp(
Calendar.getInstance().get(Calendar.YEAR) - 1900,
Calendar.getInstance().get(Calendar.MONTH),
Calendar.getInstance().get(Calendar.DATE),
Calendar.getInstance().get(Calendar.HOUR),
Calendar.getInstance().get(Calendar.MINUTE),
Calendar.getInstance().get(Calendar.SECOND), 0
);
以上就是Java时间处理核心要点的详细内容,更多关于Java开发技巧的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













