日期:2016-2-6 表示某一天他不是连续变换的,而是离散的
时间:20:21:59
时刻:2016-2-6 20:21:59 带日期的时间,他可以唯一的确定某一个时刻(Instant)
在不同的时区的同一时间,他们的本地时刻是不同的
时区的表示方式
GMT+08:00 表示东八区
UTC+08:00 表示东八区
CST 中国时间(缩写)
Asia/Shanghai 上海时间(国家/城市)
GMT与UTC基本一致,UTC使用原子钟计算更加精确
Locale概念
Locale用来针对当地用户习惯格式化日期、时间、数字、货币等:
zh_CN:2016-11-30 中国的locale
en_US:11/30/2016 美国的locale
计算机用locale在日期、时间、货币和字符之间进行转换:
理解数据的表示方式
数据的存储方式指的是指数据在内存中的保存方式
用日期和时间加上字符串展示时刻其实是时刻的展示方式:
那么计算机中时间的存储方式是什么?
在计算机中使用Epoch Time来存储时间。
Epoch Time:从1970年1月1日零点(格林威治时区/GMT+00:00)到现在的秒数,例如:
北京2016-11-20 8:15:01=1479600901
当我们使用Epoch表示时间的时候实际上我们存储的是一个整数
当Epoch=1479600901在全球各地他的本地时间都能确定下来
在计算机中使用long类型的整形表示毫秒数,被称为Epoch Time或者Timestamp(时间戳)
long t=1479600901123L
复制代码
java时间api
java.util
主要的类:Date、Calendar
java.util.Date表示日期和时间,内部使用long表示epoch毫秒数
Date和long的转换
SimpleDateFormat:用于Date和String的解析和格式化
获取当前时间:
new Date().toString()获取GMT时间
long getTme() 获取时间戳
实例代码:1
import java.util.Date;
public class Main {
public static void main(String[] args) throws Exception {
System.out.println(System.currentTimeMillis());
Date now = new Date();
System.out.println(now);
long t = now.getTime();
System.out.println(t);
System.out.println(new Date(t));
复制代码
输出
1554885481247
Wed Apr 10 16:38:01 CST 2019
1554885481249
Wed Apr 10 16:38:01 CST 2019
复制代码
实例代码:2
import java.util.Date;
public class Date2String {
public static void main(String[] args) throws Exception {
Date now = new Date();
System.out.println(now.toString());
System.out.println(now.toGMTString());
System.out.println(now.toLocaleString());
复制代码
输出
Wed Apr 10 16:33:33 CST 2019
10 Apr 2019 08:33:33 GMT
2019-4-10 16:33:33
复制代码
把java.util.Date转换为string
toString()
toGMTString()
toLocaleString()
SimpleDateFormat上面3个是指定的格式,这个是自定义格式
SimpleDateFormat类的作用:
参考文档
将new Date()解析成想要格式的时间字符串
将字符串解析成Date类型的时间对象
实例代码:1
import java.text.SimpleDateFormat;
import java.util.Date;
public class Format {
public static void main(String[] args) throws Exception {
Date now = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf.format(now));
复制代码
输出
2019-04-10 16:39:12
复制代码
实例代码:2
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class Parse {
public static void main(String[] args) throws Exception {
String s1 = "2016-11-20 12:15:59";
Date date1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(s1);
System.out.println(date1);
String s2 = "Nov/20/2016 12:15:59";
Date date2 = new SimpleDateFormat("MMM/dd/yyyy HH:mm:ss", Locale.US).parse(s2);
System.out.println(date2);
String iso = "2016-11-20T12:15:59";
Date date3 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").parse(iso);
System.out.println(date3);
复制代码
输出
Sun Nov 20 12:15:59 CST 2016
Sun Nov 20 12:15:59 CST 2016
Sun Nov 20 12:15:59 CST 2016
复制代码
Date的问题:
java.util.Date不能转换时区
日期和时间的加减比较困难
不能计算两个日期相差多少天
不能计算某个月第一个星期一是几号
Calendar
Calendar和Date、long可以互相转换
Calendar可以用set/get设置和获取指定字段
Calendar可以实现:
设置特定的日期和时间
设置时区并获得转换后的时间
加减日期和时间
TimeZone表示时区,getAvailableIDs()可以枚举所有有效的时区ID
Java Calendar 日历类的时间操作 Timestamp Date Calendar 相互转换
示例代码:1
import java.util.Calendar;
public class Main {
public static void main(String[] args) throws Exception {
Calendar c = Calendar.getInstance();
System.out.println(c.getTime());
System.out.println(c.getTimeInMillis());
System.out.println(" Year = " + c.get(Calendar.YEAR));
System.out.println(" Month = " + c.get(Calendar.MONTH));
System.out.println(" Day = " + c.get(Calendar.DAY_OF_MONTH));
System.out.println(" Weekday = " + c.get(Calendar.DAY_OF_WEEK));
System.out.println(" Hour = " + c.get(Calendar.HOUR_OF_DAY));
System.out.println(" Minute = " + c.get(Calendar.MINUTE));
System.out.println(" Second = " + c.get(Calendar.SECOND));
System.out.println(" Millis = " + c.get(Calendar.MILLISECOND));
System.out.println("TimeZone = " + c.getTimeZone());
复制代码
输出
Wed Apr 10 22:14:57 CST 2019
1554905697700
Year = 2019
Month = 3
Day = 10
Weekday = 4
Hour = 22
Minute = 14
Second = 57
Millis = 700
TimeZone = sun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=19,lastRule=null]
复制代码
示例代码:2时间计算
import java.util.Calendar;
public class Calculate {
public static void main(String[] args) throws Exception {
Calendar c = Calendar.getInstance();
System.out.println(c.getTime());
c.add(Calendar.DAY_OF_MONTH, 5);
c.add(Calendar.HOUR_OF_DAY, -2);
System.out.println(c.getTime());
复制代码
输出
Wed Apr 10 22:30:22 CST 2019
Mon Apr 15 20:30:22 CST 2019
复制代码
实例代码:3设置时间
import java.util.Calendar;
public class SetTime {
public static void main(String[] args) throws Exception {
Calendar c = Calendar.getInstance();
System.out.println(c.getTime());
c.clear();
c.set(Calendar.YEAR, 1999);
c.set(Calendar.MONTH, 10);
c.set(Calendar.DAY_OF_MONTH, 30);
c.set(Calendar.HOUR_OF_DAY, 21);
System.out.println(c.getTime());
复制代码
输出
Wed Apr 10 22:31:41 CST 2019
Tue Nov 30 21:00:00 CST 1999
复制代码
示例代码:4时区
import java.util.Calendar;
import java.util.TimeZone;
public class Zone {
public static void main(String[] args) throws Exception {
Calendar c = Calendar.getInstance();
System.out.println(c.getTime());
c.setTimeZone(TimeZone.getTimeZone("America/New_York"));
int y = c.get(Calendar.YEAR);
int m = c.get(Calendar.MONTH) + 1;
int d = c.get(Calendar.DAY_OF_MONTH);
int hh = c.get(Calendar.HOUR_OF_DAY);
int mm = c.get(Calendar.MINUTE);
int ss = c.get(Calendar.SECOND);
System.out.println(y + "-" + m + "-" + d + " " + hh + ":" + mm + ":" + ss);
复制代码
输出
Wed Apr 10 22:33:00 CST 2019
2019-4-10 10:33:0
复制代码
总结
date对象主要用于获取当前时间,或者给定一个时间按照不同格式进行转换输出,但是不能进行日期时间的计算。
Calendar对象处理可以获取当前时间,还可以进行时间运算等复杂的时间格式。
java.time(JDK>=1.8)
主要类:LocalDate、LocalTime、ZonedDateTime、Instant
严格区分日期和时间
不变类 (类似String)
修复了Month(1-12)和Week(1-7)的常量值
增加了时间日期的运算
LocalDate、LocalTime、LocalDateTime
当我们打印LocalDate、LocalTime、LocalDateTime的时候他是严格按照ISO 8601格式输出的
由于这些新的时间API都是不可变对象,因此进行运算后需要使用一个新的
LocalDate、LocalTime、LocalDateTime
类型的变量来接收运算后的时间对象
示例代码1
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
public class Main {
public static void main(String[] args) throws Exception {
LocalDate d1 = LocalDate.now();
System.out.println(d1);
System.out.println("Week = " + d1.getDayOfWeek().getValue());
LocalDate d2 = LocalDate.of(2016, 11, 30);
System.out.println(d2);
LocalTime t1 = LocalTime.now();
System.out.println(t1);
LocalTime t2 = LocalTime.of(15, 16, 17);
System.out.println(t2);
LocalDateTime dt1 = LocalDateTime.now();
System.out.println(dt1);
LocalDateTime dt2 = LocalDateTime.of(d2, t2);
System.out.println(dt2);
复制代码
输出
2019-04-10
Week = 3
2016-11-30
23:30:54.903
15:16:17
2019-04-10T23:30:54.903
2016-11-30T15:16:17
复制代码
代码示例2:时间计算
import java.time.DayOfWeek
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.Period
import java.time.temporal.TemporalAdjusters
public class Calculate {
public static void main(String[] args) throws Exception {
// 获取当前日期和时间:
LocalDateTime ldt = LocalDateTime.now()
System.out.println(ldt)
// + 5 days:
LocalDateTime ldt2 = ldt.plusDays(5)
System.out.println(ldt2)
// - 2 hours:
LocalDateTime ldt3 = ldt2.minusHours(2)
System.out.println(ldt3)
// 获得当月第一天:
LocalDate firstDay = LocalDate.now().withDayOfMonth(1)
LocalDate firstDay2 = LocalDate.now().with(TemporalAdjusters.firstDayOfMonth())
System.out.println(firstDay.equals(firstDay2))
System.out.println(firstDay)
// 获得当月最后一天:
LocalDate lastDay = LocalDate.now().with(TemporalAdjusters.lastDayOfMonth())
System.out.println(lastDay)
// 获得当月第一个星期日:
LocalDate firstSunday = LocalDate.now().with(TemporalAdjusters.firstInMonth(DayOfWeek.SUNDAY))
System.out.println(firstSunday)
// 判断两个日期哪个在前:
System.out.println(firstSunday.isBefore(LocalDate.now()))
// 两个日期相差?年?月?天:
Period p = LocalDate.now().until(LocalDate.of(2050, 1, 1))
System.out.println(p)
// 两个日期一共相差多少天:
System.out.println(LocalDate.of(2050, 1, 1).toEpochDay() - LocalDate.now().toEpochDay())
复制代码
输出
2019-04-10T23:32:35.942
2019-04-15T23:32:35.942
2019-04-15T21:32:35.942
2019-04-01
2019-04-30
2019-04-07
P30Y8M22D
11224
复制代码
示例代码3:时间格式化
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class Format {
public static void main(String[] args) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
System.out.println(dtf.format(LocalDateTime.now()));
LocalDateTime dt1 = LocalDateTime.parse("2016-11-30T15:16:17");
System.out.println(dt1);
LocalDateTime dt2 = LocalDateTime.parse("2016-11-30 15:16:17", dtf);
System.out.println(dt2);
复制代码
输出
2019-04-10 23:33:55
2016-11-30T15:16:17
2016-11-30T15:16:17
复制代码
小结
不变类(类似String)
默认按ISO8601标准格式化和解析
使用 DateTimeFormatter自定义格式化和解析
使用 plusDays()/minusHours()等方法对日期和时间进行加减,返回新对象
使用 withDayOfMonthi0)/with()等方法调整日期和时间,返回新对象
使用 isBefore()/ isAfter()/ equals(判断日期和时间的先后
ZonedDateTime
ZonedDateTime = LocalDateTime + ZoneId
ZonedDateTime可以做时区转换:withZoneSameInstant
ZoneId:新的时区对象
Instant:时刻,可以转换为long(注意单位是秒)
ZonedDateTime、Instant和long可以互相转换
Period和Duration表示一段时间,可用于日期和时间的加减
其它底层API:
ZoneOffset 时区偏移量
OffsetDateTime 类似ZonedDateTime
OffsetTime 带offset的LocalTime
ChronoLocalDate / ChronoLocalDateTime用于实现其他历法
时间对象转换示意图:
继承关系:
TemporalAmout接口表示一段时间:1天/2小时/30分钟...
可以加减一个TemporalAmout对象
实例代码1
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class Main {
public static void main(String[] args) throws Exception {
ZonedDateTime now = ZonedDateTime.now();
System.out.println(now);
System.out.println(now.getZone());
Instant ins = now.toInstant();
System.out.println(ins.getEpochSecond());
ZonedDateTime london = ZonedDateTime.now(ZoneId.of("Europe/London"));
System.out.println(london);
ZonedDateTime newyork = london.withZoneSameInstant(ZoneId.of("America/New_York"));
System.out.println(newyork);
复制代码
输出
2019-04-11T15:02:51.919+08:00[Asia/Shanghai]
Asia/Shanghai
1554966171
2019-04-11T08:02:51.923+01:00[Europe/London]
2019-04-11T03:02:51.923-04:00[America/New_York]
复制代码
代码示例2:LocalDateTime的转换
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class Local2Zoned {
public static void main(String[] args) throws Exception {
LocalDateTime ldt = LocalDateTime.of(2016, 11, 30, 8, 15, 59);
ZonedDateTime bj = ldt.atZone(ZoneId.systemDefault());
System.out.println(bj);
ZonedDateTime ny = ldt.atZone(ZoneId.of("America/New_York"));
System.out.println(ny);
复制代码
输出
2016-11-30T08:15:59+08:00[Asia/Shanghai]
2016-11-30T08:15:59-05:00[America/New_York]
复制代码
代码示例3:
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class ChangeZone {
public static void main(String[] args) {
LocalDateTime ldt = LocalDateTime.of(2016, 11, 30, 8, 15, 59);
ZonedDateTime bj = ldt.atZone(ZoneId.systemDefault());
System.out.println(bj);
ZonedDateTime ny = bj.withZoneSameInstant(ZoneId.of("America/New_York"));
System.out.println(ny);
复制代码
输出
2016-11-30T08:15:59+08:00[Asia/Shanghai]
2016-11-29T19:15:59-05:00[America/New_York]
复制代码
总结:
ZonedDateTime就是LocalDateTime关联Zoned
ZonedDateTime可以做时区转换
Zoned表示时区
Instant表示时刻(内部用long表示eqoch second)
ZonedDateTime、Instant和Long可以互相转换
关系型数据库datatime字段与javaAPI的映射关系
新旧API的相互转换
尽量使用的新的api来处理时间日期java.time
储存到数据库的api接口与数据库字段映射:
日期:LocalDate->DATE
时间:LocalTime->TIME
日期+时间:LocalDateTime->DATETIME
时刻:long->BIGINT
如果要根据用户所在的时区不同来展示数据,数据表中最好保存long类型的时间戳,然后通过自定义的方法根据时区输出格式化后的日期时间,让JDK处理时区,不要手动调节时差。
连接数据库指定时区
如果你设置
serverTimezone=UTC
连接数据库正常,但是java代码将时间插入到数据库时间的时候会出现以下问题:
比如在java代码里面插入的时间为
2019-01-20 10:14:01
但是在数据库里面显示的时间却为
2019-01-20 02:14:01
有了8个小时的时差
UTC代表的是全球标准时间 ,中国使用的时间是北京时区也就是东八区,领先UTC八个小时。
正确的方式
mysql安装目录下my.ini配置文件中添加
default-time-zone='+08:00'
spring boot 配置文件application.properties中设置spring默认时区
spring.jackson.time-zone=GMT+8
spring boot 配置文件application.properties中设置jpa与数据库链接增加配置项默认时区
url: jdbc:mysql://127.0.0.1:3306/sys?serverTimezone=CTT&characterEncoding=utf8
复制代码
或者
//北京时间东八区
serverTimezone=GMT%2B8
//上海时间
serverTimezone=Asia/Shanghai
复制代码
持续更新......