繁体   English   中英

如何将 java.nio.file.attribute.FileTime 保存到 PostgreSQL 的时间戳列中?

[英]How to save a java.nio.file.attribute.FileTime into a PostgreSQL's timestamp column?

我试图了解如何将收到的文件的修改日期作为java.nio.file.attribute.FileTime到 PostgreSQL 中的列中,这是一个timestamp

Reading the PostgreSQL page relating to Java 8 dates & times:https://jdbc.postgresql.org/documentation/head/8-date-time.html

我只能指出这一点:请注意,不支持 ZonedDateTime、 Instant和 OffsetTime / TIME [ WITHOUT TIMEZONE ]。

In the matching table (see link above) PostgreSQL advices TIMESTAMP [ WITHOUT TIMEZONE ] LocalDateTime but some people discourage you to use this Java class, eg http://blog.schauderhaft.de/2018/03/14/dont-use-localdatetime /

顺便说一下, FileTime只能转换为long (毫秒)或Instant (请参阅 Java 文档)。

那我该怎么办? 我迷路了。

tl;博士

您问:

如何将我收到的文件的修改日期作为java.nio.file.attribute.FileTime到 PostgreSQL 的列中

在 JDBC 4.2 或更高版本中使用类型TIMESTAMP WITH TIME ZONEOffsetDateTime来存储由FileTime object 表示的时刻。

myPreparedStatement
.setObject( 
    … ,                    // Specify number of placeholder `?` in your SQL code.
    myFileTime             // Your `java.nio.file.attribute.FileTime` object.
    .toInstant()           // Convert to a `java.time.Instant` object.
    .atOffset(             // JDBC 4.2 oddly does not require support for `Instant`, so simply convert to an `OffsetDateTime` object. Same moment, both in UTC, so no value added except to match JDBC spec.
        ZoneOffset.UTC     // We must specify *some* offset, so we might as well use an offset of zero hours-minutes-seconds. The constant `ZoneOffset.UTC` represents just that offset. 
    )                      // Returns an `OffsetDateTime` object we can use with JDBC 4.2 compliant drivers. 
);

Java(传统和现代)和标准 SQL 中的日期时间类型表

片刻

我只能指出这一点:请注意,不支持 ZonedDateTime、Instant 和 OffsetTime / TIME [ WITHOUT TIMEZONE ]。

该文本不是 Postgres 问题,而是JDBC 4.2 问题。 让我解释。

InstantOffsetDateTimeZonedDateTime这三个类都代表一个时刻,即时间线上的一个特定点。 表示时刻需要与 UTC 的偏移量(与 UTC 相差几小时-分钟-秒)或时区(过去、现在和未来对特定人群使用的偏移量的历史变化)的上下文地区)。

  • Instant始终采用 UTC(零时分秒的偏移量)。
  • OffsetDateTime是日期、时间和偏移量。
  • ZonedDateTime是日期、时间和时区。

从逻辑上讲,所有这三个 map 到 Postgres 中的TIMESTAMP WITH TIME ZONE列。 Postgres 采用任何时区或偏移信息来调整为 UTC,存储 UTC 值,然后丢弃任何提供的区域/偏移量。

所以你会认为 JDBC 规范需要对所有这三个规范的支持。 但莫名其妙的是,JDBC 团队选择只需要对OffsetDateTime的支持。 这是一个不幸的决定,因为其他两种类型更常用。 无论如何,您可以轻松转换。 查看 to to…from…at…with…方法。

Instant instant = Instant.now() ;
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;  // Effectively the same thing as an `Instant`, a moment as seen in UTC. 
myPreparedStatement.setObject( … , odt ) ;

特定的JDBC 驱动程序可能支持Instant和/或ZonedDateTime以及OffsetDateTime 但是,如果您的目的是编写可移植代码以与各种驱动程序一起使用,请单独使用OffsetDateTime

存储java.nio.file.attribute.FileTime

立柱类型

你说:

我试图了解如何将我收到的文件的修改日期作为 java.nio.file.attribute.FileTime 保存到 PostgreSQL 中的列中,这是一个时间戳。

检查数据库列的类型。

  • 您的列必须是TIMESTAMP WITH TIME ZONE类型
  • 另一种类型TIMESTAMP WITHOUT TIME ZONE不能代表时刻,因此它不能存储您的FileTime object 的值。

Java型

如您所述, java.nio.file.attribute.FileTime class 在 Java 8 及更高版本中添加了toInstant方法。 正是我们需要通过 JDBC 4.2 或更高版本将这一时刻存储在数据库中的内容。

与上面看到的相同类型的代码:

Instant instant = myFileTime.toInstant() ;
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;  // Effectively the same thing as an `Instant`, a moment as seen in UTC. 
myPreparedStatement.setObject( … , odt ) ;

或更短,但不一定更好:

myPreparedStatement.setObject( … , myFileTime.toInstant().atOffset( ZoneOffset.UTC ) ) ;

恢复。

OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;

如果您需要Instant ,请转换。

Instant instant = odt.toInstant() ;

你说:

在匹配表中(参见上面的链接) PostgreSQL 建议 TIMESTAMP [ WITHOUT TIMEZONE ] LocalDateTime

这两种类型, TIMESTAMP WITHOUT TIMEZONELocalDateTime故意缺少任何时区或与 UTC 偏移的概念。 因此,它们不能代表片刻。 因此他们无法存储您的FileTime值,因为值是时间线上的特定点。

调整到时区

如果您想查看特定时区的挂钟时间,请应用ZoneId以获取ZonedDateTime object。 同一时刻,时间线上的同一点,不同的挂钟时间和日期。

Instant instant = myFileTime.toInstant() ;
ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

生成文本来表示该值。 我们可以要求java.time自动定位此类文本。

Locale locale = Locale.CANADA_FRENCH ; 
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime​( FormatStyle.FULL ).withLocale( locale ) ;
String output = zdt.format( f ) ;

请参阅在 IdeOne.com 上实时运行的代码 请注意日期和小时如何不同但代表相同的时刻。

即时.toString():2020-12-18T00:37:55.704644Z

output:jeudi 2020 年 12 月 17 日 à 19 小时 37 分 55 秒 heure normale de l'Est

日期时间处理很棘手

你说:

那我该怎么办? 我迷路了。

日期时间处理令人惊讶地令人困惑。 我们的直觉理解和日常习惯并没有帮助,实际上在程序员做这项工作时会适得其反。

要弄清楚主要概念是: A moment vs Not a moment

  • 销售交易的完成,在数据库中创建的记录,或者送货到您的前门——这些都是时刻。
  • 说今年的圣诞节从 2020 年 12 月 25 日开始并不是一个时刻,因为这一天的开始在世界各地有所不同,东方早晚西方。 圣诞老人在太平洋岛屿开始送货,随着日历逐小时翻到新的一天,向西飞去。
  • 无论政客们如何改变该地区与 UTC 的偏移量,都应在 6 个月内安排牙科预约,该预约应从下午 3 点开始——这不是一个时刻。

另一个关键概念是程序员和系统管理员应该将 UTC(零时分秒的偏移量)视为一个真实时间。 所有时区都只是变化。 在工作中,忘记您当地的教区时间; 将您桌上的时钟设置为 UTC。 在教区时间和 UTC 之间来回转换会让人发疯。


关于java.time

java.time框架内置于 Java 8 及更高版本中。 这些类取代了麻烦的日期时间类,例如java.util.DateCalendarSimpleDateFormat

要了解更多信息,请参阅Oracle 教程 并在 Stack Overflow 上搜索许多示例和解释。 规范是JSR 310

现在处于维护模式Joda-Time项目建议迁移到java.time类。

您可以直接与数据库交换java.time对象。 使用符合JDBC 4.2或更高版本的JDBC 驱动程序 不需要字符串,不需要java.sql.*类。 Hibernate 5 & JPA 2.2 支持java.time

从哪里获得 java.time 课程?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM