当前位置: 首页 > 知识库问答 >
问题:

由于Java SimpleDataFormat问题,在Oracle数据库中保存时间数据(带区域)不起作用

颜阳炎
2023-03-14

我有一个定义为TIMESTAMP AND TIME ZONE的字段。

要保存的值从美国/夏威夷区域中的"09-23-2019 10:03:11pm"开始。

这就是我试图保存到数据库的内容(所有日期信息加上区域)

数据库以UTC格式存储时间信息。

截至目前,日期存储在数据库中,如下所示:

DAYS
---------------------------------------------------------------------------
23-SEP-19 10.03.11.000000 PM -05:00
23-SEP-19 10.03.11.000000 PM -05:00

在处理过程中,它会运行以下代码:

    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价值是我们/夏威夷

返回值为java。util。GregorianCalendar[time=157767859100,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id=“America/Chicago”,offset=-2160000,dststavings=3600000,UseDayland=true,transitions=235,lastRule=java.util.SimpleTimeZone[id=America/Chicago,offset=-2160000,DStSaves=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDayOfWeek=8,startDayOfWeek=1,startDayOfWeek=1,startDayOfWeek=7200000,startTimeMode=0,endDayOfWeek=0,endDayOfWeek=1,endDayOfWeek=3,endMonth=10,endDayOfWeek=1,endDayOfWeek=1,endDayOfWeek=3,endDayOfWeek=1,endDayOfWeek=3,endDayOfWeek=3,endDayOfWeek=1,EndOfWeeOfWeek=1,WeeOfWeeOfWeek=1,We,周中的天(月中的),上午(月中的)下午(月中的)下午(月中的)下午(月中的)下午(月中的)下午(月)下午(月中的)下午(月)上午(月)下午(月)下午(月)上午(月)下午(月)下午(月)下午(月)上午(月)下午(月)下午)下午(月)上午(月)下午)下午(月)上午(月)下午)下午(月)下午(月)

看起来美国/夏威夷没有被设定在回归价值中。

我能做些什么来确保这一切都准备好了?

在那之后,我可以把它放在数据库中,看看设置是否会“粘住”,而不会恢复到America/Chicago

更新@Patrick H-感谢您的输入。我使用您指定的模式进行了更改,并且能够保存数据。它现在看起来像这样:

2017-08-02 13:38:49跟踪o.h.类型。描述符。sql。BasicBinder-绑定参数[26]为[TIMESTAMP]-[java.util.GregorianCalendar[time=156929419100,areFieldsSet=true,ArealFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id=“America/Chicago”,offset=-2160000,DSTSCAvings=3600000,useDaylight=true,transitions=235,lastRule=java.util.SimpleTimeZone[id=America/Chicago,offset=-2160000,DStSaves=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDayOfWeek=8,startDayOfWeek=1,startDayOfWeek=1,startDayOfWeek=1,startDayOfWeek=1,startTime=7200000,StartDayOfMendMode=0,endMode=3,endMonth=10,endDayOfWeek=1,endDayOfWeek=1,endDayOfWeek=1,endDayOfWeek=4,endTimeMode=2],firstDayOfWeek=1,MinimadayOfFirstDayOfWeek=1,ERA=1,ERA=2019=8,WEEK=8,WEEK=8,周中的天,月中的上午下午1点,小时10点,日中的小时22点,分钟3点,秒11点,毫秒0点,区域偏移量=-2160000点,DST偏移量=3600000点]]

数据库中的数据如下所示:

23-SEP-19 10.03.11.000000 PM -05:00

即使通过指定了美国/夏威夷,该区域仍然是America/Chicago。如何让美国/夏威夷坚持而不恢复到美国/芝加哥

共有2个答案

宰父疏珂
2023-03-14
匿名用户

根据SimpleDataFormat,我认为您的格式字符串是错误的。您还可以在返回值中看到,月份和日期是错误的<代码>月=11,月中日=29

这就是你目前拥有的:19年9月23日10.03.11.000000下午-05:00

我认为格式字符串应该是:'dd-MMM-yyhh.mm.ss.SSSSSS a Z'

看起来时区问题也可能是因为它里面有一个冒号。SimpleDataFormat的文档表明,对于RFC 822时区,它需要采用这种格式:-0500您可能会发现使用通用时区组件更容易。

纪辰沛
2023-03-14

根据这一结果:

java.util.GregorianCalendar[time=1569294191000,...

上述时间值(即自unix epoch(1970-01-01T00:00Z)起156929419100毫秒)相当于芝加哥的09-23-2019 10:03 PM)。这是因为readFormat正在使用系统的默认时区(可能是America/Chicago,只需检查timezone.getDefault()的值即可)。

要解析输入的09-23-2019 10:03:11pm并将其视为夏威夷的当地时间,您只需将相应的时区设置为SimpleDateFormat实例(在本例中,为readFormat,因为它需要知道输入日期在哪个时区-因为您没有设置任何,它使用系统的默认值)。您也不需要其他格式化程序(WriteFormatsdf),只能使用一个格式化程序来获取相应的日期:

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");

上面的date相当于夏威夷的晚上10:03。实际上,日期本身只包含unix纪元的毫秒(date.getTime()返回1569312191000),没有格式也没有任何时区信息。

然后可以将其设置为日历实例(不要忘记设置日历的时区):

Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("US/Hawaii"));
cal.setTime(date);

我已经有一段时间没有使用带有时区类型的oracle时间戳了,但我认为这足以保存正确的值。日历的价值是:

JAVAutil。GregorianCalendar[time=1569312111000,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,MinimadaySinFirstWeek=1,ERA=1,YEAR=2019,MONTH=8,WEEK=39,WEEK=4,WEEK=4,WEEK=23,DAY=266=266,DAY=2,WEEK=4,WEEK=10,DAY=上午1小时,下午1点,小时/天=22,分钟=3,秒=11,毫秒=0,区域偏移量=-36000000,DST偏移量=0]

旧类(DateCalendarSimpleDateFormat)有很多问题和设计问题,它们正在被新的API所取代。

其中一个主要问题是,在不同的时区工作是多么困难和令人困惑。

如果您使用的是Java8,请考虑使用新的Java。时间API。与旧的API相比,它更容易实现,更少出现错误,更不容易出错。

如果你使用的是Java

下面的代码适用于两者。唯一的区别是包名称(在Java8中是java.time,在Threeten Backport(或Android的ThreeTenABP)中是org.threeten.bp),但类和方法名称是相同的。

要解析输入09-23-2019 10:03:11pm,您可以使用DateTimeFormaster并将其解析为LocalDateTime-输入没有时区信息,因此我们只考虑日期和时间,然后我们可以将其转换为时区。

// 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),但是如果您仍然需要使用Calendar,您可以轻松地将ZoneDateTime转换为它:

Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("US/Hawaii"));
calendar.setTimeInMillis(hawaiiDate.toInstant().toEpochMilli());

在Java 8中,您还可以执行以下操作:

Calendar calendar = GregorianCalendar.from(hawaiiDate);

如果您需要与旧的CalendarDateAPI的互操作性,您可以在内部使用新API进行计算并在需要时从/转换为API。

 类似资料:
  • 尝试与数据库MySQL建立连接时出现此错误 与MySQL的连接是这样完成的:

  • 我有一个包在11g版本中运行良好。 但是当我在19c版本中部署相同的包时,行为是不同的。 PFB的描述。 包规范有一个游标,并使用游标%rowtype创建了一个表类型。具有返回表类型的流水线函数。 使用函数with table子句 因此,返回值可以作为一个表,我可以用列名读取结果。 在11g中,函数返回的列标题与游标列名相同。但在19c中,函数返回列标题,如“Attr_1、Attr_2等”。 我需

  • 问题内容: 我已经使用gps设备捕获了一个图的四个点(坐标)。 点1:-lat- 27.54798833长-80.16397166 点2:-lat 27.547766,长-80.16450166 点3:-lat 27.548131,长-80.164701 点4:---- 现在我想将这些坐标保存在oracle数据库中,并将其另存为多边形。 谢谢 问题答案: 如果打算使用Oracle Spatial来

  • 日志条目:10:25 运营:08:25

  • 这根本不是关于Spring靴的。 我的英语可以更好。 使用下面的Spring Data配置,我正在尝试执行DML请求。 恰好是< code>CrudRepository#save方法。 然而,执行Spring的CrudRepository#保存方法,我接下来要做的是: 只有选择由功能记录。 没有执行任何“插入”或“更新”语句来hibernate.show_sql日志记录。 数据库根本没有变化。 =

  • 我尝试使用pg_dump命令导出PostgreSQL数据库(数据库名ari_company): 然后我得到了这个错误: 但当我运行默认数据库(postgres)时,它会工作并转储。sql被创建。使用命令