【问题标题】:Java constants for Postgresql's days-of-weekPostgresql 星期几的 Java 常量
【发布时间】:2018-10-28 12:20:14
【问题描述】:

Postgresql 使用 EXTRACTdow 以下列方式返回星期几:0 是星期日,1 是星期一,一直到 6 是星期六,see official documentation

我正在寻找一些官方常量,无论是在 Java 中还是在 JDBC 中,或者可能是一些与此编号匹配的标准库(Apache Commons?)中。

【问题讨论】:

  • 您能给我们展示一些真正重要的 SQL/Java 代码吗?这几乎听起来打破了 JDBC 的抽象。
  • 你为什么不用isodow来代替dow?
  • @Rcordoval 这是正确的解决方案,请将其写成答案,我会接受。我没有意识到isodow 存在。
  • @TimBiegeleisen 我目前正在编写一个查询,该查询正在查找当前在各自时区有星期五上午 10:00 的客户,因此我需要将“星期五”的概念传递到查询中当然我不想硬编码。

标签: java postgresql dayofweek


【解决方案1】:

您可以使用 Calendar 常量减 1,以便匹配 PostgreSQL 值,即:Calendar.SUNDAY = 1

【讨论】:

  • 我在找官方的常量,如果我开始减1我还不如写自己的枚举。
  • 我绝对会随时使用它们,但不幸的是,Postgres 不符合 ISO 标准...
  • @DamCx 你有点没抓住重点(但对你+1)。 OP 希望使用与实际驱动程序一致的 Postgres Java 类。 java.util.Calendar 对 Postgres 一无所知。
  • 如果可以的话,我会避免使用 Calendar 类,它早已过时且设计不佳。而且,@DamCx,除了在这个过时的类中声明的常量之外,没有任何官方的常量。是的,这可能使它们成为官方的,但肯定不会使它们成为唯一的官方。
【解决方案2】:

根据相同的official documentation你应该使用isodow

星期一 (1) 到星期日 (7) 是星期几

【讨论】:

【解决方案3】:

tl;博士

我正在寻找一些 Java 中的官方常量

是的,Java 使用与 Postgres 中的 isodow 函数相同的标准 ISO 8601 定义在 DayOfWeek 枚举中定义一周中的 7 天值,其中一周从星期一到星期日运行,天数为 1-7 .

DayOfWeek.WEDNESDAY.getValue()  // Returns an `int` 1-7 for Monday-Sunday. 

3

java.time.DayOfWeek枚举

正如Answer by Rcordoval 建议的那样,使用Postgres function isodow

isodow 中的“iso”指的是ISO 8601 标准和its definition of week,其中周一至周日的天数为 1-7。

Java 在其DayOfWeek 枚举中支持相同的星期定义。该类为您定义了七个对象,一个用于一周中的每一天,例如DayOfWeek.MONDAY。要获取每个对象的星期几编号(周一至周日为 1-7),请致电 DayOfWeek::getValue。但在您的 Java 编码中,请专注于使用和传递 DayOfWeek 对象本身,而不仅仅是整数。

int dowNumber = DayOfWeek.WEDNESDAY.getValue() ;

3

从整数到 DayOfWeek 对象有点棘手,因为我们需要使用索引访问 Java 数组。该指数表示从零开始计数,因此请从您的星期数中减去 1。星期三是第 3 天,因此 2 的结果减去 1 即可访问DayOfWeek.WEDNESDAY

DayOfWeek dow = DayOfWeek.values()[ 3-1 ] ;  // Get object named `WEDNESDAY` using zero-based index counting, so 3 - 1 = 2.

dow.toString(): 星期三

顺便说一句,要自动本地化星期几的名称,请致电DayOfWeek::getDisplayName

Java 而非 SQL

我目前正在编写一个查询,该查询正在查找当前在各自时区具有星期五上午 10:00 的客户,因此我需要将“星期五”的概念传递到查询中,当然我不需要想要硬编码。

使用行业领先的 java.time 类在 Java 中完成这项工作可能比在 SQL 中更好。

您必须非常小心时区。明确时区,而不是依赖隐含的默认时区。

时区对于确定日期至关重要。对于任何给定的时刻,日期在全球范围内因区域而异。例如,Paris France 的午夜后几分钟是新的一天,而 Montréal Québec 仍然是“昨天”。

如果没有指定时区,JVM 会隐式应用其当前的默认时区。该默认值可能随时更改,因此您的结果可能会有所不同。最好将您想要/预期的时区明确指定为参数。

continent/region 的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用 3-4 个字母的缩写,例如 ESTIST,因为它们不是真正的时区,没有标准化,甚至不是唯一的 (!)。

ZoneId z = ZoneId.of( "America/Montreal" ) ;  
LocalDate today = LocalDate.now( z ) ;

如果你想使用 JVM 当前的默认时区,请求它并作为参数传递。如果省略,则隐式应用 JVM 的当前默认值。最好是明确的,因为默认值可能会在任何时候在运行时被 JVM 中任何应用程序的任何线程中的任何代码更改。

ZoneId z = ZoneId.systemDefault() ;  // Get JVM’s current default time zone.

接下来,争取下一个星期五,如果已经是星期五,就坚持今天。使用TemporalAdjuster 在日期之间进行调整,特别是在TemporalAdjusters 中找到的那个。

LocalDate nextOrSameFriday = today.with( TemporalAdjusters.nextOrSame( DayOfWeek.FRIDAY ) ) ;

你说你的目标是上午 10 点。

LocalTime lt = LocalTime.of( 10 , 0 ) ;  // 10 AM.

结合日期和区域以获得特定时刻。

ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z ) ;

通过提取Instant 对象调整为UTC。同一时刻,时间轴上的同一点,但挂钟时间不同。

Instant instant = zdt.toInstant() ;

制定您的 SQL 以查询 TIMESTAMP WITH TIME ZONE 类型的数据库列。

String sql = "SELECT * from tbl WHERE when_col = ? ; " ;
…
myPreparedStatement.setObject( … , instant ) ;

和检索。

Instant instant = myResultSet.getObject( … , Instant.class ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

在这种方法中,您需要 Postgres 中的 dowisodow 函数。


关于java.time

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

Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

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

您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。

从哪里获得 java.time 类?

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

【讨论】:

    猜你喜欢
    • 2015-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-31
    • 2021-12-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多