Oracle的to_date函数返回一个不存在的日期

时间:2017-06-01 23:05:31

标签: java oracle date datetime

java.util.Date正在将"01/01/1901"解析为Date对象时,Java API会将日期转换为“01/01/1901 0:08:39”而不是“01/01/1901 0:00:00”,这仅发生在马来西亚时区。

这种情况正在发生,因为1901年马来西亚决定将他的时区与槟城,马六甲和新加坡同步,因此他们增加了8分39秒。 Java知道这一点,因此会自动为日期对象添加分钟和秒数(因为在马来西亚,01/01/1991日期不存在00:00:00小时)。

马来西亚TZ改变: https://www.timeanddate.com/time/change/malaysia/kuala-lumpur?year=1901

Java来源:

public class SimpleDateFormatExample {

    public static void main(String[] args) {

        SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy");

        // Locale for formatter
        Locale malaysianLocale = new Locale("ms", "MY");
        // Default date and time format for Malaysia
        DateFormat defaultMalaysianFormatter = DateFormat.getDateTimeInstance(
                DateFormat.DEFAULT, DateFormat.DEFAULT, malaysianLocale);
        // This step is crucial
        TimeZone malaysianTimeZone= TimeZone.getTimeZone("Asia/Kuala_Lumpur");
        defaultMalaysianFormatter.setTimeZone(malaysianTimeZone);
        try {
            format.setTimeZone(malaysianTimeZone);
            Date a = format.parse("01/01/1901");
            String t = defaultMalaysianFormatter.format(a);
            System.out.println(t);
                } catch (ParseException e) {
            e.printStackTrace();
        }
    }
}

示例java输出:

  

01 Januari 1901 12:08:39 AM

在Oracle数据库TO_date中,函数的工作方式不同,我们认为Oracle数据库不考虑时区,因此在通过SQL查询发送时,它不会检索正确的值。

Oracle Sql Source:

ALTER SESSION SET TIME_ZONE='Asia/Kuala_Lumpur';
select to_date('19010101 00:00:00','YYYYMMDD HH24:MI:SS') from dual;

示例Oracle输出:

  

01-JAN-01 00:00:00

此问题特定于马来西亚时区和1901 01/01

为什么Java和Oracle数据库的行为方式不同?

1 个答案:

答案 0 :(得分:2)

评论太长了:

DATE数据类型没有位置或时区。如果您需要,则需要使用TIMESTAMP WITH TIME ZONE数据类型:

ALTER SESSION SET TIME_ZONE='Asia/Kuala_Lumpur';

SELECT FROM_TZ(
         CAST(
           DATE '1901-01-01' + INTERVAL '08:39' MINUTE TO SECOND
           AS TIMESTAMP
         ),
         'Asia/Kuala_Lumpur'
       )
FROM DUAL;

输出:

1901-01-01 00.09.04.000000000 ASIA/KUALA_LUMPUR

指定1900-01-01 00:00:001900-01-01 00:08:38之间的任何值都会给ORA-01878: specified field not found in datetime or interval,因为Oracle知道它是无效的日期/时间/时区组合。

为什么输出为00:09:04而非00:08:39是另一个问题......

您还可以使用ANSI时间戳文字:

SELECT TIMESTAMP '1901-01-01 00:08:39 Asia/Kuala_Lumpur' FROM DUAL;