在 JDK 8 之前,Java 语言为我们提供了两个类用于操作时间,它们分别是:java.util.Date 和 java.util.Calendar,但在 JDK 8 的时候为了解决旧时间操作类的一些缺陷,提供了几个新的类,用于操作时间和日期,它们分别是:LocalTime、LocalDateTime、Instant,都位于 java.time 包下。
格林威治时间
格林威治(又译格林尼治)是英国伦敦南郊原格林威治天文台的所在地,格林威治是世界计算时间和地球经度的起点,国际经度会议 1884 年在美国华盛顿召开,会上通过协议,以经过格林威治天文台的经线为零度经线(即本初子午线),作为地球经度的起点,并以格林威治为“世界时区”的起点。
格林威治时间和北京时间的关系
格林威治时间被定义为世界时间,就是 0 时区,北京是东八区。也就是说格林威治时间的 1 日 0 点,对应到北京的时间就是 1 日 8 点。
时间戳
时间戳是指格林威治时间 1970-01-01 00:00:00(北京时间 1970-01-01 08:00:00)起至现在的总秒数。
// Date
Date date = new Date();
// Calendar
Date date = Calendar.getInstance().calendar.getTime();
输出结果:Sat Mar 28 08:36:01 CST 2020
long time = date.getTime();
long timeInMillis = calendar.getTimeInMillis();
long currentTimeMillis = System.currentTimeMillis();
输出结果:1585355761358
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd hh-mm-ss");
String format = df.format(date);
System.out.println(format);
输出结果:2020-03-28 08-36-01
SimpleDateFormat 构造参数的含义,请参考以下表格信息:
字符 | 含义 | 示例 |
---|---|---|
yyyyy | 年 | 1996 |
MM | 月 | 07 |
dd | 月中的天数 | 02 |
D | 年中的天数 | 121 |
E | 星期几 | 星期四 |
HH | 小时数(0-23) | 23 |
hh | 小时数(1-12) | 11 |
mm | 分钟数 | 02 |
ss | 秒数 | 03 |
Z | 时区 | +0800 |
使用示例
注意事项
在多线程下 SimpleDateFormat 是非线程安全的,因此在使用 SimpleDateFormat 时要注意这个问题。在多线程下,如果使用不当,可能会造成结果不对或内存泄漏等问题。
// String -> Date
String str = "2019-10-10 10:10:10";
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
Date parse = df.parse(str);
// String -> Date
String s = "1556788591462";
long lg = Long.parseLong(s);
Timestamp t = new Timestamp(lg);
long time = t.getTime();
Date date = new Date(time);
注意事项:当使用 SimpleDateFormat.parse() 方法进行时间转换的时候,SimpleDateFormat 的构造函数必须和待转换字符串格式一致。
Calendar instance = Calendar.getInstance();
instance.add(Calendar.DAY_OF_MONTH,1);
Date time = instance.getTime();
System.out.println(time);
输出结果:Fri Mar 27 08:55:50 CST 2020
JDK 8 对时间操作新增了三个类:LocalDate、LocalTime、LocalDateTime。
值得一提的是 JDK 8 中新增的这三个时间相关的类,都是线程安全的,这极大地降低了多线程下代码开发的风险。
// 获取日期
LocalDate localDate = LocalDate.now();
System.out.println(localDate); // output:2019-08-16
// 获取时间
LocalTime localTime = LocalTime.now();
System.out.println(localTime); // output:21:09:13.708
// 获取日期和时间
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDateTime); // output:2019-08-16T21:09:13.708
// 获取当前时间戳(精确到毫秒)
long milli = Instant.now().toEpochMilli();
System.out.println(milli); // output:1565932435792
// 获取当前时间戳(精确到秒)
long second = Instant.now().getEpochSecond();
System.out.println(second); // output:1565932435
String str = "yyyy-MM-dd HH:mm:ss";
String format = DateTimeFormatter.ofPattern(str).format(LocalDateTime.now());
System.out.println(format); // 2020-03-28 09:01:47
String format1 = LocalDateTime.now().format(DateTimeFormatter.ofPattern(str));
System.out.println(format1); // 2020-03-28 09:01:47
String timeStr = "2019-10-10 06:06:06";
LocalDateTime dateTime = LocalDateTime.parse(timeStr,DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
System.out.println(dateTime);
LocalDateTime today = LocalDateTime.now();
LocalDateTime yesterday = today.plusDays(-1);
System.out.println(yesterday);
答:获取当前时间常见的方式有以下三种:
答:以下为获取昨天此刻时间的两种方式:
// 获取昨天此刻的时间(JDK 8 以前)
Calendar c = Calendar.getInstance();
c.add(Calendar.DATE,-1);
System.out.println(c.getTime());
// 获取昨天此刻的时间(JDK 8)
LocalDateTime todayTime = LocalDateTime.now();
System.out.println(todayTime.plusDays(-1));
答:以下为获取本月最后一天的两种方式:
// 获取本月的最后一天(JDK 8 以前)
Calendar ca = Calendar.getInstance();
ca.set(Calendar.DAY_OF_MONTH, ca.getActualMaximum(Calendar.DAY_OF_MONTH));
System.out.println(ca.getTime());
// 获取本月的最后一天(JDK 8)
LocalDate today = LocalDate.now();
System.out.println(today.with(TemporalAdjusters.lastDayOfMonth()));
答:以下为获取当前时间戳的几种方式:
其中,第四种和第五种方式是 JDK 8 才新加的。
答:JDK 8 中可以使用 静态方法 Duration.between() 来优雅地计算两个时间的相隔时间,代码如下:
LocalDateTime dt1 = LocalDateTime.now();
LocalDateTime dt2 = dt1.plusSeconds(60);
Duration duration = Duration.between(dt1, dt2);
System.out.println(duration.getSeconds()); // output:60
答:JDK 8 中可以使用 静态方法 Period.between() 来优雅地计算两个日期的相隔日期,代码如下:
LocalDate d1 = LocalDate.now();
LocalDate d2 = d1.plusDays(2);
Period period = Period.between(d1, d2);
System.out.println(period.getDays()); //output:2
答:SimpleDateFormat 是非线程安全的。因为查看 SimpleDateFormat 的源码可以得知,所有的格式化和解析,都需要通过一个中间对象进行转换,这个中间对象就是 Calendar,这样的话就造成非线程安全。试想一下当我们有多个线程操作同一个 Calendar 的时候后来的线程会覆盖先来线程的数据,那最后其实返回的是后来线程的数据,因此 SimpleDateFormat 就成为了非线程的了。
答:保证 SimpleDateFormat 线程安全的方式如下:
答:JDK 8 中的优点具体有以下几个优点,如下:
答:时间比较有以下三种方式:
答:JDK 8 之前使用 Calendar.add()
方法获取,代码如下:
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DATE, 1);
System.out.println(calendar.getTime());
JDK 8 有两种获取明天时间的方法。
方法一,使用 LocalDateTime.plusDays()
方法获取,代码如下:
LocalDateTime today = LocalDateTime.now();
LocalDateTime tomorrow = today.plusDays(1);
System.out.println(tomorrow);
方法二,使用 LocalDateTime.minusDays()
方法获取,代码如下:
LocalDateTime today = LocalDateTime.now();
LocalDateTime tomorrow = today.minusDays(-1);
System.out.println(tomorrow);
minusDays()
方法为当前时间减去 n 天,传负值就相当于当前时间加 n 天。