add LocalDateTimeUtil

This commit is contained in:
Looly 2020-07-07 12:51:39 +08:00
parent 25b9d61ffd
commit c12557eac4
7 changed files with 455 additions and 9 deletions

View File

@ -3,13 +3,14 @@
-------------------------------------------------------------------------------------------------------------
## 5.3.9 (2020-07-06)
## 5.3.9 (2020-07-07)
### 新特性
* 【core 】 DateUtil增加formatChineseDatepr#932@Github
* 【core 】 ArrayUtil.isEmpty修改逻辑pr#948@Github
* 【core 】 增强StrUtil中空判断后返回数据性能pr#949@Github
* 【core 】 deprecate掉millsecond改为millisecondissue#I1M9P8@Github
* 【core 】 deprecate掉millsecond改为millisecondissue#I1M9P8@Gitee
* 【core 】 增加LocalDateTimeUtilissue#I1KUVC@Gitee
### Bug修复
* 【core 】 修复NumberUtil.partValue有余数问题issue#I1KX66@Gitee

View File

@ -76,6 +76,7 @@ public class DatePattern {
* ISO8601日期时间格式精确到毫秒yyyy-MM-dd HH:mm:ss,SSS
*/
public static final String ISO8601_PATTERN = "yyyy-MM-dd HH:mm:ss,SSS";
/**
* ISO8601日期时间格式精确到毫秒 {@link FastDateFormat}yyyy-MM-dd HH:mm:ss,SSS
*/
@ -155,6 +156,15 @@ public class DatePattern {
*/
public static final FastDateFormat JDK_DATETIME_FORMAT = FastDateFormat.getInstance(JDK_DATETIME_PATTERN, Locale.US);
/**
* UTC时间yyyy-MM-dd'T'HH:mm:ss
*/
public static final String UTC_SIMPLE_PATTERN = "yyyy-MM-dd'T'HH:mm:ss";
/**
* UTC时间{@link FastDateFormat}yyyy-MM-dd'T'HH:mm:ss
*/
public static final FastDateFormat UTC_SIMPLE_FORMAT = FastDateFormat.getInstance(UTC_SIMPLE_PATTERN, TimeZone.getTimeZone("UTC"));
/**
* UTC时间yyyy-MM-dd'T'HH:mm:ss'Z'
*/

View File

@ -834,6 +834,9 @@ public class DateUtil extends CalendarUtil {
} else if (length == DatePattern.UTC_MS_WITH_ZONE_OFFSET_PATTERN.length() + 2 || length == DatePattern.UTC_MS_WITH_ZONE_OFFSET_PATTERN.length() + 3) {
// 格式类似2018-09-13T05:34:31.999+0800 2018-09-13T05:34:31.999+08:00
return parse(utcString, DatePattern.UTC_MS_WITH_ZONE_OFFSET_FORMAT);
} else if(length == DatePattern.UTC_SIMPLE_PATTERN.length()-2){
// 格式类似2018-09-13T05:34:31
return parse(utcString, DatePattern.UTC_SIMPLE_FORMAT);
}
}
// 没有更多匹配的时间格式
@ -1868,9 +1871,10 @@ public class DateUtil extends CalendarUtil {
* @param instant {@link Instant}
* @return {@link LocalDateTime}
* @since 5.0.5
* @see LocalDateTimeUtil#of(Instant)
*/
public static LocalDateTime toLocalDateTime(Instant instant) {
return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
return LocalDateTimeUtil.of(instant);
}
/**
@ -1879,10 +1883,10 @@ public class DateUtil extends CalendarUtil {
* @param date {@link Date}
* @return {@link LocalDateTime}
* @since 5.0.5
* @see LocalDateTimeUtil#of(Date)
*/
public static LocalDateTime toLocalDateTime(Date date) {
final DateTime dateTime = date(date);
return LocalDateTime.ofInstant(dateTime.toInstant(), dateTime.getZoneId());
return LocalDateTimeUtil.of(date);
}
/**

View File

@ -0,0 +1,305 @@
package cn.hutool.core.date;
import cn.hutool.core.util.ObjectUtil;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalUnit;
import java.util.Date;
import java.util.TimeZone;
/**
* JDK8+中的{@link LocalDateTime} 工具类封装
*
* @author looly
* @since 5.3.9
*/
public class LocalDateTimeUtil {
/**
* 当前时间默认时区
*
* @return {@link LocalDateTime}
*/
public static LocalDateTime now() {
return LocalDateTime.now();
}
/**
* {@link Instant}{@link LocalDateTime}使用默认时区
*
* @param instant {@link Instant}
* @return {@link LocalDateTime}
*/
public static LocalDateTime of(Instant instant) {
return of(instant, ZoneId.systemDefault());
}
/**
* {@link Instant}{@link LocalDateTime}使用UTC时区
*
* @param instant {@link Instant}
* @return {@link LocalDateTime}
*/
public static LocalDateTime ofUTC(Instant instant) {
return of(instant, ZoneId.of("UTC"));
}
/**
* {@link ZonedDateTime}{@link LocalDateTime}
*
* @param zonedDateTime {@link ZonedDateTime}
* @return {@link LocalDateTime}
*/
public static LocalDateTime of(ZonedDateTime zonedDateTime) {
if (null == zonedDateTime) {
return null;
}
return zonedDateTime.toLocalDateTime();
}
/**
* {@link Instant}{@link LocalDateTime}
*
* @param instant {@link Instant}
* @param zoneId 时区
* @return {@link LocalDateTime}
*/
public static LocalDateTime of(Instant instant, ZoneId zoneId) {
if (null == instant) {
return null;
}
return LocalDateTime.ofInstant(instant, ObjectUtil.defaultIfNull(zoneId, ZoneId.systemDefault()));
}
/**
* {@link Instant}{@link LocalDateTime}
*
* @param instant {@link Instant}
* @param timeZone 时区
* @return {@link LocalDateTime}
*/
public static LocalDateTime of(Instant instant, TimeZone timeZone) {
if (null == instant) {
return null;
}
return of(instant, ObjectUtil.defaultIfNull(timeZone, TimeZone.getDefault()).toZoneId());
}
/**
* 毫秒转{@link LocalDateTime}使用默认时区
*
* <p>注意此方法使用默认时区如果非UTC会产生时间偏移</p>
*
* @param epochMilli 从1970-01-01T00:00:00Z开始计数的毫秒数
* @return {@link LocalDateTime}
*/
public static LocalDateTime of(long epochMilli) {
return of(Instant.ofEpochMilli(epochMilli));
}
/**
* 毫秒转{@link LocalDateTime}使用UTC时区
*
* @param epochMilli 从1970-01-01T00:00:00Z开始计数的毫秒数
* @return {@link LocalDateTime}
*/
public static LocalDateTime ofUTC(long epochMilli) {
return ofUTC(Instant.ofEpochMilli(epochMilli));
}
/**
* 毫秒转{@link LocalDateTime}根据时区不同结果会产生时间偏移
*
* @param epochMilli 从1970-01-01T00:00:00Z开始计数的毫秒数
* @param zoneId 时区
* @return {@link LocalDateTime}
*/
public static LocalDateTime of(long epochMilli, ZoneId zoneId) {
return of(Instant.ofEpochMilli(epochMilli), zoneId);
}
/**
* 毫秒转{@link LocalDateTime}结果会产生时间偏移
*
* @param epochMilli 从1970-01-01T00:00:00Z开始计数的毫秒数
* @param timeZone 时区
* @return {@link LocalDateTime}
*/
public static LocalDateTime of(long epochMilli, TimeZone timeZone) {
return of(Instant.ofEpochMilli(epochMilli), timeZone);
}
/**
* {@link Date}{@link LocalDateTime}使用默认时区
*
* @param date Date对象
* @return {@link LocalDateTime}
*/
public static LocalDateTime of(Date date) {
if (null == date) {
return null;
}
if (date instanceof DateTime) {
return of(date.toInstant(), ((DateTime) date).getZoneId());
}
return of(date.toInstant());
}
/**
* {@link Date}{@link LocalDateTime}使用默认时区
*
* @param temporalAccessor {@link TemporalAccessor}
* @return {@link LocalDateTime}
*/
public static LocalDateTime of(TemporalAccessor temporalAccessor) {
if (null == temporalAccessor) {
return null;
}
if(temporalAccessor instanceof LocalDate){
return ((LocalDate)temporalAccessor).atStartOfDay();
}
return LocalDateTime.of(
TemporalAccessorUtil.get(temporalAccessor, ChronoField.YEAR),
TemporalAccessorUtil.get(temporalAccessor, ChronoField.MONTH_OF_YEAR),
TemporalAccessorUtil.get(temporalAccessor, ChronoField.DAY_OF_MONTH),
TemporalAccessorUtil.get(temporalAccessor, ChronoField.HOUR_OF_DAY),
TemporalAccessorUtil.get(temporalAccessor, ChronoField.MINUTE_OF_HOUR),
TemporalAccessorUtil.get(temporalAccessor, ChronoField.SECOND_OF_MINUTE),
TemporalAccessorUtil.get(temporalAccessor, ChronoField.NANO_OF_SECOND)
);
}
/**
* 解析日期时间字符串为{@link LocalDateTime}仅支持yyyy-MM-dd'T'HH:mm:ss格式例如2007-12-03T10:15:30
*
* @param text 日期时间字符串
* @return {@link LocalDateTime}
*/
public static LocalDateTime parse(CharSequence text) {
return parse(text, (DateTimeFormatter)null);
}
/**
* 解析日期时间字符串为{@link LocalDateTime}格式支持日期时间日期时间
*
* @param text 日期时间字符串
* @param formatter 日期格式化器预定义的格式见{@link DateTimeFormatter}
* @return {@link LocalDateTime}
*/
public static LocalDateTime parse(CharSequence text, DateTimeFormatter formatter) {
if (null == text) {
return null;
}
if (null == formatter) {
return LocalDateTime.parse(text);
}
return of(formatter.parse(text));
}
/**
* 解析日期时间字符串为{@link LocalDateTime}
*
* @param text 日期时间字符串
* @param format 日期格式类似于yyyy-MM-dd HH:mm:ss,SSS
* @return {@link LocalDateTime}
*/
public static LocalDateTime parse(CharSequence text, String format) {
if (null == text) {
return null;
}
return parse(text, DateTimeFormatter.ofPattern(format));
}
/**
* 格式化日期时间为指定格式
*
* @param time {@link LocalDateTime}
* @param formatter 日期格式化器预定义的格式见{@link DateTimeFormatter}
* @return 格式化后的字符串
*/
public static String format(LocalDateTime time, DateTimeFormatter formatter) {
if (null == time) {
return null;
}
return time.format(formatter);
}
/**
* 格式化日期时间为指定格式
*
* @param time {@link LocalDateTime}
* @param format 日期格式类似于yyyy-MM-dd HH:mm:ss,SSS
* @return 格式化后的字符串
*/
public static String format(LocalDateTime time, String format) {
if (null == time) {
return null;
}
return format(time, DateTimeFormatter.ofPattern(format));
}
/**
* 日期偏移,根据field不同加不同值偏移会修改传入的对象
*
* @param time {@link LocalDateTime}
* @param number 偏移量正数为向后偏移负数为向前偏移
* @param field 偏移单位{@link ChronoField}不能为null
* @return 偏移后的日期时间
*/
public static LocalDateTime offset(LocalDateTime time, long number, TemporalUnit field) {
if (null == time) {
return null;
}
return time.plus(number, field);
}
/**
* 获取两个日期的差如果结束时间早于开始时间获取结果为负
* <p>
* 返回结果为{@link Duration}对象通过调用toXXX方法返回相差单位
*
* @param startTime 开始时间
* @param endTime 结束时间
* @return 时间差 {@link Duration}对象
*/
public static Duration between(LocalDateTime startTime, LocalDateTime endTime) {
return Duration.between(startTime, endTime);
}
/**
* 修改为一天的开始时间例如2020-02-02 00:00:00,000
*
* @param time 日期时间
* @return 一天的开始时间
*/
public static LocalDateTime beginOfDay(LocalDateTime time) {
return time.with(LocalTime.of(0, 0, 0, 0));
}
/**
* 修改为一天的结束时间例如2020-02-02 23:59:59,999
*
* @param time 日期时间
* @return 一天的结束时间
*/
public static LocalDateTime endOfDay(LocalDateTime time) {
return time.with(LocalTime.of(23, 59, 59, 999_999_999));
}
}

View File

@ -0,0 +1,28 @@
package cn.hutool.core.date;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalField;
/**
* {@link TemporalAccessor} 工具类封装
*
* @author looly
* @since 5.3.9
*/
public class TemporalAccessorUtil {
/**
* 安全获取时间的某个属性属性不存在返回0
*
* @param temporalAccessor 需要获取的时间对象
* @param field 需要获取的属性
* @return 时间的值如果无法获取则默认为 0
*/
public static int get(TemporalAccessor temporalAccessor, TemporalField field) {
if (temporalAccessor.isSupported(field)) {
return temporalAccessor.get(field);
}
return (int)field.range().getMinimum();
}
}

View File

@ -0,0 +1,99 @@
package cn.hutool.core.date;
import org.junit.Assert;
import org.junit.Test;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
public class LocalDateTimeUtilTest {
@Test
public void nowTest() {
Assert.assertNotNull(LocalDateTimeUtil.now());
}
@Test
public void ofTest() {
String dateStr = "2020-01-23T12:23:56";
final DateTime dt = DateUtil.parse(dateStr);
LocalDateTime of = LocalDateTimeUtil.of(dt);
Assert.assertNotNull(of);
Assert.assertEquals(dateStr, of.toString());
of = LocalDateTimeUtil.ofUTC(dt.getTime());
Assert.assertEquals(dateStr, of.toString());
}
@Test
public void parseTest() {
final LocalDateTime localDateTime = LocalDateTimeUtil.parse("2020-01-23T12:23:56", DateTimeFormatter.ISO_DATE_TIME);
Assert.assertEquals("2020-01-23T12:23:56", localDateTime.toString());
}
@Test
public void parseTest2() {
final LocalDateTime localDateTime = LocalDateTimeUtil.parse("2020-01-23", DatePattern.NORM_DATE_PATTERN);
Assert.assertEquals("2020-01-23T00:00", localDateTime.toString());
}
@Test
public void parseTest3() {
final LocalDateTime localDateTime = LocalDateTimeUtil.parse("12:23:56", DatePattern.NORM_TIME_PATTERN);
Assert.assertEquals("12:23:56", localDateTime.toLocalTime().toString());
}
@Test
public void parseTest4() {
final LocalDateTime localDateTime = LocalDateTimeUtil.parse("2020-01-23T12:23:56");
Assert.assertEquals("2020-01-23T12:23:56", localDateTime.toString());
}
@Test
public void formatTest() {
final LocalDateTime localDateTime = LocalDateTimeUtil.parse("2020-01-23T12:23:56");
String format = LocalDateTimeUtil.format(localDateTime, DatePattern.NORM_DATETIME_PATTERN);
Assert.assertEquals("2020-01-23 12:23:56", format);
format = LocalDateTimeUtil.format(localDateTime, DatePattern.NORM_DATE_PATTERN);
Assert.assertEquals("2020-01-23", format);
}
@Test
public void offset() {
final LocalDateTime localDateTime = LocalDateTimeUtil.parse("2020-01-23T12:23:56");
LocalDateTime offset = LocalDateTimeUtil.offset(localDateTime, 1, ChronoUnit.DAYS);
// 非同一对象
Assert.assertNotSame(localDateTime, offset);
Assert.assertEquals("2020-01-24T12:23:56", offset.toString());
offset = LocalDateTimeUtil.offset(localDateTime, -1, ChronoUnit.DAYS);
Assert.assertEquals("2020-01-22T12:23:56", offset.toString());
}
@Test
public void between() {
final Duration between = LocalDateTimeUtil.between(
LocalDateTimeUtil.parse("2019-02-02T00:00:00"),
LocalDateTimeUtil.parse("2020-02-02T00:00:00"));
Assert.assertEquals(365, between.toDays());
}
@Test
public void beginOfDayTest() {
final LocalDateTime localDateTime = LocalDateTimeUtil.parse("2020-01-23T12:23:56");
final LocalDateTime beginOfDay = LocalDateTimeUtil.beginOfDay(localDateTime);
Assert.assertEquals("2020-01-23T00:00", beginOfDay.toString());
}
@Test
public void endOfDayTest() {
final LocalDateTime localDateTime = LocalDateTimeUtil.parse("2020-01-23T12:23:56");
final LocalDateTime endOfDay = LocalDateTimeUtil.endOfDay(localDateTime);
Assert.assertEquals("2020-01-23T23:59:59.999999999", endOfDay.toString());
}
}

View File

@ -1,8 +1,5 @@
package cn.hutool.db.nosql.redis;
import java.io.Closeable;
import java.io.IOException;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.setting.Setting;
@ -11,6 +8,8 @@ import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.Protocol;
import java.io.Closeable;
/**
* Jedis数据源
*
@ -174,7 +173,7 @@ public class RedisDS implements Closeable{
}
@Override
public void close() throws IOException {
public void close() {
IoUtil.close(pool);
}
}