XMLGregorianCalendar到GregorianCalendar

时间:2016-08-31 20:44:09

标签: java date timezone

我只是尝试使用以下代码将XMLGregorianCalendar(我从JAXWS获得)的实例转换为特定TimeZone中的GregorianCalendar

日期将在EST中出现,我想将其转换为GMT以进一步保存到DB

//soap response <ns4:TimeStamp>2016-06-18T04:43:54-04:00</ns4:TimeStamp>
//dtime is what i got from JAXB for the above date, so I wrote::
Date date = dTime.toGregorianCalendar(TimeZone.getTimeZone("UTC"), Locale.US, null).getTime();
System.out.println(date);

输出:Sat Jun 18 14:13:54 IST 2016

由于上面没有按预期工作,所以我尝试了DateFormat并给出了预期的结果。

    DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
    df.setTimeZone(TimeZone.getTimeZone("UTC"));

    GregorianCalendar gc =  dTime.toGregorianCalendar();
    System.out.println(df.format(gc.getTime()));

输出:2016-06-18 08:43:54 +0000

这可能是什么问题,因为 toGregorianCalendar(...)没有给出所需的结果?

我还注意到上面从 toGregorianCalendar 获得的GregorianCalendar实例的fieldSet = false。不确定这是否是导致问题的原因。

  

java.util.GregorianCalendar中[时间= 1468382241000,的 areFieldsSet =假,areAllFieldsSet =假下,从宽=真,区= sun.util.calendar.ZoneInfo [ID = “UTC”,偏移= 0,dstSavings = 0,useDaylight =假,过渡= 0,lastRule =空],Firstdayofweek可= 1,minimalDaysInFirstWeek = 1,ERA = 1,YEAR = 2016,MONTH = 6,WEEK_OF_YEAR = 29,WEEK_OF_MONTH = 3,DAY_OF_MONTH = 12 ,DAY_OF_YEAR = 194,DAY_OF_WEEK = 3,DAY_OF_WEEK_IN_MONTH = 2,AM_PM = 1,HOUR = 11,HOUR_OF_DAY = 23,MINUTE = 57,SECOND = 21,微差= 0,ZONE_OFFSET = -14400000,DST_OFFSET = 0]

任何帮助将不胜感激.. !!

4 个答案:

答案 0 :(得分:1)

请记住,Java Date个对象没有时区。它们在UTC内部。时区仅在打印(格式化)时显示。

这个简单的代码有效:

XMLGregorianCalendar xmlCal = XMLGregorianCalendarImpl.parse("2016-06-18T04:43:54-04:00");
GregorianCalendar cal = xmlCal.toGregorianCalendar();
java.util.Date date = cal.getTime();

SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
format.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println(format.format(date)); // prints: 2016-06-18 08:43:54

由于您的目标是将其保存到数据库,因此您真的不在乎将其格式化为文本。假设您正在使用JDBC(而不是某些NoSQL),则需要Timestamp

XMLGregorianCalendar xmlCal = XMLGregorianCalendarImpl.parse("2016-06-18T04:43:54-04:00");
GregorianCalendar cal = xmlCal.toGregorianCalendar();
java.sql.Timestamp date = new java.sql.Timestamp(cal.getTimeInMillis());

现在,您可以使用PreparedStatement将其提交给setTimestamp()

答案 1 :(得分:1)

tl; dr

myPreparedStatement
.setObject(                     // Exchange java.time objects with your database in JDBC 4.2 and later.
    … ,                         // Specify which `?` placeholder in your SQL statement.
    myXMLGregorianCalendar      // A legacy class. Better to use *java.time* whenever possible.
    .toGregorianCalendar()      // Convert from the one legacy class to another, as a bridge towards the modern `ZonedDateTime` class.
    .toZonedDateTime()          // Convert to the modern class.
    .toInstant()                // Adjust from a time zone to UTC. Same moment, same point on the timeline, different wall-clock time.
    .atOffset(                  // Adjust from basic `Instant` class to the more flexible `OffsetDateTime` class, if your JDBC driver does not offer the optional support for `Instant`. 
        ZoneOffset.UTC          // Specify UTC using this constant.
    )                           // Returns a `OffsetDateTime` object.
)

java.time

您使用的是可怕的旧日期时间类,而这些类早已被JSR 310中定义的现代 java.time 类取代了。

  

将XMLGregorianCalendar(我从JAXWS获得)的实例转换为GregorianCalendar

首次通话XMLGregorianCalendar::toGregorianCalendar()

GregorianCalendar gc = myXMLGregorianCalendar.toGregorianCalendar() ;

从旧类GregorianCalendar转换为现代java.time.ZonedDateTimeCall the new conversion method已添加到旧类中。

ZonedDateTime zdt = gc.toZonedDateTime() ;
  

日期将在EST中发布,我想将其转换为GMT

java.time.Instant类代表UTC中的时刻,始终以UTC表示。您可以从Instant中提取ZonedDateTime。相同的时刻,不同的时钟时间。

Instant instant = zdt.toInstant() ;
  

进一步保存到数据库

如果JDBC驱动程序支持,则 可以将Instant传递给数据库。 Instant类型在JDBC 4.2中是可选的。

myPreparedStatement.setObject( … , instant ) ;

如果不支持,请使用OffsetDateTime,因为JDBC 4.2需要支持。

OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
myPreparedStatement.setObject( … , odt ) ;

检索。

OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
  

日期是美国东部时间

EST不是实时区域。

Continent/Region的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用2-4个字母的缩写,例如ESTIST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

ZoneId z = ZoneId.of( "America/Montreal" ) ;  
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;

答案 2 :(得分:1)

我正在使用以下代码将具有给定时区(例如 GMT+0)的给定源的 XMLGregorianCalendar 转换为具有当前系统时区的 GregorianCalendar

GregorianCalendar.from(xmlGregorianCalendar
    .toGregorianCalendar()
    .toZonedDateTime()
    .withZoneSameInstant(ZoneId.systemDefault()))

当您只使用XMLGregorianCalendar.toGregorianCalendar()时,返回的GregorianCalendar与源系统的时区相同,而不是当前系统的时区。 在收到数据时转换时区更安全:这样可以减少代码中潜在问题的数量,因为所有日期都基于系统时区。

例如:

XMLGregorianCalendar xmlGregorianCalendarFromSource = DatatypeFactory.newInstance()
    .newXMLGregorianCalendar("1983-09-30T23:00:00.000Z"); // the source system is on GMT+0
GregorianCalendar gregorianCalendarWithSourceTZ = xmlGregorianCalendarFromSource.toGregorianCalendar();
GregorianCalendar gregorianCalendarWithSystemTZ = GregorianCalendar.from(xmlGregorianCalendarFromSource 
    .toGregorianCalendar()
    .toZonedDateTime()
    .withZoneSameInstant(ZoneId.systemDefault()));
System.out.println(xmlGregorianCalendarFromSource); // displays "1983-09-30T23:00:00.000Z" (i.e. GMT+0)
System.out.println(gregorianCalendarWithSourceTZ.toZonedDateTime()); // displays "1983-09-30T23:00Z[GMT]" (i.e. GMT+0)
System.out.println(gregorianCalendarWithSystemTZ.toZonedDateTime()); // displays "1983-10-01T00:00+01:00[Europe/Berlin]" (my system timezone is GMT+1 or GMT+2 depending on daylight saving)

答案 3 :(得分:0)

作为另一种途径,您可以考虑在代码中使用Date&#39;而不是XMLGregorianCalendars,使用jaxb绑定,如this堆栈溢出问题中所述。