添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
力能扛鼎的领结  ·  Java ...·  7 月前    · 
谦虚好学的毛衣  ·  How to round up ...·  10 月前    · 
安静的麻辣香锅  ·  RemoteCertificateValid ...·  1 年前    · 

日期: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);
    		// 把Date转化为long:
    		long t = now.getTime();
    		System.out.println(t);
    		// 把long转化为Date:
    		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());
    		// 以GMT+00:00时区打印日期时间:
    		System.out.println(now.toGMTString());
    		// 以当前时区+当前Locale打印日期时间:
    		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 {
    		// 按系统Locale解析日期时间:
    		String s1 = "2016-11-20 12:15:59";
    		Date date1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(s1);
    		System.out.println(date1);
    		// 解析MMM时默认按照系统Locale:如果奥解析英文Nov需要指定解析环境
    		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);
    		// 按ISO 8601标准格式解析:T用来分割时间和日期,所以解析的时候用单引号'T'来解析
    		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:
    		Calendar c = Calendar.getInstance();
    		// 转换为Date打印:
    		System.out.println(c.getTime());
    		// 转换为long打印:
    		System.out.println(c.getTimeInMillis());
    		// 获取年月日时分秒:
    		System.out.println("    Year = " + c.get(Calendar.YEAR));
    		// 注意月份从0开始:1月=0,2月=1,...,12月=11:
    		System.out.println("   Month = " + c.get(Calendar.MONTH));
    		System.out.println("     Day = " + c.get(Calendar.DAY_OF_MONTH));
    		// 注意星期从1开始:星期日=1,星期一=2,...,星期六=7:
    		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:
    		Calendar c = Calendar.getInstance();
    		// 转换为Date打印:
    		System.out.println(c.getTime());
    		// + 5 days:
    		c.add(Calendar.DAY_OF_MONTH, 5);
    		// - 2 hours:
    		c.add(Calendar.HOUR_OF_DAY, -2);
    		// 转换为Date打印:
    		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:
    		Calendar c = Calendar.getInstance();
    		// 转换为Date打印:
    		System.out.println(c.getTime());
    		// 设置为指定时间:
    		c.clear();
    		c.set(Calendar.YEAR, 1999);
    		c.set(Calendar.MONTH, 10); // 11月
    		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());
    		// 注意11月=11:
    		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);
    		// 用LocalDate和LocalTime组合:
    		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()));
    		// 按ISO格式解析:
    		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:
    		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转换为ZonedDateTime:
    		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转换为ZonedDateTime:
    		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
    复制代码

    持续更新......

    分类:
    阅读
    标签: