# 实践

## 旧API转新API

如果要把旧的Date或Calendar转换为新的API对象，可以通过toInstant()方法转换为Instant对象，在继续转换为ZonedDateTime。

```java
// Date -> Instant
Instant insl = new Date().toInstant();

// Calendar -> Instant -> ZonedDateTime
Calendar calendar = Calendar.getInstance();
Instant ins2 = calendar.toInstant();
ZonedDateTime zdt = ins2.atZone(calendar.getTimeZone().toZoneId());
```

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

除了旧的java.util.Date，我们还可以找到另为一个java.sql.Date。它继承自java.util.Date，但会自动忽略所有时间相关信息。

在数据库中，也存在几种日期和时间类型：

* DATETIME：表示日期和时间；
* DATE：仅表示日期
* TIME：仅表示时间
* TIMESTAMP：和DATETIME类似，但是数据库会在创建或者更新记录的时候同时修改TIMESTAMP。

在使用Java程序操作数据库时，我们需要把数据库类型与Java类型映射起来。下表是数据库类型与Java新旧API的映射关系：

| 数据库       | 对应Java类（旧）         | 对应Java类（新）    |
| --------- | ------------------ | ------------- |
| DATETIME  | java.util.Date     | LocalDateTime |
| DATE      | java.sql.Date      | LocalDate     |
| TIME      | java.sql.Time      | LocalTime     |
| TIMESTAMP | java.sql.Timestamp | LocalDateTime |

实际上，在数据库中，我们需要存储的最常用的是时刻（`Instant`），因为有了时刻信息，就可以根据用户自己选择的时区，显示出正确的本地时间。所以，最好的方法是直接用长整数`long`表示，在数据库中存储为`BIGINT`类型。

通过存储一个`long`型时间戳，我们可以编写一个`timestampToString()`的方法，非常简单地为不同用户以不同的偏好来显示不同的本地时间：

```java
public class Main {
    public static void main(String[] args) {
        long ts = 1574208900000L;
        System.out.println(timestampToString(ts, Locale.CHINA, "Asia/Shanghai"));
        System.out.println(timestampToString(ts, Locale.US, "America/New_York"));
    }

    static String timestampToString(long epochMilli, Locale lo, String zoneId) {
        Instant ins = Instant.ofEpochMilli(epochMilli);
        DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM, FormatStyle.SHORT);
        return f.withLocale(lo).format(ZonedDateTime.ofInstant(ins, ZoneId.of(zoneId)));
    }
}

```
