欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java基础:日期与时间

程序员文章站 2022-05-18 17:21:15
...

日期与时间

  • 日期
    如2020-06-17
  • 时间(可包含日期)
    如 12:10:10或2020-06-17 12:10:10

新纪元时间(Epoch Time)

epoch time 表示一个特定时间:1970-01-01 00:00:00 UTC,从这一时刻开始计算所经过的秒数称为UNIX时间戳(Unix timestamp)。在Java中可使用System.currentTimeMillis()获取时间戳。

Java时间API

老版本API

老版本时间API位于java.util包中。

  • Date 表示一个日期和时间对象。可以获取当前时间及对应的年月日时分秒等。
  • Calendar 可获取和设置年月日时分秒,比Date多了时间运算。
  • TimeZone 提供时区转换功能
    更多信息参考:廖雪峰-Date和Calendar

时间格式化

Date date = new Date();
var sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf.format(date));

更多格式化格式见:JDK文档: Class SimpleDateFormat

Java8中的新版本API

新的时间API位于java.time包中,主要API包含:

类别 API
本地日期时间 LocalDateTime ,LocalDate,LocalTime
时刻 Instant
时间间隔 Duration
包含时区的时间 ZonedDateTime
时区 ZoneId,ZoneOffset

时刻(Instant)

获取某一时刻时间戳

// 秒
instant.getEpochSecond()
// 毫秒
instant.toEpochMilli()

将时间戳转为特定时区时间

Instant ins = Instant.ofEpochSecond(1592385860);
System.out.println(ins);    // UTC 时间
ZonedDateTime zonedDateTime = ins.atZone(ZoneId.systemDefault());
ZonedDateTime zonedDateTime2 = ins.atZone(ZoneId.of("America/New_York"));

创建一个时间对象

LocalDateTime ldt = LocalDateTime.now();
LocalDateTime ldt2 = LocalDateTime.of(2020, 6, 17, 12, 12, 12);

上述两个时间对象都将输出标准的ISO 8601的格式

Duration和Period

Duration表示两个时刻之间的时间间隔,Period表示两个日期之间的天数

LocalDateTime ldt = LocalDateTime.now();
LocalDateTime ldt2 = LocalDateTime.of(2020, 6, 17, 12, 12, 12);
Duration duration = Duration.between(ldt2, ldt);
System.out.println(duration);
Period period = Period.between(LocalDate.now().minusDays(1), LocalDate.now());
System.out.println(period);

输出内容类似:PT4H34M1.412SP1D
输出格式:以P...T...的形式表示,P...T之间表示日期间隔,T后面表示时间间隔。
所以上述输出分别表示时间间隔为4小时34分钟1.412秒以及日期间隔为1天。

新版时间格式化(DateTimeFormatter)

DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
System.out.println(dtf.format(LocalDateTime.now()));

新版API还提供了更强大的日期计算方法,参见廖雪峰-LocalDateTime

带时区的时间

ZonedDateTime beijingTime = ZonedDateTime.now(); // 默认时区
ZonedDateTime newYorkTime = ZonedDateTime.now(ZoneId.of("America/New_York")); // 指定时区
// or create by asZone
ZonedDateTime beijingTime2 = ldt.atZone(ZoneId.systemDefault());
ZonedDateTime newYorkTime2 = ldt.atZone(ZoneId.of("America/New_York"));

输出如下

2020-06-17T16:55:47.874+08:00[Asia/Shanghai]
2020-06-17T04:55:47.876-04:00[America/New_York]

也可使用withZoneSameInstant()将时区转换为纽约时间:

ZonedDateTime newYorkTime3 = beijingTime.withZoneSameInstant(ZoneId.of("America/New_York"));

在数据库中存储日期和时间

我们可以在数据库中保存unix时间戳,然后根据用户选择的时区显示本地时间。

public static void main(String[] args) {
    long unixTimestamp = 1592386268000L;
    String bj = timestampToString(unixTimestamp, Locale.CHINA, "Asia/Shanghai");
    String ny = timestampToString(unixTimestamp, Locale.US, "America/New_York");
    System.out.println(bj);
    System.out.println(ny);
}
static String timestampToString(long epochMilli, Locale locale, String zoneId) {
    Instant ins = Instant.ofEpochMilli(epochMilli);
	// DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE_TIME;
    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    return dtf.withLocale(locale).format(ZonedDateTime.ofInstant(ins, ZoneId.of(zoneId)));
}

输出如下

2020-06-17 17:31:08
2020-06-17 05:31:08

ISO 8601

ISO 8601规定的日期和时间分隔符是T

  • 日期:yyyy-MM-dd
  • 时间:HH:mm:ss
  • 带毫秒的时间:HH:mm:ss.SSS
  • 日期和时间:yyyy-MM-dd’T’HH:mm:ss
  • 带毫秒的日期和时间:yyyy-MM-dd’T’HH:mm:ss.SSS

API文档

中文
English