Postgresql jooq UTC localdatetime在保存和加载之间更改

Postgresql jooq UTC localdatetime在保存和加载之间更改,postgresql,jdbc,jooq,localdatetime,Postgresql,Jdbc,Jooq,Localdatetime,我的同事使用jooq创建了一个postgresql数据库。从那时起,我们创建了具有字段和LocalDateTime.now(ZoneOffset.UTC)值的对象。当这些数据保存到此数据库并在几个小时后再次读取时,数据对象中的更改: public class PlannedInvoice { private UUID accountId; private LocalDateTime billingTime; } 保存方法类似于以下内容: LocalDateTime now =

我的同事使用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);
public PlannedInvoice findByAccountId(UUID accountId)
{
    PlannedInvoiceWithOffset temp = dsl.selectFrom(PLANNEDINVOICE)
            .where(PLANNEDINVOICE.ACCOUNTID.eq(accountId.toString()))
            .fetchOneInto(PlannedInvoiceWithOffset.class);

    return new PlannedInvoice(temp);
}
数据库当前使用带时区的时间戳,但我也很乐意用实际的LocalDateTime替换它,以完全避免这些问题()

当我们保存(2020年,8月13日,0日,0日)的
LocalDateTime.of值时,它将
2020-08-12 20:00:00-04
。这似乎仍然是正确的

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


那么,为什么在保存UTC值时会进行转换,而在从数据库读回UTC值时又不会进行转换呢?这对我来说似乎很违反直觉。我更愿意避免任何时区转换。

对我有效的方法是创建一个带有OffsetDateTime的临时读取对象,然后使用OffsetSameInstant(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();
}
现在我的read方法如下所示:

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

    return new PlannedInvoice(temp);
}

对我来说,有效的方法是使用OffsetDateTime创建一个临时读取对象,然后使用OffsetSameInstant(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();
}
现在我的read方法如下所示:

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

    return new PlannedInvoice(temp);
}

请提供一个时间进入的例子,以及它是如何出来的。另外,datetime存储的字段的数据类型是什么?另外,Postgres服务器中设置的
时区是什么,以及运行此代码的机器上的时区是什么?为什么现在使用了两次
ZoneOffset.UTC
?为什么不使用带时区的
TIMESTAMP
(以及
java.TIME.OffsetDateTime
,(jOOQ和JDBC中的默认值)或
java.TIME.Instant
)数据类型?否则,如果您的服务器(PostgreSQL)和客户端(Java)时区设置不一致,它们将一直妨碍您。我刚刚意识到您有(2020年,8月13日,0日,0日)和(2020-09-12 20:00:00-04)的
LocalDateTime.of(2020年,8月13日,0日,0日)和
2020-09-12 20:00:00-04
,并说“这似乎仍然正确。”。我不明白这是怎么回事?@BluE:正如我所说,映射到带时区的
时间戳的最佳类型是
java.TIME.OffsetDateTime
(jOOQ和JDBC的默认选择),或者
java.TIME.Instant
(这将在PostgreSQL中造成最少的麻烦)。为什么要使用
LocalDateTime
?这取决于您的客户端时区。@blue:SQL
DATE
java.time.LocalDate
请提供一个时间输入和输出的示例。日期时间存储在字段中的数据类型是什么?设置的
时区是什么Postgres服务器以及运行此代码的机器上的时区?为什么现在使用了两次
ZoneOffset.UTC
?为什么不使用带时区的
时间戳(以及
java.time.OffsetDateTime
,(在jOOQ和JDBC中默认)或
java.time.Instant
)相反,数据类型?否则,如果服务器(PostgreSQL)和客户端(Java)时区设置不一致,它们将一直妨碍您。我刚刚意识到您有
LocalDateTime.of(2020,Month.AUGUST,13,0,0
2020-09-12 20:00:00-04
并说“这似乎仍然正确。”。我不明白这是怎么回事?@BluE:正如我所说,映射到带时区的
时间戳的最佳类型是
java.TIME.OffsetDateTime
(jOOQ和JDBC的默认选择),或者
java.TIME.Instant
(这将在PostgreSQL中造成最少的麻烦)。为什么要使用
LocalDateTime
?这取决于您的客户端时区。@blue:SQL
DATE
java.time.LocalDate
我建议您不要基于每个查询或每个列来解决此问题,因为如果您在全局范围内没有正确地解决此问题,您团队中的每个人都会遇到此问题。我建议您不要这样做在每个查询或每个列的基础上解决这个问题,因为如果您在全球范围内没有正确地解决这个问题,团队中的每个人都会遇到这个问题。