try {
String dateString = dateTimeFormatter.format(LocalDateTime.now());
TemporalAccessor temporalAccessor = dateTimeFormatter.parse(dateString);
String dateString2 = dateTimeFormatter.format(temporalAccessor);
System.out.println(Thread.currentThread().getName()+" 线程是否安全: "+dateString.equals(dateString2));
} catch (Exception e) {
e.printStackTrace();
System.out.println(Thread.currentThread().getName()+" 格式化失败 ");
}
}
}
}
![image-2021080591443373](https://img-blog.csdnimg.cn/img_convert/8dbddf627d283357f1765d17ba4a52fd.png)
使用DateTimeFormatter能保证线程安全,且效率也是挺高的。**适合高并发场景使用**。
###### 解决方案5:使用FastDateFormat 替换SimpleDateFormat
使用FastDateFormat 替换SimpleDateFormat(FastDateFormat 是线程安全的,Apache Commons Lang包支持,不受限于java版本)
public class FastDateFormatDemo6 {
private static FastDateFormat fastDateFormat = FastDateFormat.getInstance(“yyyy-MM-dd HH:mm:ss”);
public static void main(String[] args) {
//1、创建线程池
ExecutorService pool = Executors.newFixedThreadPool(5);
//2、为线程池分配任务
ThreadPoolTest threadPoolTest = new ThreadPoolTest();
for (int i = 0; i < 10; i++) {
pool.submit(threadPoolTest);
}
//3、关闭线程池
pool.shutdown();
}
static class ThreadPoolTest implements Runnable{
@Override
public void run() {
try {
String dateString = fastDateFormat.format(new Date());
Date parseDate = fastDateFormat.parse(dateString);
String dateString2 = fastDateFormat.format(parseDate);
System.out.println(Thread.currentThread().getName()+" 线程是否安全: "+dateString.equals(dateString2));
} catch (Exception e) {
e.printStackTrace();
System.out.println(Thread.currentThread().getName()+" 格式化失败 ");
}
}
}
}
使用FastDateFormat能保证线程安全,且效率也是挺高的。**适合高并发场景使用**。
###### FastDateFormat源码分析
Apache Commons Lang 3.5
//FastDateFormat
@Override
public String format(final Date date) {
return printer.format(date);
}
@Override
public String format(final Date date) {
final Calendar c = Calendar.getInstance(timeZone, locale);
c.setTime(date);
return applyRulesToString(c);
}
源码中 Calender 是在 format 方法里创建的,肯定不会出现 setTime 的线程安全问题。这样线程安全疑惑解决了。那还有性能问题要考虑?
我们来看下FastDateFormat是怎么获取的
FastDateFormat.getInstance();
FastDateFormat.getInstance(CHINESE_DATE_TIME_PATTERN);
看下对应的源码
/**
* 获得 FastDateFormat实例,使用默认格式和地区
*
* @return FastDateFormat
*/
public static FastDateFormat getInstance() {
return CACHE.getInstance();
}
/**
* 获得 FastDateFormat 实例,使用默认地区
* 支持缓存
*
* @param pattern 使用{@link java.text.SimpleDateFormat} 相同的日期格式
* @return FastDateFormat
* @throws IllegalArgumentException 日期格式问题
*/
public static FastDateFormat getInstance(final String pattern) {
return CACHE.getInstance(pattern, null, null);
}
这里有用到一个CACHE,看来用了缓存,往下看
private static final FormatCache CACHE = new FormatCache(){
@Override
protected FastDateFormat createInstance(final String pattern, final TimeZone timeZone, final Locale locale) {
return new FastDateFormat(pattern, timeZone, locale);
}
};
//
abstract class FormatCache {
…
private final ConcurrentMap<Tuple, F> cInstanceCache = new ConcurrentHashMap<>(7);
private static final ConcurrentMap<Tuple, String> C_DATE_TIME_INSTANCE_CACHE = new ConcurrentHashMap<>(7);
...
}
![image-20210728914309](https://img-blog.csdnimg.cn/img_convert/726cfac67f45b965a81cf383137696ab.png)
在getInstance 方法中加了ConcurrentMap 做缓存,提高了性能。且我们知道ConcurrentMap 也是线程安全的。
###### 实践
/**
* 年月格式 {@link FastDateFormat}:yyyy-MM
*/
public static final FastDateFormat NORM_MONTH_FORMAT = FastDateFormat.getInstance(NORM_MONTH_PATTERN);
![image-2021072895013629](https://img-blog.csdnimg.cn/img_convert/5e9d8fabbff309ed788541717b2a4706.png)
//FastDateFormat
public static FastDateFormat getInstance(final String pattern) {
return CACHE.getInstance(pattern, null, null);
}
![image-20210728205104833](https://img-blog.csdnimg.cn/img_convert/0dcc8e2f0db4ff15a3c3349710a9a1e8.png)
![image-2021072895259113](https://img-blog.csdnimg.cn/img_convert/36412da4194421f93245070987d70b2f.png)
如图可证,是使用了ConcurrentMap 做缓存。且key值是格式,时区和locale(语境)三者都相同为相同的key。
### 问题
1、tostring()输出时,总以系统的默认时区格式输出,不友好。
2、时区不能转换
3、日期和时间的计算不简便,例如计算加减,比较两个日期差几天等。
4、格式化日期和时间的SimpleDateFormat对象是线程不安全的
5、Date对象本身也是线程不安全的
public class Date
implements java.io.Serializable, Cloneable, Comparable
{
…
}
## 二:Calendar
### 支持版本及以上
JDK1.1
### 介绍
#### Calendar类说明
Calendar类提供了获取或设置各种日历字段的各种方法,比Date类多了一个可以计算日期和时间的功能。
#### Calendar常用的用法
// 获取当前时间:
Calendar c = Calendar.getInstance();
int y = c.get(Calendar.YEAR);
int m = 1 + c.get(Calendar.MONTH);
int d = c.get(Calendar.DAY_OF_MONTH);
int w = c.get(Calendar.DAY_OF_WEEK);
int hh = c.get(Calendar.HOUR_OF_DAY);
int mm = c.get(Calendar.MINUTE);
int ss = c.get(Calendar.SECOND);
int ms = c.get(Calendar.MILLISECOND);
System.out.println("返回的星期:"+w);
System.out.println(y + "-" + m + "-" + d + " " + " " + hh + ":" + mm + ":" + ss + "." + ms);
![image-202107141981024](https://img-blog.csdnimg.cn/img_convert/9bb2f5d9bfdb5429740864709bf9744d.png)
如上图所示,月份计算时,要+1;返回的星期是从周日开始计算,周日为1,1~7表示星期;
#### Calendar的跨年问题和解决方案
##### 问题
背景:在使用Calendar 的api getWeekYear()读取年份,在跨年那周的时候,程序获取的年份可能不是我们想要的,例如在2019年30号时,要返回2019,结果是返回2020,是不是有毒
// 获取当前时间:
Calendar c = Calendar.getInstance();
c.clear();
String str = “2019-12-30”;
try {
c.setTime(new SimpleDateFormat(“yyyy-MM-dd”).parse(str));
int y = c.getWeekYear();
System.out.println(y);
} catch (ParseException e) {
e.printStackTrace();
}
![image-202107148203567](https://img-blog.csdnimg.cn/img_convert/9ffa5367a01e018f765146e16de13303.png)
##### 分析原因
老规矩,从源码入手
Calendar类
-------------------------
//@since 1.7
public int getWeekYear() {
throw new UnsupportedOperationException();
}
这个源码有点奇怪,getWeekYear()方法是java 7引入的。它的实现怎么是抛出异常,但是执行时,又有结果返回。
断点跟进,通过**Calendar.getInstance()**获取的Calendar实例是**GregorianCalendar**
![image-202107148065](https://img-blog.csdnimg.cn/img_convert/79a9f056837047953dc23d36048026cc.png)
GregorianCalendar
--------------------------------------
public int getWeekYear() {
int year = get(YEAR); // implicitly calls complete()
if (internalGetEra() == BCE) {
year = 1 - year;
}
// Fast path for the Gregorian calendar years that are never
// affected by the Julian-Gregorian transition
if (year > gregorianCutoverYear + 1) {
int weekOfYear = internalGet(WEEK_OF_YEAR);
if (internalGet(MONTH) == JANUARY) {
if (weekOfYear >= 52) {
--year;
}
} else {
if (weekOfYear == 1) {
++year;
}
}
return year;
}
...
}
方法内获取的年份刚开始是正常的
![image-20210714707548](https://img-blog.csdnimg.cn/img_convert/48203e94cf0f6094b6d1b9c92cef736b.png)
![image-20210714847423](https://img-blog.csdnimg.cn/img_convert/b606e887414738556b7f6c58dda43981.png)
**在JDK中会把前一年末尾的几天判定为下一年的第一周,因此上面程序的结果是1**
##### 解决方案
使用Calendar类 get(Calendar.YEAR)获取年份
### 问题
1、读取月份时,要+1
2、返回的星期是从周日开始计算,周日为1,1~7表示星期
3、Calendar的跨年问题,获取年份要用c.get(Calendar.YEAR),不要用c.getWeekYear();
4、获取指定时间是一年中的第几周时,调用cl.get(Calendar.WEEK\_OF\_YEAR),要注意跨年问题,跨年的那一周,获取的值为1。离跨年最近的那周为52。
## 三:LocalDateTime
### 支持版本及以上
jdk8
### 介绍
#### LocalDateTime类说明
表示当前日期时间,相当于:yyyy-MM-ddTHH:mm:ss
#### LocalDateTime常用的用法
##### 获取当前日期和时间
LocalDate d = LocalDate.now(); // 当前日期
LocalTime t = LocalTime.now(); // 当前时间
LocalDateTime dt = LocalDateTime.now(); // 当前日期和时间
System.out.println(d); // 严格按照ISO 8601格式打印
System.out.println(t); // 严格按照ISO 8601格式打印
System.out.println(dt); // 严格按照ISO 8601格式打印
![image-20210714857780](https://img-blog.csdnimg.cn/img_convert/88a2ca1f2ab378e9fb78c35b6c19578c.png)
由运行结果可行,本地日期时间通过now()获取到的总是以当前默认时区返回的
##### 获取指定日期和时间
LocalDate d2 = LocalDate.of(2021, 07, 14); // 2021-07-14, 注意07=07月
LocalTime t2 = LocalTime.of(13, 14, 20); // 13:14:20
LocalDateTime dt2 = LocalDateTime.of(2021, 07, 14, 13, 14, 20);
LocalDateTime dt3 = LocalDateTime.of(d2, t2);
System.out.println("指定日期时间:"+dt2);
System.out.println("指定日期时间:"+dt3);
![image-20210714803165](https://img-blog.csdnimg.cn/img_convert/e4815e85482b966bf64df64ee74af08d.png)
##### 日期时间的加减法及修改
LocalDateTime currentTime = LocalDateTime.now(); // 当前日期和时间
System.out.println("------------------时间的加减法及修改-----------------------");
//3.LocalDateTime的加减法包含了LocalDate和LocalTime的所有加减,上面说过,这里就只做简单介绍
System.out.println("3.当前时间:" + currentTime);
System.out.println("3.当前时间加5年:" + currentTime.plusYears(5));
System.out.println("3.当前时间加2个月:" + currentTime.plusMonths(2));
System.out.println("3.当前时间减2天:" + currentTime.minusDays(2));
System.out.println("3.当前时间减5个小时:" + currentTime.minusHours(5));
System.out.println("3.当前时间加5分钟:" + currentTime.plusMinutes(5));
System.out.println("3.当前时间加20秒:" + currentTime.plusSeconds(20));
//还可以灵活运用比如:向后加一年,向前减一天,向后加2个小时,向前减5分钟,可以进行连写
System.out.println("3.同时修改(向后加一年,向前减一天,向后加2个小时,向前减5分钟):" + currentTime.plusYears(1).minusDays(1).plusHours(2).minusMinutes(5));
System.out.println("3.修改年为2025年:" + currentTime.withYear(2025));
System.out.println("3.修改月为12月:" + currentTime.withMonth(12));
System.out.println("3.修改日为27日:" + currentTime.withDayOfMonth(27));
System.out.println("3.修改小时为12:" + currentTime.withHour(12));
System.out.println("3.修改分钟为12:" + currentTime.withMinute(12));
System.out.println("3.修改秒为12:" + currentTime.withSecond(12));
![image-20210714941902](https://img-blog.csdnimg.cn/img_convert/391472f879266d60a5d313b8a0796da9.png)
### LocalDateTime和Date相互转化
##### Date转LocalDateTime
System.out.println("------------------方法一:分步写-----------------------");
//实例化一个时间对象
Date date = new Date();
//返回表示时间轴上同一点的瞬间作为日期对象
Instant instant = date.toInstant();
//获取系统默认时区
ZoneId zoneId = ZoneId.systemDefault();
//根据时区获取带时区的日期和时间
ZonedDateTime zonedDateTime = instant.atZone(zoneId);
//转化为LocalDateTime
LocalDateTime localDateTime = zonedDateTime.toLocalDateTime();
System.out.println("方法一:原Date = " + date);
System.out.println("方法一:转化后的LocalDateTime = " + localDateTime);
System.out.println("------------------方法二:一步到位(推荐使用)-----------------------");
//实例化一个时间对象
Date todayDate = new Date();
//Instant.ofEpochMilli(long l)使用1970-01-01T00:00:00Z的纪元中的毫秒来获取Instant的实例
LocalDateTime ldt = Instant.ofEpochMilli(todayDate.getTime()).atZone(ZoneId.systemDefault()).toLocalDateTime();
System.out.println("方法二:原Date = " + todayDate);
System.out.println("方法二:转化后的LocalDateTime = " + ldt);
![image-20210714210839339](https://img-blog.csdnimg.cn/img_convert/fef7dbb7e4ae8717d415490471be8959.png)
##### LocalDateTime转Date
System.out.println("------------------方法一:分步写-----------------------");
//获取LocalDateTime对象,当前时间
LocalDateTime localDateTime = LocalDateTime.now();
//获取系统默认时区
ZoneId zoneId = ZoneId.systemDefault();
//根据时区获取带时区的日期和时间
ZonedDateTime zonedDateTime = localDateTime.atZone(zoneId);
//返回表示时间轴上同一点的瞬间作为日期对象
Instant instant = zonedDateTime.toInstant();
//转化为Date
Date date = Date.from(instant);
System.out.println("方法一:原LocalDateTime = " + localDateTime);
System.out.println("方法一:转化后的Date = " + date);
System.out.println("------------------方法二:一步到位(推荐使用)-----------------------");
//实例化一个LocalDateTime对象
LocalDateTime now = LocalDateTime.now();
//转化为date
Date dateResult = Date.from(now.atZone(ZoneId.systemDefault()).toInstant());
System.out.println("方法二:原LocalDateTime = " + now);
System.out.println("方法二:转化后的Date = " + dateResult);
![image-20210714211035080](https://img-blog.csdnimg.cn/img_convert/878a923c61fa76d95853b0c45e3f1d0a.png)
### 线程安全
网上大家都在说JAVA 8提供的LocalDateTime是线程安全的,但是它是如何实现的呢
今天让我们来挖一挖
public final class LocalDateTime
implements Temporal, TemporalAdjuster, ChronoLocalDateTime, Serializable {
…
}
由上面的源码可知,LocalDateTime是不可变类。我们都知道一个Java并发编程规则:不可变对象永远是线程安全的。
对比下Date的源码 ,Date是可变类,所以是线程不安全的。
public class Date
implements java.io.Serializable, Cloneable, Comparable
{
…
}
## 四:ZonedDateTime
### 支持版本及以上
jdk8
### 介绍
#### ZonedDateTime类说明
表示一个带时区的日期和时间,ZonedDateTime可以理解为LocalDateTime+ZoneId
从源码可以看出来,ZonedDateTime类中定义了LocalDateTime和ZoneId两个变量。
且ZonedDateTime类也是不可变类且是线程安全的。
public final class ZonedDateTime
implements Temporal, ChronoZonedDateTime, Serializable {
/\*\*
* Serialization version.
*/
private static final long serialVersionUID = -6260982410461394882L;
/\*\*
* The local date-time.
*/
private final LocalDateTime dateTime;
/**
* The time-zone.
*/
private final ZoneId zone;
...
}
#### ZonedDateTime常用的用法
##### 获取当前时间+带时区+时区转换
// 默认时区获取当前时间
ZonedDateTime zonedDateTime = ZonedDateTime.now();
// 用指定时区获取当前时间,Asia/Shanghai为上海时区
ZonedDateTime zonedDateTime1 = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
//withZoneSameInstant为转换时区,参数为ZoneId
ZonedDateTime zonedDateTime2 = zonedDateTime.withZoneSameInstant(ZoneId.of("America/New\_York"));
System.out.println(zonedDateTime);
System.out.println(zonedDateTime1);
System.out.println(zonedDateTime2);
![image-202107205246938](https://img-blog.csdnimg.cn/img_convert/6111942ba504d9a2879f1868d189c31e.png)
##### LocalDateTime+ZoneId变ZonedDateTime
LocalDateTime localDateTime = LocalDateTime.now();
ZonedDateTime zonedDateTime1 = localDateTime.atZone(ZoneId.systemDefault());
ZonedDateTime zonedDateTime2 = localDateTime.atZone(ZoneId.of("America/New\_York"));
System.out.println(zonedDateTime1);
System.out.println(zonedDateTime2);
![image-2021072094003](https://img-blog.csdnimg.cn/img_convert/077df40143b68751ddb43cefcdf81299.png)
上面的例子说明了,LocalDateTime是可以转成ZonedDateTime的。
## 五:DateTimeFormatter
### 支持版本及以上
jdk8
### 介绍
#### DateTimeFormatter类说明
DateTimeFormatter的作用是进行格式化显示,且DateTimeFormatter是不可变类且是线程安全的。
public final class DateTimeFormatter {
…
}
说到时间的格式化显示,就要说老朋友SimpleDateFormat了,之前格式化Date就要用上。但是我们知道SimpleDateFormat是线程不安全的,还不清楚的,[请看这里–>](#simpleDateFormat)
#### DateTimeFormatter常用的用法
ZonedDateTime zonedDateTime = ZonedDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm ZZZZ");
System.out.println(formatter.format(zonedDateTime));
DateTimeFormatter usFormatter = DateTimeFormatter.ofPattern("E, MMMM/dd/yyyy HH:mm", Locale.US);
System.out.println(usFormatter.format(zonedDateTime));
DateTimeFormatter chinaFormatter = DateTimeFormatter.ofPattern("yyyy MMM dd EE HH:mm", Locale.CHINA);
System.out.println(chinaFormatter.format(zonedDateTime));
![image-202107209416958](https://img-blog.csdnimg.cn/img_convert/cf99323c3f7fe763baaaed20b12310b3.png)
### DateTimeFormatter的坑
##### 1、在正常配置按照标准格式的字符串日期,是能够正常转换的。如果月,日,时,分,秒在不足两位的情况需要补0,否则的话会转换失败,抛出异常。
DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
LocalDateTime dt1 = LocalDateTime.parse("2021-7-20 23:46:43.946", DATE_TIME_FORMATTER);
System.out.println(dt1);
会报错:
![image-202107208183](https://img-blog.csdnimg.cn/img_convert/42f5f1675522f0ec261e2812fb55f823.png)
java.time.format.DateTimeParseException: Text ‘2021-7-20 23:46:43.946’ could not be parsed at index 5
分析原因:是格式字符串与实际的时间不匹配
“yyyy-MM-dd HH:mm:ss.SSS”
“2021-7-20 23:46:43.946”
中间的月份格式是MM,实际时间是7
解决方案:保持格式字符串与实际的时间匹配
DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
LocalDateTime dt1 = LocalDateTime.parse("2021-07-20 23:46:43.946", DATE_TIME_FORMATTER);
System.out.println(dt1);
![image-20210720504067](https://img-blog.csdnimg.cn/img_convert/5be5ffd12590c1736bdee290b1d16a94.png)
##### 2、YYYY和DD谨慎使用
LocalDate date = LocalDate.of(2020,12,31);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("YYYYMM");
// 结果是 202112
System.out.println( formatter.format(date));
![image-202107208183](https://img-blog.csdnimg.cn/img_convert/6cad9fa2763a0c835ec0aeaf56d03a8c.png)
Java’s DateTimeFormatter pattern “YYYY” gives you the week-based-year, (by default, ISO-8601 standard) the year of the Thursday of that week.
YYYY是取的当前周所在的年份,week-based year 是 ISO 8601 规定的。2020年12月31号,周算年份,就是2021年
![image-2021072059555](https://img-blog.csdnimg.cn/img_convert/0310d6efe8532eaed957df94fece7f90.png)
private static void tryit(int Y, int M, int D, String pat) {
DateTimeFormatter fmt = DateTimeFormatter.ofPattern(pat);
LocalDate dat = LocalDate.of(Y,M,D);
String str = fmt.format(dat);
System.out.printf(“Y=%04d M=%02d D=%02d " +
“formatted with " +
“”%s” -> %s\n”,Y,M,D,pat,str);
}
public static void main(String[] args){
tryit(2020,01,20,“MM/DD/YYYY”);
tryit(2020,01,21,“DD/MM/YYYY”);
tryit(2020,01,22,“YYYY-MM-DD”);
tryit(2020,03,17,“MM/DD/YYYY”);
tryit(2020,03,18,“DD/MM/YYYY”);
tryit(2020,03,19,“YYYY-MM-DD”);
}
Y=2020 M=01 D=20 formatted with “MM/DD/YYYY” -> 01/20/2020
Y=2020 M=01 D=21 formatted with “DD/MM/YYYY” -> 21/01/2020
Y=2020 M=01 D=22 formatted with “YYYY-MM-DD” -> 2020-01-22
Y=2020 M=03 D=17 formatted with “MM/DD/YYYY” -> 03/77/2020
Y=2020 M=03 D=18 formatted with “DD/MM/YYYY” -> 78/03/2020
Y=2020 M=03 D=19 formatted with “YYYY-MM-DD” -> 2020-03-79
最后三个日期是有问题的,因为大写的**DD**代表的是处于这一年中那一天,不是处于这个月的那一天,但是**dd**就没有问题。
例子参考于:https://www.cnblogs.com/tonyY/p/12153335.html
所以建议使用yyyy和dd。
## 六:Instant
### 支持版本及以上
jdk8
### 介绍
#### Instant类说明
public final class Instant
implements Temporal, TemporalAdjuster, Comparable, Serializable {
…
}
Instant也是不可变类且是线程安全的。其实**Java.time** 这个包是线程安全的。
**Instant**是java 8新增的特性,里面有两个核心的字段
...
private final long seconds;
private final int nanos;
...
一个是单位为秒的时间戳,另一个是单位为纳秒的时间戳。
是不是跟\*\*System.currentTimeMillis()\*\*返回的long时间戳很像,System.currentTimeMillis()返回的是毫秒级,Instant多了更精确的纳秒级时间戳。
#### Instant常用的用法
Instant now = Instant.now();
System.out.println("now:"+now);
System.out.println(now.getEpochSecond()); // 秒
System.out.println(now.toEpochMilli()); // 毫秒
![image-20210720905353](https://img-blog.csdnimg.cn/img_convert/f9530dae1dfe480dec644bf7c292d89f.png)
##### Instant是没有时区的,但是Instant加上时区后,可以转化为ZonedDateTime
Instant ins = Instant.now();
ZonedDateTime zdt = ins.atZone(ZoneId.systemDefault());
System.out.println(zdt);
![image-202107205211996](https://img-blog.csdnimg.cn/img_convert/3fab27e4ccded2c5c85c1ad3d7b7fda3.png)
##### long型时间戳转Instant
要注意long型时间戳的时间单位选择Instant对应的方法转化
//1626796436 为秒级时间戳
Instant ins = Instant.ofEpochSecond(1626796436);
ZonedDateTime zdt = ins.atZone(ZoneId.systemDefault());
System.out.println(“秒级时间戳转化:”+zdt);
//1626796436111l 为秒级时间戳
Instant ins1 = Instant.ofEpochMilli(1626796436111l);
ZonedDateTime zdt1 = ins1.atZone(ZoneId.systemDefault());
System.out.println(“毫秒级时间戳转化:”+zdt1);
#### Instant的坑
Instant.now()获取的时间与北京时间相差8个时区,这是一个细节,要避坑。
看源码,用的是UTC时间。
public static Instant now() {
return Clock.systemUTC().instant();
}
解决方案:
Instant now = Instant.now().plusMillis(TimeUnit.HOURS.toMillis(8));
System.out.println(“now:”+now);
![image-202107234326190](https://i-blog.csdnimg.cn/blog_migrate/2db60d75e6cf2471d4fef2ef9c387495.png)
## 推荐相关文章
### hutool日期时间系列文章
[1DateUtil(时间工具类)-当前时间和当前时间戳](https://bbs.csdn.net/topics/618545628)
[2DateUtil(时间工具类)-常用的时间类型Date,DateTime,Calendar和TemporalAccessor(LocalDateTime)转换](https://bbs.csdn.net/topics/618545628)
[3DateUtil(时间工具类)-获取日期的各种内容](https://bbs.csdn.net/topics/618545628)
[4DateUtil(时间工具类)-格式化时间](https://bbs.csdn.net/topics/618545628)
[5DateUtil(时间工具类)-解析被格式化的时间](https://bbs.csdn.net/topics/618545628)
[6DateUtil(时间工具类)-时间偏移量获取](https://bbs.csdn.net/topics/618545628)
![img](https://img-blog.csdnimg.cn/img_convert/93dc2f678be112ed5d614ceebabd4642.png)
![img](https://img-blog.csdnimg.cn/img_convert/f0d86a0e639ee43174ef1b18b9a0e9e7.png)
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618545628)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
tln("now:"+now);
推荐相关文章
hutool日期时间系列文章
2DateUtil(时间工具类)-常用的时间类型Date,DateTime,Calendar和TemporalAccessor(LocalDateTime)转换
[外链图片转存中…(img-OqbRhJiX-1714463347025)]
[外链图片转存中…(img-FVppf1S8-1714463347025)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!