波斯日历 - 从Oracle DB

时间:2018-04-25 12:56:58

标签: java oracle jdbc calendar jalali-calendar

我的申请需要以下内容。

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

当我们提交表单时,日期将作为String in Action类出现。我们需要在DB中以波斯语格式保存这个日期。我们为波斯日历配置了DB。从DB用户检索数据时,应该只能以波斯语格式查看日期。

此外,用户可以切换2种语言(英语,波斯语)。因此,应用程序应该支持两种类型的日历(格里高利和波斯语)。如果用户使用英语登录,则应该可以看到公历。如果用户以波斯语登录,则波斯日历应该可见。

从格里高利到波斯语的日期转换我在下面使用: http://www.dailyfreecode.com/forum/converter-gregorian-date-jalali-date-20288.aspx

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

  1. 在提交表单时,如何在DB中以波斯语格式保存日期(在Action类中为String格式)?
  2. 从DB中检索数据时,它应该是波斯语格式。截至目前,JDBC客户端正在Gregorian Calender中检索日期。
  3. 我正在传递java.sql.Date(今天的日期),它在DB中以波斯语格式保存。使用下面的代码。

    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一样)?

    对于第1期,如果我以波斯语格式传递日期,则在数据库中保存不正确。 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。

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

4 个答案:

答案 0 :(得分:2)

java.sql.Date中没有日历类型,因此不可能将其强制为波斯语。 JDBC中的所有日期/时间值均以中性形式规范化,并且Oracle数据库也使用中性形式进行存储和处理。当NLS_CALENDAR为PERSIAN时,Oracle在中性格式之间来回转换值,而它在内部以中性格式进行处理时只是按照波斯日历约定“表示”它。

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

答案 1 :(得分:0)

  

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

将日期存储为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 |
  

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

输出值时,只需指定要用于格式化的日历。因此,对于波斯语,请将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客户端以波斯语格式检索日期。

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

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

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

答案 2 :(得分:0)

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

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

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

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

  2. 将日期转换为公历后,整个应用程序将继续使用公历日期运行。

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

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

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

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

答案 3 :(得分:0)

java.sql.Date定义为采用格里高利标准的UTC。以java.sql.Date的形式从数据库获取DATE可能无用。正确的答案是定义扩展PersianChronology的{​​{1}}和实现java.time.chrono.AbstractChronology的{​​{1}}。然后以PersianLocalDate的形式从数据库中获取值。这是很多工作,但从理论上讲是正确的事情。

java.time.chrono.ChronoLocalDate

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

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

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

反之,将PersianLocalDate发送到数据库将变得更加有趣。 Oracle数据库JDBC驱动程序不具备将未知类转换为DATE之类的数据库类型的功能,没有任何等同于上述PersianChronology方法挂钩的功能。您可以尝试使PersianLocalDate扩展ofPersianLocalDate方法必须返回一个oracle.sql.ORAData,其字节数与数据库作为查询结果发送的字节数相同。

也许更简单的方法是将波斯日期作为VARCHAR / Strings来回发送到数据库。驱动程序将在toDatum上调用oracle.sql.DATE方法,因此获取static of(String)很容易。如果数据库对PersianLocalDate的结果执行正确的操作,则调用setString会使发送值变得容易。如果没有,则定义PersianLocalDate并自己进行转换。

这是在实现对PersianLocalDate.toString的支持时讨论的一个用例,但是我们根本没有做任何事情所需的资源。而且我们不知道这种情况会多么普遍,因此很难证明进行这项工作是合理的。如果您有支持合同,建议您提交SR并要求增强功能。如果您可以提供PersianLocalDate.toDatabaseStringjava.time,则对我来说,分配一些资源来做某事会比较容易。也许无非是使setObject工作的钩子,但至少可以做到这一点。希望我能提供更多帮助。