>();
d、sql包中其实也有几个时间的类 java.sql.Date/Time/Timestamp
首先这几个类继承自util包中的Date类,相当于将java.util.Date分开表示了。Date表示年月日等信息。Time表示时分秒等信息。Timestamp多维护了纳秒,可以表示纳秒。平时用的不是很多。也是线程不安全的类。
2、java8以后的时间日期类
在java8以后新增加了date-time包
a、Instant
这个类在java8之前和之后的时间日期类中都提供了转换的方法,这样就能很明确的通过Instant这个中间变量实现,java8之前和之后的时间日期类的相互转换。但是我们需要注意的是,Instant主要维护的是秒和纳秒字段,可以表示纳秒范围,如果不符合转换条件,就会抛出异常。
以Date类为例,看一下源码:
复制代码
public static Date from(Instant instant) {
try {
return new Date(instant.toEpochMilli());
} catch (ArithmeticException ex) {
throw new IllegalArgumentException(ex);
}
}
/**
* Converts this {@code Date} object to an {@code Instant}.
*
* The conversion creates an {@code Instant} that represents the same
* point on the time-line as this {@code Date}.
*
* @return an instant representing the same point on the time-line as
* this {@code Date} object
* @since 1.8
*/
public Instant toInstant() {
return Instant.ofEpochMilli(getTime());
}
复制代码
b、Clock
有获取当前时间的方法,也可以获取当前Instant,Clock是有时区或者说时区偏移量的。Clock是一个抽象类,其内部有几个子类继承自Clock。
几个抽象方法:
复制代码
public abstract ZoneId getZone();
public abstract Clock withZone(ZoneId zone);
public long millis() {
return instant().toEpochMilli();
}
public abstract Instant instant();
复制代码
c、ZoneId/ZoneOffset/ZoneRules
ZoneId和ZoneOffset都是用来代表时区的偏移量的,一般ZoneOffset表示固定偏移量,ZoneOffset 表示与UTC时区偏移的固定区域(即UTC时间为标准),不跟踪由夏令时导致的区域偏移的更改;ZoneId 表示可变区偏移,表示区域偏移及其用于更改区域偏移的规则夏令时。这里举一个简单的例子,美国东部时间,我们可以使用zoneId来表示,应为美国使用的是冬令时和夏令时的时候时间是有区别的,和中国的时差会有一个小时的差别。而ZoneRules 跟踪区域偏移如何变化,时区的真正规则定义在ZoneRules中,定义了什么时候多少偏移量。
常用的几个:
复制代码
//美东时间
public static final String TIMEZONE_EST_NAME = "US/Eastern";
public static final ZoneId TIMEZONE_EST = ZoneId.of(TIMEZONE_EST_NAME);
//北京时间
public static final String TIMEZONE_GMT8_NAME = "GMT+8";
public static final ZoneId TIMEZONE_GMT8 = ZoneId.of(TIMEZONE_GMT8_NAME);
public static final ZoneOffset BEIJING_ZONE_OFFSET =ZoneOffset.of("+08:00");
public static final ZoneOffset STATISTIC_ZONE_OFFSET =ZoneOffset.of("+03:00");
private static final ZoneId NEW_YORK_ZONE_ID = ZoneId.of("America/New_York");
private static final ZoneId SHANGHAI_ZONE_ID = ZoneId.of("Asia/Shanghai");
复制代码
d、LocalDateTime/LocalTime/LocalDate/ZoneDateTime
LocalDateTime/LocalTime/LocalDate都没有时区的概念,其中LocalDate主要是对日期的操作,LocalTime主要是对时间的操作,LocalDateTime则是日期和时间都会涉及:
复制代码
jshell> LocalDate.now()
$46 ==> 2018-07-07
jshell> LocalDate.of(2018, 3, 30)
$47 ==> 2018-03-30
jshell> LocalTime.now()
$48 ==> 00:32:06.883656
jshell> LocalTime.of(12,43,12,33333);
$49 ==> 12:43:12.000033333
jshell> LocalDateTime.now()
$50 ==> 2018-07-07T00:32:30.335562400
jshell> LocalDateTime.of(2018, 12, 30, 12,33)
$51 ==> 2018-12-30T12:33
jshell> LocalDateTime.of(LocalDate.now(), LocalTime.now())
$52 ==> 2018-07-07T00:40:38.198318200
复制代码
而ZoneDateTime会带有时区和偏移量的,可以看看他的成员变量:
复制代码
/**
* The local date-time.
*/
private final LocalDateTime dateTime;
/**
* The offset from UTC/Greenwich.
*/
private final ZoneOffset offset;
/**
* The time-zone.
*/
private final ZoneId zone;
复制代码
可以看出这是集合了时间时区和偏移量的新的时间类。
二、常用的TimeUtils或者DateUtils的编写
复制代码
import java.text.ParseException;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.Hashtable;
import java.util.Map;
/**
* Created by hehuaichun on 2018/10/22.
*/
public class TimeUtils {
/**
* 考虑港股和美股 采用GMT-1时区来确定报表日 即T日的报表包含北京时间T日9时至T+1日9时的数据
*/
public static final ZoneId TIMEZONE_GMT_1 = ZoneId.of("GMT-1");
public static final String TIMEZONE_EST_NAME = "US/Eastern";
public static final ZoneId TIMEZONE_EST = ZoneId.of(TIMEZONE_EST_NAME);
public static final String TIMEZONE_GMT8_NAME = "GMT+8";
public static final ZoneId TIMEZONE_GMT8 = ZoneId.of(TIMEZONE_GMT8_NAME);
/**
* 常用时间转换格式
*/
public static final String TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
public static final String DATE_NO_GAP_FORMAT = "yyyyMMdd";
public static final String DATE_GAP_FORMAT = "yyyy-MM-dd";
public static final String TIME_HH_MM_FORMAT = "HHmm";
public static final Map DATE_TIME_FORMAT_MAP = new Hashtable() {
{
put(TIME_FORMAT, DateTimeFormatter.ofPattern(TIME_FORMAT));
put(DATE_NO_GAP_FORMAT, DateTimeFormatter.ofPattern(DATE_NO_GAP_FORMAT));
put(DATE_GAP_FORMAT, DateTimeFormatter.ofPattern(DATE_GAP_FORMAT));
put(TIME_HH_MM_FORMAT, DateTimeFormatter.ofPattern(TIME_HH_MM_FORMAT));
}
};
/**
* 根据format的格式获取相应的DateTimeFormatter对象
*
* @param format 时间转换格式字符串
* @return
*/
public static DateTimeFormatter getDateTimeFormatter(String format) {
if (DATE_TIME_FORMAT_MAP.containsKey(format)) {
return DATE_TIME_FORMAT_MAP.get(format);
} else {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);
DATE_TIME_FORMAT_MAP.put(format, formatter);
return formatter;
}
}
/**
* 获取当前日期的开始时间
*
* @param zoneId 时间偏移量
* @return
*/
public static LocalDateTime todayStart(ZoneId zoneId) {
return startOfDay(0, zoneId);
}
/**
* 获取当前的ZoneDateTime
*
* @param zoneId 时区偏移量
* @return
*/
public static ZonedDateTime now(ZoneId zoneId) {
return ZonedDateTime.now(zoneId);
}
/**
* 获取当前日期的开始时间ZonedDateTime
*
* @param date 日期
* @param zoneId 时区偏移量
* @return
*/
public static ZonedDateTime localDateToZoneDateTime(LocalDate date, ZoneId zoneId) {
return date.atStartOfDay(zoneId);
}
/**
* 获取当前日期的开始时间
*
* @param dateTime
* @return
*/
public static LocalDateTime startOfDay(ZonedDateTime dateTime) {
return dateTime.truncatedTo(ChronoUnit.DAYS).toLocalDateTime();
}
/**
* 获取今天后的指定天数的开始时间
*
* @param plusDays 当前多少天后
* @param zoneId 时区偏移量
* @return
*/
public static LocalDateTime startOfDay(int plusDays, ZoneId zoneId) {
return startOfDay(now(zoneId).plusDays(plusDays));
}
/**
* 获取指定日期的后几个工作日的时间LocalDate
*
* @param date 指定日期
* @param days 工作日数
* @return
*/
public static LocalDate plusWeekdays(LocalDate date, int days) {
if (days == 0) {
return date;
}
if (Math.abs(days) > 50) {
throw new IllegalArgumentException("days must be less than 50");
}
int i = 0;
int delta = days > 0 ? 1 : -1;
while (i < Math.abs(days)) {
date = date.plusDays(delta);
DayOfWeek dayOfWeek = date.getDayOfWeek();
if (dayOfWeek != DayOfWeek.SATURDAY && dayOfWeek != DayOfWeek.SUNDAY) {
i += 1;
}
}
return date;
}
/**
* 获取指定日期的后几个工作日的时间ZoneDateTime
*
* @param date
* @param days
* @return
*/
public static ZonedDateTime plusWeekdays(ZonedDateTime date, int days) {
return plusWeekdays(date.toLocalDate(), days).atStartOfDay(date.getZone());
}
/**
* 获取当前月份的第一天的时间ZoneDateTime
*
* @param zoneId
* @return
*/
public static ZonedDateTime firstDayOfMonth(ZoneId zoneId) {
return now(zoneId).withDayOfMonth(1);
}
/**
* 将Date转成指定时区的Date
*
* @param date
* @return
*/
public static Date dateToDate(Date date, ZoneId zoneId) {
LocalDateTime dt = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
return toDate(ZonedDateTime.of(dt, zoneId));
}
/**
* 将LocalDate转成Date
*
* @param date
* @return
*/
public static Date toDate(LocalDate date) {
return Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant());
}
/**
* ZonedDateTime 转换成Date
*
* @param dateTime
* @return
*/
public static Date toDate(ZonedDateTime dateTime) {
return Date.from(dateTime.toInstant());
}
/**
* String 转换成 Date
*
* @param date
* @param format
* @return
* @throws ParseException
*/
public static Date stringToDate(String date, String format, ZoneId zoneId) throws ParseException {
DateTimeFormatter formatter = getDateTimeFormatter(format).withZone(zoneId);
Instant instant = Instant.from(formatter.parse(date));
return Date.from(instant);
}
/**
* 将Date转成相应的时区的localDate
*
* @param date
* @param zoneId
* @return
*/
public static LocalDate toLocalDate(Date date, ZoneId zoneId) {
return date.toInstant().atZone(zoneId).toLocalDate();
}
/**
* 将Instant转成指定时区偏移量的localDate
*
* @param instant
* @param zoneId
* @return
*/
public static LocalDate toLocalDate(Instant instant, ZoneId zoneId) {
return instant.atZone(zoneId).toLocalDate();
}
/**
* 将Instant转换成指定时区偏移量的localDateTime
* @param instant
* @param zoneId
* @return
*/
public static LocalDateTime toLocalDateTime(Instant instant, ZoneId zoneId){
return instant.atZone(zoneId).toLocalDateTime();
}
/**
* 将Instant转成系统默认时区偏移量的LocalDateTime
* @param instant
* @return
*/
public static LocalDateTime toLocalDateTime(Instant instant){
return toLocalDateTime(instant, ZoneId.systemDefault());
}
/**
* 将ZoneDateTime 转成 指定时区偏移量的LocalDateTime
* @param zonedDateTime 时间
* @param zoneId 指定时区偏移量
* @return
*/
public static LocalDateTime toLocalDateTime(ZonedDateTime zonedDateTime, ZoneId zoneId){
return zonedDateTime.toInstant().atZone(zoneId).toLocalDateTime();
}
/**
*将ZoneDateTime 转成 LocalDateTime
* @param zonedDateTime
* @return
*/
public static LocalDateTime toLocalDateTime(ZonedDateTime zonedDateTime){
return zonedDateTime.toLocalDateTime();
}
/**
* String 转成 ZoneDateTime
* 需要类似 yyyy-MM-dd HH:mm:ss 需要日期和时间信息完整信息
*
* @param date
* @param format
* @param zoneId
* @return
*/
public static ZonedDateTime stringToZoneDateTime(String date, String format, ZoneId zoneId) {
DateTimeFormatter formatter = getDateTimeFormatter(format).withZone(zoneId);
return ZonedDateTime.parse(date, formatter);
}
/**
* 将时间戳long转成ZonedDateTime
*
* @param timeStamp
* @param zoneId
* @return
*/
public static ZonedDateTime longToZoneDateTime(long timeS