Saving time data (with Zone) in Oracle DB not working because of Java SimpleDateFormat issue
我有一个字段定义为
要保存的值从
这是我试图保存到数据库的内容(所有日期信息加上区域)
数据库以UTC格式存储时间信息。
到目前为止,日期存储在数据库中,因此如下所示:
1 2 3 4 | DAYS --------------------------------------------------------------------------- 23-SEP-19 10.03.11.000000 PM -05:00 23-SEP-19 10.03.11.000000 PM -05:00 |
在处理过程中,它通过以下代码运行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | dateStr: the date (as seen above) ZoneLoc: 'US/Hawaii' public Calendar convDateStrWithZoneTOCalendar(String dateStr, String ZoneLoc) throws Exception { // convert the string sent in from user (which uses AM/PM) to one that uses military time (24HR) // it String formattedDate = null; DateFormat readFormat = new SimpleDateFormat(this.getPattern()); DateFormat writeFormat = new SimpleDateFormat("MM-dd-yyyy'T'HH:mm:ss'Z'"); writeFormat.setTimeZone(TimeZone.getTimeZone(ZoneLoc)); Date date = null; date = readFormat.parse(dateStr); formattedDate = writeFormat.format(date); // see if you can parse the date needed WITH the TimeZone Date d; SimpleDateFormat sdf = new SimpleDateFormat("MM-dd-yyyy'T'HH:mm:ss'Z'"); sdf.setTimeZone(TimeZone.getTimeZone(ZoneLoc)); d = sdf.parse(formattedDate); Calendar cal = Calendar.getInstance(); cal.setTime(d); system.out.println(" ZONELOC VALUE" + ZoneLoc); system.out.println(" RETURNED VALUE" + cal ); return cal; } |
号
返回的日历信息是:
ZONELOC VALUE IS US/Hawaii
RETURNED VALUE IS
java.util.GregorianCalendar[time=1577678591000,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="America/Chicago",offset=-21600000,dstSavings=3600000,useDaylight=true,transitions=235,lastRule=java.util.SimpleTimeZone[id=America/Chicago,offset=-21600000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2019,MONTH=11,WEEK_OF_YEAR=1,WEEK_OF_MONTH=5,DAY_OF_MONTH=29,DAY_OF_YEAR=363,DAY_OF_WEEK=1,DAY_OF_WEEK_IN_MONTH=5,AM_PM=1,HOUR=10,HOUR_OF_DAY=22,MINUTE=3,SECOND=11,MILLISECOND=0,ZONE_OFFSET=-21600000,DST_OFFSET=0]
号
看起来好像返回值中没有设置美国/夏威夷。
我能做些什么来确保这个设置?
之后,我可以把它放在数据库中,看看设置是否会"坚持"而不返回到
更新@帕特里克H-谢谢你的意见。我按照您指定的模式进行了更改,并且能够保存数据。现在看起来是这样的:
2017-08-02 13:38:49 TRACE o.h.type.descriptor.sql.BasicBinder - binding parameter [26] as [TIMESTAMP] - [java.util.GregorianCalendar[time=1569294191000,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="America/Chicago",offset=-21600000,dstSavings=3600000,useDaylight=true,transitions=235,lastRule=java.util.SimpleTimeZone[id=America/Chicago,offset=-21600000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2019,MONTH=8,WEEK_OF_YEAR=39,WEEK_OF_MONTH=4,DAY_OF_MONTH=23,DAY_OF_YEAR=266,DAY_OF_WEEK=2,DAY_OF_WEEK_IN_MONTH=4,AM_PM=1,HOUR=10,HOUR_OF_DAY=22,MINUTE=3,SECOND=11,MILLISECOND=0,ZONE_OFFSET=-21600000,DST_OFFSET=3600000]]
号
数据库中的数据如下:
1 | 23-SEP-19 10.03.11.000000 PM -05:00 |
即使指定了
根据此输出:
1 |
上面的时间值(也就是自unix epoch(
要解析输入
1 2 3 4 | SimpleDateFormat parser = new SimpleDateFormat("MM-dd-yyyy hh:mm:ss a"); // the input is in Hawaii timezone parser.setTimeZone(TimeZone.getTimeZone("US/Hawaii")); Date date = parser.parse("09-23-2019 10:03:11 pm"); |
号
上面的
然后可以将其设置为
我用Oracle的Timestamp作为时区类型已经有一段时间了,但我认为这足以保存正确的值。日历的价值是:
java.util.GregorianCalendar[time=1569312191000,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="US/Hawaii",offset=-36000000,dstSavings=0,useDaylight=false,transitions=7,lastRule=null],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2019,MONTH=8,WEEK_OF_YEAR=39,WEEK_OF_MONTH=4,DAY_OF_MONTH=23,DAY_OF_YEAR=266,DAY_OF_WEEK=2,DAY_OF_WEEK_IN_MONTH=4,AM_PM=1,HOUR=10,HOUR_OF_DAY=22,MINUTE=3,SECOND=11,MILLISECOND=0,ZONE_OFFSET=-36000000,DST_OFFSET=0]
号Java新的日期/时间API
旧类(
其中一个主要的问题是在不同的时区工作是多么的困难和混乱。
如果使用Java 8,请考虑使用新的JavaTimeAPI。与旧的API相比,它更容易、更少被窃听和更少出错。
如果您使用的是Java <=7,您可以使用StuteTeN后端,这是Java 8新的日期/时间类的一个很大的后端。对于Android,有三个etenabp(更多关于如何使用它)。
下面的代码适用于这两种情况。唯一的区别是包名称(在Java 8中是EDCOX1,20),在三重后端(或Android的TruteEnabp)是EDCOX1(21),但是类和方法名称是相同的。
要解析输入
1 2 3 4 5 6 7 8 9 10 11 | // parse the input DateTimeFormatter fmt = new DateTimeFormatterBuilder() // parse AM/PM and am/pm .parseCaseInsensitive() // input pattern .appendPattern("MM-dd-yyyy hh:mm:ss a") // use English locale for am/pm symbols .toFormatter(Locale.ENGLISH); LocalDateTime dt = LocalDateTime.parse("09-23-2019 10:03:11 pm", fmt); // convert to Hawaii timezone ZonedDateTime hawaiiDate = dt.atZone(ZoneId.of("US/Hawaii")); |
。
最新的JDBC驱动程序支持新的API(但仅针对Java 8,我猜),但是如果您仍然需要使用EDCOX1 OR 16,那么您可以很容易地将EDCOX1的26度转换为:
1 2 |
在Java 8中,您也可以这样做:
1 |
。
如果需要与旧的
根据simpledateformat,我认为您的格式化字符串是错误的。您还可以在返回值中看到月份和日期是错误的。
这是您目前拥有的:江户十一〔一〕号
我认为格式字符串应该是:
看起来时区问题也可能是因为里面有冒号。simpledateformat的文档表明,对于RFC822时区,它需要采用这种格式: