PostgreSQL 日期类型

在前后端的数据传递过程中,日期类型是一种特殊的类型,因此需要单独介绍处理方法。

创建表

首先,在 PostgreSQL 中创建一个带有时区的时间戳的表,示例如下:

CREATE TABLE activity(
  id BIGINT NOT NULL,
  title VARCHAR(256),
  start_time TIMESTAMP WITH TIME ZONE,
  end_time TIMESTAMP WITH TIME ZONE,
  PRIMARY KEY (id)
);

后端存储和查询

在后端,我们使用 Java 来处理和存储带有时区的时间戳。以下是一个示例:

import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.junit.Test;

import com.litongjava.data.utils.SnowflakeIdUtils;
import com.litongjava.jfinal.plugin.activerecord.Db;
import com.litongjava.jfinal.plugin.activerecord.Record;
import com.litongjava.tio.utils.environment.EnvUtils;
import com.sejie.admin.config.DbConfig;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class ActivityTest {

  @Test
  public void addActivity() {
    // 连接数据库
    EnvUtils.load();
    new DbConfig().config();

    // 获取当前系统时区
    ZoneId zoneId = ZoneId.systemDefault();

    // 设置开始时间
    long currentTimeMillis = System.currentTimeMillis();
    Instant startInstant = Instant.ofEpochMilli(currentTimeMillis);
    OffsetDateTime startTime = startInstant.atZone(zoneId).toOffsetDateTime();

    // 设置结束时间
    long endTimeMillis = System.currentTimeMillis() + (1000 * 60 * 60 * 24);
    Instant endInstant = Instant.ofEpochMilli(endTimeMillis);
    OffsetDateTime endTime = endInstant.atZone(zoneId).toOffsetDateTime();

    // 创建记录
    Record record = new Record()
        .set("id", SnowflakeIdUtils.id())
        .set("title", "Test Activity")
        .set("start_time", startTime)
        .set("end_time", endTime);
    boolean save = Db.save("activity", record);
    log.info("save result:{}", save);
    // SQL: insert into "activity"("id", "title", "start_time", "end_time") values(?, ?, ?, ?)
  }

  @Test
  public void listActivity() {
    // 连接数据库
    EnvUtils.load();
    new DbConfig().config();
    // 查询所有记录
    List<Record> records = Db.findAll("activity");
    List<Map<String, Object>> lists = records.stream()
        .map(e -> e.toMap())
        .collect(Collectors.toList());
    // 打印结果
    for (Map<String, Object> map : lists) {
      for (Map.Entry<String, Object> e : map.entrySet()) {
        if (e.getValue() != null) {
          log.info("{},{},{}", e.getKey(), e.getValue(), e.getValue().getClass().toString());
        }
      }
    }
  }
}

在 Java 中,对应的类型是 Timestamp

start_time,2024-07-08 15:37:30.846,class java.sql.Timestamp
end_time,2024-07-08 15:37:30.846,class java.sql.Timestamp

前后端参数传递

创建活动接口

前端通过 /api/table/activity/create 接口传递如下参数:

{
  "title": "Test Title1",
  "start_time": 1720420650846,
  "end_time": 1720420650846,
  "start_time_input_type": "millisecond",
  "end_time_input_type": "millisecond",
  "start_time_to_type": "ISO8601",
  "end_time_to_type": "ISO8601"
}

后端实际接收到的数据:

tableName: activity, kv: {start_time=2024-07-08T15:37:30.846+09:00, end_time=2024-07-08T15:37:30.846+09:00, title=Test Title1}

执行的 SQL 语句:

insert into "activity"("start_time", "end_time", "title", "id") values(?, ?, ?, ?)

查询活动接口

通过 ID 查询活动的示例:

id=399895750549155840
idType=long

返回的数据格式如下:

{
  "data": {
    "title": "Test Activity",
    "start_time": 1720418576632,
    "update_time": 1720418590002,
    "id": "399895750549155840"
  },
  "ok": true,
  "msg": null,
  "code": 1
}

注意,输出的 start_timeupdate_time 都是毫秒时间戳格式,前端需要自行解析。