这期总结了Java中常用的关于日期和时间的接口,代码在后面的 DateUtil 类中。顺便讨论了一下时区。文章尽量做到精简
表示时间的形式在 Java 里,表示时间通常有3种形式
- 时间戳
- Date (java.util.Date)
- 字符串
(不讨论LocalDateTime之类的)
例如
- 时间戳: System.currentTimeMillis() 的值
- Date:你经常 new Date()
- 字符串: 比如 2015-04-04 16:22:01,或者 2015-04-04
上述3种情况
-
时间戳是不带时区的
时间戳是绝对的值,是当前这一刻(无论你在什么时区) 距离零时区1970年1月1日的毫秒数,所以时间戳是没有时区的
-
new Date() (
java.util.Date
) 也是没有时区概念的Date其里面存放的值是 System.currentTimeMillis() ,但是 toString() 方法会根据本地时区(即操作系统的时区)转成相应的字串,其本身是不带时区的!! 这点太容易混淆
SimpleDateFormat 是我们常用的类,用来把 Date 格式化成时间字符串,这个是可以设定时区的,Date 本身没有时区,要得到指定时区的时间字符串,需要对 SimpleDateFormat 设置时区
sdf.setTimeZone(TimeZone zone);
-
日期格式的字符串
是有时区的,比如 2015-04-04 16:22:01,或者 2015-04-04,这些表示方法都是没有时区概念的
附 DateUtil.java
/**
* @author Stone
* @version V1.0.0
* @date 2021/3/18
*/
public class DateUtil {
/**
* 常用时间格式
*/
public static final String Y_M_D_H_M_S = "yyyy-MM-dd HH:mm:ss";
public static final String Y_M_D = "yyyy-MM-dd";
public static final String YMD = "yyyyMMdd";
public static final String Y_M_D_H_M_S_SSS = "yyyy-MM-dd HH:mm:ss.SSS";
//public static final String DATE_FORMAT_UTC_TEMPLATE = "yyyy-MM-dd'T'HH:mm:ss'Z'";
//public static final String DATE_FORMAT_UTC_TEMPLATE = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
/**
* 常用时区
*/
public static class TZ {
public static final TimeZone UTC = TimeZone.getTimeZone("GMT+00:00");
public static final TimeZone BEIJING = TimeZone.getTimeZone("GMT+08:00");
public static final TimeZone TOKYO = TimeZone.getTimeZone("GMT+09:00");
public static final TimeZone LOCAL = localTimeZone();
}
/**
* 获取本地时区(指当前的时区,即Java程序所在JVM,JVM所在的操作系统的时区)
*
* @return 本地时区
*/
public static TimeZone localTimeZone() {
return TimeZone.getDefault();
}
/************************************ 时间类型互转,字串,Date,long BEGIN ************************************/
/**
* 时间戳转字串(本地时区)
*
* @param timestampWithMillis 时间戳,精确到毫秒,例如 System.currentTimeMillis() 的值
* @param destDateFormat 要转成什么样的字串格式
* @return 本地时区的日期时间的字串形式
*/
public static String long2Str(long timestampWithMillis, String destDateFormat) {
return long2StrTz(timestampWithMillis, destDateFormat, localTimeZone());
}
public static String long2StrUTC(long timestampWithMillis, String destDateFormat) {
return long2StrTz(timestampWithMillis, destDateFormat, TZ.UTC);
}
/**
* 时间戳转字串(指定时区)
*
* @param timestampWithMillis 时间戳,精确到毫秒,例如 System.currentTimeMillis() 的值
* @param destDateFormat 要转成什么样的字串格式
* @param destTimeZone 目的时区,即时间戳要转成什么时区。参考本类中定义的常用时区。
* @return 指定时区的日期时间的字串形式
*/
public static String long2StrTz(long timestampWithMillis, String destDateFormat, TimeZone destTimeZone) {
SimpleDateFormat sdf = new SimpleDateFormat(destDateFormat);
sdf.setTimeZone(destTimeZone);
return sdf.format(timestampWithMillis);
}
/**
* 时间戳转 Date
*
*
* 注意:Date 是没有时区概念的,其内部保存了时间戳,toString() 时根据本地时区转成字串而已
*
*
* @param timestampWithMillis 时间戳,到达毫秒级,如 System.currentTimeMillis()
* @return 返回 java.util.Date
*/
public static Date long2Date(long timestampWithMillis) {
Date date = new Date(timestampWithMillis);
return date;
}
/**
* Date 转字串(本地时区)
*
* @param date 日期
* @param destDateFormat 输出的字串格式
* @return 本地时区的字串形式
*/
public static String date2Str(Date date, String destDateFormat) {
return date2StrTz(date, destDateFormat, localTimeZone());
}
public static String date2StrUTC(Date date, String destDateFormat) {
return date2StrTz(date, destDateFormat, TZ.UTC);
}
/**
* Date 转字串(指定时区)
*
* @param date 日期
* @param destDateFormat 格式
* @param destTimeZone 转成什么时区的字串
* @return 指定时区的字串形式
*/
public static String date2StrTz(Date date, String destDateFormat, TimeZone destTimeZone) {
SimpleDateFormat sdf = new SimpleDateFormat(destDateFormat);
sdf.setTimeZone(destTimeZone);
return sdf.format(date);
}
/**
* Date 转时间戳
*
* @param date 日期时间
* @return 时间戳
*/
public static long date2long(Date date) {
return date.getTime();
}
/**
* 字串(本地时区)转 Date
*
*
* 注意:该方法把传入的日期字串当成是本地时区来进行转换的。
*
* 比如同样是 2017-04-02 15:33:08,在不同时区,
* 返回的Date里的时间戳的值是不一样的!!即 date.getTime() 得到不一样的值
*
* 北京时区(东八区)
* Sun Apr 02 15:33:08 CST 2017
* 1491118388000
* 东京时区(东九区)
* Sun Apr 02 15:33:08 JST 2017
* 1491114788000
*
*
* @param localDateStr 待转换的字串
* @param formatOfThisDateStr 字串的格式
* @return 返回 "把该字串认为是本地时区的 java.util.Date"
*/
public static Date str2Date(String localDateStr, String formatOfThisDateStr) {
return str2DateTz(localDateStr, formatOfThisDateStr, localTimeZone());
}
public static Date str2DateUTC(String utcDateStr, String formatOfThisDateStr) {
return str2DateTz(utcDateStr, formatOfThisDateStr, localTimeZone());
}
/**
* 字串(本地时区)转 Date
*
* @param dateStr 待转换的字串
* @param formatOfThisDateStr 字串的格式
* @param timeZoneOfThisDateStr 字串的时区
* @return 返回 "把该字串认为是本地时区的 java.util.Date"
*/
public static Date str2DateTz(String dateStr, String formatOfThisDateStr, TimeZone timeZoneOfThisDateStr) {
try {
SimpleDateFormat sdf = new SimpleDateFormat(formatOfThisDateStr);
sdf.setTimeZone(timeZoneOfThisDateStr);
return sdf.parse(dateStr);
} catch (ParseException e) {
throw new IllegalArgumentException(e);
}
}
/**
* 字串(本地时区)转时间戳
*
* @param dateStr 待转换的字串
* @param formatOfThisDateStr 字串的时区
* @return 返回 "把该字串认为是本地时区的时间戳"
*/
public static long str2long(String dateStr, String formatOfThisDateStr) {
return str2longTz(dateStr, formatOfThisDateStr, localTimeZone());
}
public static long str2longUTC(String dateStr, String formatOfThisDateStr) {
return str2longTz(dateStr, formatOfThisDateStr, TZ.UTC);
}
/**
* 字串(指定时区)转时间戳
*
* @param dateStr 待转换的字串
* @param formatOfThisDateStr 字串的时区
* @param timeZoneOfThisDateStr
* @return 返回 "把该字串认为是指定时区的时间戳"
*/
public static long str2longTz(String dateStr, String formatOfThisDateStr, TimeZone timeZoneOfThisDateStr) {
return date2long(str2DateTz(dateStr, formatOfThisDateStr, timeZoneOfThisDateStr));
}
/**
* 传入时间字串,指定格式和时区,转换成指定的时区的时间字串
*
* @param srcDateString 源字串
* @param srcDateFormat 源字串的格式
* @param srcTimeZone 源字串的时区
* @param destDateFormat 目的字串的格式
* @param destTimeZone 目的字串的时区
* @return 返回指定时区、指定格式的字串
*/
public static String str2str(String srcDateString,
String srcDateFormat,
TimeZone srcTimeZone,
String destDateFormat,
TimeZone destTimeZone
) {
SimpleDateFormat srcSdf = new SimpleDateFormat(srcDateFormat);
srcSdf.setTimeZone(srcTimeZone);
SimpleDateFormat destSdf = new SimpleDateFormat(destDateFormat);
destSdf.setTimeZone(destTimeZone);
Date sourceDate;
try {
sourceDate = srcSdf.parse(srcDateString);
return destSdf.format(sourceDate);
} catch (ParseException e) {
throw new RuntimeException("Can not parse date", e);
}
}
/************************************ 时间类型互转,字串,Date,long END ************************************/
/************************************ 获取时间 BEGIN ************************************/
/**
* 获取本地日期时间
*
* 这个 Date 其实是没有时区概念的,其里面存放的值是 System.currentTimeMillis() 的值
* 但是 toString() 方法会根据系统时区来转成相应的字串
*
*
* @return 返回 java.util.Date
*/
public static Date now() {
return new Date();
}
/**
* 获取 java.util.Date
*
* @return 获取日期部分(去掉了时分秒和毫秒)
*/
public static Date nowDate() {
return datePart(now());
}
/**
* 获取时间戳(到达毫秒,13位数字)
*
* @return 实际能不能精度达到毫秒,要看操作系统,详细参考 System.currentTimeMillis() 内的 javadoc
*/
private long currentTimeMillis() {
return System.currentTimeMillis();
}
/**
* 获取时间戳,精确到秒(也叫Unix时间戳,10位数字)
*
* @return 返回Unix时间戳(仅到达秒)
*/
private long currentTimeSecs() {
return System.currentTimeMillis() / 1000L;
}
/**
* 获取日期部分
*
* @param date 日期时间
* @return 返回只要日期部分的Date(注意 : 重新new了一个Date , 入参得到Date不变化)
*/
public static Date datePart(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
// 必须设置这个,否则毫秒数不同会导致compareDate方法在毫秒数上有差异
cal.set(Calendar.MILLISECOND, 0);
return cal.getTime();
}
/************************************ 获取时间 END ************************************/
/************************************ 时间顺序 BEGIN ************************************/
/**
* 获得日期是星期几
*
* @param date 日期时间
* @return 返回1~7分别代表周一到周日
*/
public static int getDayOfWeek(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
int index = cal.get(Calendar.DAY_OF_WEEK);
switch (index) {
case 1:
return 7;
case 2:
return 1;
case 3:
return 2;
case 4:
return 3;
case 5:
return 4;
case 6:
return 5;
default:
return 6;
}
}
/**
* 获得日期是当月第几天,从1开始
*
* @param date 日期时间
* @return 返回第几天, 从1开始
*/
public static int getDayOfMonth(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
int index = cal.get(Calendar.DAY_OF_MONTH);
return index;
}
/**
* 获得某个日期所在月份一共有多少天
*
* @param date 日期时间
* @return 日期所在月份有多少天
*/
public static int getHowManyDaysInMonth(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
return cal.getActualMaximum(Calendar.DATE);
}
/**
* 获得指定日期所在当月第一天(时间部分会保留)
*
* @param date 日期时间
* @return 日期所在月份的开始那天
*/
public static Date getStartDayOfMonth(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.set(Calendar.DATE, 1);
return cal.getTime();
}
/**
* 获得指定日期所在当月最后一天(时间部分会保留), 能正确识别月份不同天数
*
* @param date 日期时间
* @return 日期所在月份最后一天
*/
public static Date getLastDayOfMonth(Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.set(Calendar.DATE, 1);
cal.add(Calendar.MONTH, 1);
cal.add(Calendar.DATE, -1);
return cal.getTime();
}
/************************************ 时间顺序 END ************************************/
/************************************ 时间比较 BEGIN ************************************/
/**
* 判断两个日期时间是否相等,连秒、毫秒都必须相等
*
* @param date1 日期时间1
* @param date2 日期时间2
* @return true则相等,反之不等
*/
public static boolean isEqualDateTime(Date date1, Date date2) {
return date1.getTime() == date2.getTime();
}
/**
* 仅仅比较日期部分是否相等, 不比较时间部分
* 相等: 2015-08-19 14:28:47 和 2015-08-19 14:28:51、2015-08-18 和 2015-08-18
* 不等: 2015-08-18 和 2015-08-19、2015-08-19 14:32:51和2015-08-18 14:32:57
*
* @param date1 日期1
* @param date2 日期2
* @return true则相等,反之不等
*/
public static boolean isEqualDate(Date date1, Date date2) {
date1 = datePart(date1);
date2 = datePart(date2);
return isEqualDateTime(date1, date2);
}
/**
* 比较日期时间先后顺序
* 辅助理解: 1.所谓时间大于,未来的时间比现在大
* 2.看着入参列出等式,如date1-date2,结果是1就表示大于0,即date1-date2>0亦即date1>date2
*
* @param date1
* @param date2
* @return date1>date2返回1,date1date2返回1,date1
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?