[英]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 文档)。
那我该怎么办? 我迷路了。
您问:
如何将我收到的文件的修改日期作为
java.nio.file.attribute.FileTime
到 PostgreSQL 的列中
在 JDBC 4.2 或更高版本中使用类型TIMESTAMP WITH TIME ZONE
和OffsetDateTime
来存储由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.
);
我只能指出这一点:请注意,不支持 ZonedDateTime、Instant 和 OffsetTime / TIME [ WITHOUT TIMEZONE ]。
该文本不是 Postgres 问题,而是JDBC 4.2 问题。 让我解释。
Instant
、 OffsetDateTime
和ZonedDateTime
这三个类都代表一个时刻,即时间线上的一个特定点。 表示时刻需要与 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.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 TIMEZONE
和LocalDateTime
故意缺少任何时区或与 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 。
另一个关键概念是程序员和系统管理员应该将 UTC(零时分秒的偏移量)视为一个真实时间。 所有时区都只是变化。 在工作中,忘记您当地的教区时间; 将您桌上的时钟设置为 UTC。 在教区时间和 UTC 之间来回转换会让人发疯。
java.time框架内置于 Java 8 及更高版本中。 这些类取代了麻烦的旧日期时间类,例如java.util.Date
、 Calendar
和SimpleDateFormat
。
要了解更多信息,请参阅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.