1

我的同事使用 jooq 创建了一个 postgresql 数据库。从那时起,我们创建了具有字段和 LocalDateTime.now(ZoneOffset.UTC) 值的对象。当这些被保存到这个数据库并在几个小时后再次读取时,我们的数据对象发生了变化:

public class PlannedInvoice
{
    private UUID accountId;
    private LocalDateTime billingTime;
}

保存方法与此类似:

LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC);
UUID accountId = UUID.randomUUID();

PlannedinvoiceRecord record = plannedInvoiceService.create();
record.setAccountid(accountId.toString());
record.setBillingtime(now.atOffset(ZoneOffset.UTC));
record.store();

和这样的读取方法:

return dsl.selectFrom(PLANNEDINVOICE)
        .where(PLANNEDINVOICE.ACCOUNTID.eq(accountId.toString()))
        .fetchOneInto(PlannedInvoice.class);

数据库timestamp with time zone目前使用,但我也很乐意用实际的 LocalDateTime 替换它,以完全避免这些问题(JOOQ 支持这个)!

当我们保存 的值时LocalDateTime.of(2020, Month.AUGUST, 13, 0, 0),它将2020-08-12 20:00:00-04在数据库中。这似乎仍然是正确的。

从数据库中读取值似乎出了问题。在 read 方法之后 billingTime 的值为 2020-08-12 20:00:00。在我看来,fetchOneInto重建数据对象时时区会被忽略。

那么为什么在保存 UTC 值时会进行转换,为什么在从数据库中读取这些值时没有转换呢?这对我来说似乎非常违反直觉。我宁愿完全避免任何时区转换。

4

1 回答 1

0

对我有用的是使用 OffsetDateTime 创建一个临时读取对象,然后使用withOffsetSameInstant(ZoneOffset.UTC).toLocalDateTime(). 最后修复它相当容易。从一开始就违反直觉,db 和/或 jooq 会将数据转换为其他时区。

这是新对象:

public class PlannedInvoiceWithOffset
{
    private UUID accountId;
    private OffsetDateTime billingTime;
}

用于创建所需数据对象并将时区调整为 UTC 的新构造函数:

public PlannedInvoice(PlannedInvoiceWithOffset tempObject)
{
    this.accountId = tempObject.getAccountId();
    this.billingTime = tempObject.getBillingTime().withOffsetSameInstant(ZoneOffset.UTC).toLocalDateTime();
}

现在我的读取方法如下所示:

public PlannedInvoice findByAccountId(UUID accountId)
{
    PlannedInvoiceWithOffset temp = dsl.selectFrom(PLANNEDINVOICE)
            .where(PLANNEDINVOICE.ACCOUNTID.eq(accountId.toString()))
            .fetchOneInto(PlannedInvoiceWithOffset.class);

    return new PlannedInvoice(temp);
}
于 2020-08-13T20:26:27.773 回答