【问题标题】:Persian calendar - Insertion and retrieval date in Persian format from Oracle DB波斯日历 - 从 Oracle DB 以波斯格式插入和检索日期
【发布时间】:2018-10-05 23:21:22
【问题描述】:

我的应用程序需要以下内容。

在我的应用程序中(在 struts 中),我们需要支持波斯日历。

当我们提交表单时,日期在 Action 类中以 String 的形式出现。我们需要将此日期以波斯格式保存在数据库中。我们已经为波斯日历配置了数据库。在从数据库用户检索数据时,应该只能看到波斯格式的日期。

此外,用户可以切换 2 种语言(英语、波斯语)。所以,应用程序应该支持两种类型的日历(公历和波斯)。如果用户用英语登录,公历应该是可见的。如果用户使用波斯语登录,那么波斯日历应该是可见的。

对于从公历到波斯的日期转换,我在下面使用: http://www.dailyfreecode.com/forum/converter-gregorian-date-jalali-date-20288.aspx

在上述要求中,我面临两个问题:

  1. 提交表单时,如何将日期(在 Action 类中为 String 格式)以波斯格式保存到 DB 中?
  2. 从 DB 检索数据时,它应该采用波斯语格式。截至目前,JDBC 客户端正在检索公历中的日期。

我正在传递 java.sql.Date(今天的日期),它以波斯格式保存在数据库中。使用下面的代码。

java.sql.Date sqlDate = null; 
java.util.Date utilDate = new Date(); 
sqlDate = new java.sql.Date(utilDate.getTime()); 
PreparedStatement psmtInsert = conn.prepareStatement(insertQuery); 
psmtInsert.setDate(1, sqlDate)); 
psmtInsert.executeUpdate();

用于检索:

PreparedStatement psmtSelect = conn.prepareStatement("select dateOfJoining from EMPLOYEE");
ResultSet resultSet = psmtSelect.executeQuery();
while (resultSet.next()) {
    System.out.println(resultSet.getDate(1));
}

但它以公历类型返回日期。

我们在 Tomcat/JVM/JDBC 客户端中是否有任何设置可以将从 DB 返回的日期转换为波斯格式本身(就像我们在 Oracle 中有 NLS_CALENDAR 、NLS_DATE_FORMAT 一样)?

对于第一个问题,如果我以波斯格式传递日期,那么在 DB 中它保存不正确。 PFB 我的代码:

java.sql.Date sqlDate = null; 
java.util.Date utilDate = new Date("1397/02/04"); 
sqlDate = new java.sql.Date(utilDate.getTime()); 
PreparedStatement psmtInsert = conn.prepareStatement(insertQuery); 
psmtInsert.setDate(1, sqlDate)); 
psmtInsert.executeUpdate();

以上是在 DB 中插入为 0777/09/13。

我们如何才能克服上述问题? 提前致谢。

【问题讨论】:

  • 到底是什么问题?您不能将日期从公历转换为波斯?你知道怎么做,但你得到错误的结果?您不知道如何将日期从字符串转换为日期格式?请缩小您的问题范围,现在它太宽泛了,没有具体的问题说明。
  • 实际时间是通用的,为什么不能直接保存日期为时间戳!!!然后根据需要转换为波斯语/格鲁吉亚语
  • @Psytho:关于第二期,我可以将日期以波斯格式保存在数据库中。但是在从数据库 JDBC 客户端获取公历格式的检索日期时。所以,我的问题是:我们有什么方法可以使用哪个 JDBC 客户端以波斯格式检索日期。附言这是一个现有的应用程序,因此我希望实现上述目标所需的更改最少。虽然,我可以将从 DB 返回的日期转换为波斯语,但这需要太多的努力。这就是为什么我需要另一种方法。
  • 请添加一些代码,您如何向数据库提交日期,如何从那里检索它以及它的外观。
  • 当你说new Date("1397/02/04")(一个被弃用的构造函数,顺便说一句)“插入为 0777/09/13”时,你是如何确定的? Java 似乎已经解释了公历/儒略历中的“1397/02/04”(大约 18078422400000 毫秒 纪元之前),在“波斯历”中将是 777 年。如果你想要Java 要在其他日历中解释“1397/02/04”,那么您需要在存储之前将其转换为公历,然后在检索后将其转换回来。您在问题中引用的代码应该对此有所帮助,假设它是正确的。

标签: java oracle jdbc calendar jalali-calendar


【解决方案1】:

java.sql.Date 中没有日历类型,因此无法将其强制为 波斯语。 JDBC 中的所有日期/时间值都以中性形式标准化,Oracle 数据库也使用中性形式进行存储和处理。当NLS_CALENDAR 是波斯语时,Oracle 将值转换为中性形式和从中性形式转换,它只是在内部以中性形式处理时以波斯日历约定“呈现”它。

通常最好对后端中的所有值始终使用中性形式。通常在 UI 层中使用转换器作为本地化的一部分,以根据个人用户的首选语言环境进行定制。如果需要中间层的 Java 本地化,Douglas 在上面建议的 java.time.chrono 包将是一个干净的解决方案。

【讨论】:

  • 谢谢。这意味着数据库将波斯 DATE 值发送到公历中的 JDBC,并且要构造 PersianLocalDate 方法必须从公历转换。最简单的方法是定义 of(LocalDate) 并使用 java.time.chrono 支持进行转换。要将 PersianLocalDate 发送到数据库,您将使用 LocalDate.from(TemporalAccessor)。
【解决方案2】:

提交表单时,如何将日期(在Action类中为String格式)以波斯格式保存在DB中?

将日期存储为 DATE 数据类型,当您要将其插入表中时,请使用 TO_DATE 和波斯语的 NLS 日历参数,将其从 Persion 格式的字符串转换为日期:

SQL Fiddle

查询 1

SELECT TO_DATE(
         '1397/02/05',
         'yyyy/mm/dd',
         'nls_calendar=persian'
       )
FROM   DUAL

Results

| TO_DATE('1397/02/05','YYYY/MM/DD','NLS_CALENDAR=PERSIAN') |
|-----------------------------------------------------------|
|                                      2018-04-25T00:00:00Z |

从数据库中检索数据时,它应该是波斯语格式。截至目前,JDBC 客户端正在检索公历中的日期。

输出值时,只需指定要用于格式化的日历即可。所以对于波斯语,使用TO_CHAR 和波斯语的 NLS 日历参数:

查询 2

SELECT TO_CHAR(
         DATE '2018-04-25',
         'yyyy/mm/dd',
         'nls_calendar=persian'
       )
FROM   DUAL

Results

| TO_CHAR(DATE'2018-04-25','YYYY/MM/DD','NLS_CALENDAR=PERSIAN') |
|---------------------------------------------------------------|
|                                                    1397/02/05 |

我们有什么方法可以使用哪个 JDBC 客户端以波斯格式检索日期。

这是一个常见的误解。 DATE 数据类型以 7 个字节存储在 Oracle 表中,包含年(2 个字节)、月、日、小时、分钟和秒(每个 1 个字节)。它没有任何“格式”(但它有效地存储在公历中)。

JDBC 不传输格式化的日期,它只是传输这 7 个字节并将其存储在 java.sql.Date 类中(该类也仅存储这些字节)。

如果要格式化DATE 数据类型,则需要将其转换为另一种数据类型;通常是您希望在 Oracle 数据库中使用 TO_CHAR 的字符串(或其他一些在 Java 中格式化日期的方法)。

【讨论】:

  • 是的,上面会起作用。但我的问题是我需要对现有应用程序进行更改。并且使用上述方法,我需要对每个 DAO 文件进行更改,这是一个非常长的活动。实际上,我正在寻找一些需要做最少更改的方法。 Tomcat/JVM/JDBC 客户端中的一些设置将从数据库返回的日期转换为波斯格式本身(就像我们在 Oracle 中有 NLS_CALENDAR ,NLS_DATE_FORMAT )。否则,我将继续使用建议的方法。
【解决方案3】:

只是为那些仍在寻找如何在应用程序中实现波斯日历的人提供输入。

我的应用程序应该支持公历和波斯历,还应该支持 Oracle 和 PostgreSQL 数据库。

要以最少的努力实施波斯历法,请执行以下步骤:

  1. 使用以下链接中建议的实现将来自 UI 的每个日期转换为 validate() 形式的公历格式 http://www.dailyfreecode.com/forum/converter-gregorian-date-jalali-date-20288.aspx

  2. 一旦日期转换为公历,整个应用程序将继续运行,因为它之前使用公历日期运行。

  3. 在数据库中保存日期时,我决定仅以公历格式存储日期,因为我还需要支持 PostgreSQL 数据库并且它不支持波斯日历。

  4. 在将数据提取到 UI 时,将从 DB 中检索日期,然后我再次将日期转换为波斯格式。

要在 UI 上显示波斯日历,请参阅以下链接。它也有其他日历实现 http://keith-wood.name/calendars.html

上述方法可以帮助实现大多数不同的日历。

【讨论】:

    【解决方案4】:

    java.sql.Date 定义为 UTC,即公历。从数据库中获取 DATE 作为 java.sql.Date 不太可能做任何有用的事情。正确的答案是定义一个扩展java.time.chrono.AbstractChronologyPersianChronology 和实现java.time.chrono.ChronoLocalDatePersianLocalDate。然后从数据库中获取值作为PersianLocalDate。工作量很大,但理论上这是正确的做法。

    PersianLocalDate per = rs.getObject(col, PersianLocalDate.class);
    

    我认为这可以发挥作用。不容易,但可能。如果您的PersianLocalDate 类定义了以下方法

    public static PersianLocalDate of(oracle.sql.DATE date) { ... }
    

    然后,Oracle 数据库 JDBC 将使用该方法在上面的 getObject 调用中构造一个 PersianLocalDate。有趣的部分是实现of(DATE) 方法。所有oracle.sql.DATE 方法都假定为公历。最好的办法是致电DATE.getBytes 并自己解释这些字节。字节 0 和 1 是年份,2 是月份,3 是月份中的日期。 TIMESTAMP.getJavaYear 会将这两个字节转换为 int 年份。它对日历一无所知;它只是在做算术。取决于数据库在发送波斯日期作为查询结果时所做的事情,这应该让您构造一个PersianLocalDate。如果数据库正在转换为公历,则您必须转换回波斯语。您的 PersianChronology 应该会对此有所帮助。

    反过来,向数据库发送PersianLocalDate 会更有趣。 Oracle 数据库 JDBC 驱动程序无法将未知类转换为 DATE 等数据库类型,这与上述 of 方法挂钩没有任何功能。你可以尝试让PersianLocalDate 扩展oracle.sql.ORADatatoDatum 方法必须返回一个 oracle.sql.DATE,其字节数与数据库作为查询结果发送的相同。

    一种更简单的方法可能是将波斯日期作为 VARCHAR/字符串来回发送到数据库。驱动程序会在PersianLocalDate 上调用static of(String) 方法,因此很容易获得PersianLocalDate。如果数据库对PersianLocalDate.toString 结果进行了正确处理,那么调用 setString 可以轻松发送值。如果没有,则定义 PersianLocalDate.toDatabaseString 并自己进行转换。

    这是我们在实现对java.time 的支持时谈到的一个用例,但我们根本没有做任何事情所需的资源。而且我们不知道它有多普遍,所以很难证明做这项工作的合理性。如果您有支持合同,我鼓励您提交 SR 并请求增强请求。如果您可以提供PersianChronologyPersianLocalDate,我会更容易分配一些资源来做某事。也许只不过是一个使 setObject 工作的钩子,但至少如此。我希望我能提供更多帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多