9.1Java日期与时间

Epoch Time又称为时间戳,通常是用long表示的毫秒数

long t = 1574208900123L;

转换成北京时间就是2019-11-20T8:15:00.123。要获取当前时间戳可以使用System.currentTimeMillis()。

Java新旧标准库

  • 一套定义在java.util这个包里面,主要包括Date、Calendar和TimeZone这几个类;
  • 一套新的API是在Java 8引入的,定义在java.time这个包里面,主要包括LocalDateTime、Zon

新旧之间仍存有一定的关系,因此不能全部抛弃。

Date(旧)

java.util.Date表示一个日期与时间的对象,在其源码中实际存储了一个Long类型的时间戳。
Date基本用法

public class Main {
    public static void main(String[] args) {
        // 获取当前时间:
        Date date = new Date();
        System.out.println(date.getYear() + 1900); // 必须加上1900
        System.out.println(date.getMonth() + 1); // 0~11,必须加上1
        System.out.println(date.getDate()); // 1~31,不能加1
        // 转换为String:
        System.out.println(date.toString());
        // 转换为GMT时区:
        System.out.println(date.toGMTString());
        // 转换为本地时区:
        System.out.println(date.toLocaleString());
    }
}
输出:
2020
7
9
Thu Jul 09 01:36:39 UTC 2020
9 Jul 2020 01:36:39 GMT
Jul 9, 2020, 1:36:39 AM

注意getYear()返回的年份必须加上1900,getMonth()返回的月份是011分别表示112月,所以要加1,而getDate()返回的日期范围是1~31,又不能加1。
想要将其更加格式化:
使用SimpleDateFormat对其进行转换

public class Main {
    public static void main(String[] args) {
        // 获取当前时间:
        Date date = new Date();
        var sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println(sdf.format(date));
    }
}
输出:
2020-07-09 01:38:12

其中: yyyy:年, MM:月 ,dd: 日 ,HH: 小时 ,mm: 分钟,ss: 秒
一般来说,字母越长,输出越长,M为例:

  • M:输出9
  • MM:输出09
  • MMM:输出Sep
  • MMMM:输出September

Date是根据系统默认时间进行加载,因此有很多局限性,不能转换时区、不能对时间日期进行加减等。

Calendar(旧)

它比Date比多了一个可以计算日期和时间的功能。
使用Calendar需要用到该类的getInstance()静态方法,获取到该对象。另外,获取年月日信息时用到的是get()方法,参数为Calendar.MONTH等。年份不用换算,但月份加一,日期1-7是从周日到周六这样计算的。

public class Main {
    public static void main(String[] args) {
        // 获取当前时间:
        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(y + "-" + m + "-" + d + " " + w + " " + hh + ":" + mm + ":" + ss + "." + ms);
    }
}
2020-7-9 5 1:49:13.622

另外,如果要单独设置时间的话,要将其全部清除,并重新set()。

public class Main {
    public static void main(String[] args) {
        // 当前时间:
        Calendar c = Calendar.getInstance();
        // 清除所有:
        c.clear();
        // 设置2019年:
        c.set(Calendar.YEAR, 2019);
        // 设置9月:注意8表示9月:
        c.set(Calendar.MONTH, 8);
        // 设置2日:
        c.set(Calendar.DATE, 2);
        // 设置时间:
        c.set(Calendar.HOUR_OF_DAY, 21);
        c.set(Calendar.MINUTE, 22);
        c.set(Calendar.SECOND, 23);
        System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(c.getTime()));
        // 2019-09-02 21:22:23
    }
}
2019-09-02 21:22:23

对时区的转换中,需要用到java.util包中另一个类,TimeZone。
该类只用来获取时区ID,不是用来获取时间。
要列出系统支持的所有ID,请使用TimeZone.getAvailableIDs()。
下面例子是对时区的转换:

public class Main {
    public static void main(String[] args) {
        // 当前时间:
        Calendar c = Calendar.getInstance();
        // 清除所有:
        c.clear();
        // 设置为北京时区:
        c.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        // 设置年月日时分秒:
        c.set(2019, 10 /* 11月 */, 20, 8, 15, 0);
        // 显示时间:
        var sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));
        System.out.println(sdf.format(c.getTime()));
        // 2019-11-19 19:15:00
    }
}

时区转换步骤:

  1. 清除所有字段;
  2. 设定指定时区;
  3. 设定日期和时间;
  4. 创建SimpleDateFormat并设定目标时区;
  5. 格式化获取的Date对象(注意Date对象无时区信息,时区信息存储在SimpleDateFormat中)。

Calendar也可以对时间进行加减:

public class Main {
    public static void main(String[] args) {
        // 当前时间:
        Calendar c = Calendar.getInstance();
        // 清除所有:
        c.clear();
        // 设置年月日时分秒:
        c.set(2019, 10 /* 11月 */, 20, 8, 15, 0);
        // 加5天并减去2小时:
        c.add(Calendar.DAY_OF_MONTH, 5);
        c.add(Calendar.HOUR_OF_DAY, -2);
        // 显示时间:
        var sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date d = c.getTime();
        System.out.println(sdf.format(d));
        // 2019-11-25 6:15:00
    }
}
2019-11-25 06:15:00

新的日期和时间API

主要涉及的类型有:

  • 本地日期和时间:LocalDateTime,LocalDate,LocalTime;
  • 带时区的日期和时间:ZonedDateTime;
  • 时刻:Instant;
  • 时区:ZoneId,ZoneOffset;
  • 时间间隔:Duration。
  • 格式化类型:DateTimeFormatter

LocalDateTime(新)

表示当前日期:LocalDate,表示当前时间:LocalTime,表示当前日期和时间:LocalDateTime
在创建以上对象时,由于会消耗一定时间,因此三个对象创建的时间不一定一致,因此采用:

LocalDateTime dt = LocalDateTime.now(); // 当前日期和时间
LocalDate d = dt.toLocalDate(); // 转换到当前日期
LocalTime t = dt.toLocalTime(); // 转换到当前时间

创建指定的日期时,用of():

// 指定日期和时间:
LocalDate d2 = LocalDate.of(2019, 11, 30); // 2019-11-30, 注意11=11月
LocalTime t2 = LocalTime.of(15, 16, 17); // 15:16:17
LocalDateTime dt2 = LocalDateTime.of(2019, 11, 30, 15, 16, 17);
LocalDateTime dt3 = LocalDateTime.of(d2, t2);

例:

public static void main(String[] args) {
		LocalDateTime localDateTime = LocalDateTime.now();
		System.out.println(localDateTime);
		LocalDate localDate = localDateTime.toLocalDate();
		System.out.println(localDate);
		LocalTime localTime = localDateTime.toLocalTime();
		System.out.println(localTime);
	}

LocalDateTime对时间的加减:

public class Main {
    public static void main(String[] args) {
        LocalDateTime dt = LocalDateTime.of(2019, 10, 26, 20, 30, 59);
        System.out.println(dt);
        // 加5天减3小时:
        LocalDateTime dt2 = dt.plusDays(5).minusHours(3);
        System.out.println(dt2); // 2019-10-31T17:30:59
        // 减1月:
        LocalDateTime dt3 = dt2.minusMonths(1);
        System.out.println(dt3); // 2019-09-30T17:30:59
    }
}

对日期和时间进行调整则使用withXxx()方法,例如:withHour(15)会把10:11:12变为15:11:12:

  • 调整年:withYear()
  • 调整月:withMonth()
  • 调整日:withDayOfMonth()
  • 调整时:withHour()
  • 调整分:withMinute()
  • 调整秒:withSecond()

时间间隔:Duration和Period
Duration表示时刻的间隔,Period表示日期之间间隔的天数。

Duration d = Duration.between(start, end);//start和end都是LocalTime的实例
Period p = LocalDate.of(2019, 11, 19).until(LocalDate.of(2020, 1, 9));

ZonedDateTime

ZonedDateTime适用于操作时区,可用于时区转换。
创建ZonedDateTime对象,用now()返回当前时间。

ZonedDateTime zbj = ZonedDateTime.now(); // 默认时区
ZonedDateTime zny = ZonedDateTime.now(ZoneId.of("America/New_York")); // 用指定时区获取当前时间

ZoneId是java.time新引入的时区类,因此LocalDateTime也可以调用。

LocalDateTime ldt = LocalDateTime.of(2019, 9, 15, 15, 16, 17);
ZonedDateTime zbj = ldt.atZone(ZoneId.systemDefault());
ZonedDateTime zny = ldt.atZone(ZoneId.of("America/New_York"));

withZoneSameInstant()方法将一个时区转换为另一个时区。

 // 以中国时区获取当前时间:
        ZonedDateTime zbj = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
        // 转换为纽约时间:
        ZonedDateTime zny = zbj.withZoneSameInstant(ZoneId.of("America/New_York"));

DateTimeFormatter

这个对象与SimpleDateFormat相似,都是对日期时间进行格式化。
SimpleDateFormat不是线程安全的,但是DateTimeFormatter是线程安全的
对ZonedDateTime或LocalDateTime进行格式化,需要使DateTimeFormatter类
DateTimeFormatter可以通过格式化字符串和Locale对日期和时间进行定制输出。

Instant

Instant表示高精度时间戳,它可以和ZonedDateTime以及long互相转换。

Instant now = Instant.now();
System.out.println(now.getEpochSecond()); // 秒
System.out.println(now.toEpochMilli()); // 毫秒

1594272512
1594272512239

旧API转新的API
可以利用Instant,将旧的对象转换为Instant,再将Instant转换为新的对象
新API转旧API:

ZonedDateTime zdt = ZonedDateTime.now();
long ts = zdt.toEpochSecond() * 1000;

// long -> Date:
Date date = new Date(ts);

// long -> Calendar:
Calendar calendar = Calendar.getInstance();
calendar.clear();
calendar.setTimeZone(TimeZone.getTimeZone(zdt.getZone().getId()));
calendar.setTimeInMillis(zdt.toEpochSecond() * 1000);

java.sql.Date

在数据库中,我们最常用的方式是存储一个Instant用BIGINT型。
在数据库中存储时间戳时,尽量使用long型时间戳,它具有省空间,效率高,不依赖数据库的优点。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值