Wrong timezone in XMLGregorian calendar - java

I am using the below code to set a XMLGregorianCalendar field in webservice
SimpleDateFormat format = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss");
Date dateOfBirth = null;
try {
dateOfBirth = format.parse(adult.getDob_day() + "-" + adult.getDob_month() + "-"
+ adult.getDob_year() + " 00:00:00");
} catch (Exception e) {
log.error("Error while parsing dateOfBirth. Cause " + e.getMessage());
e.printStackTrace();
}
passenger.setDateOfBirthField(convertToXMLCalendar(dateOfBirth));
The method convertToXMLCalendar is as below
private XMLGregorianCalendar convertToXMLCalendar(Date date) {
XMLGregorianCalendar xmlCalendar = null;
GregorianCalendar calendar = new GregorianCalendar();
if (date != null) {
try {
calendar.setTime(date);
xmlCalendar = DatatypeFactory.newInstance().newXMLGregorianCalendar(calendar);
} catch (Exception e) {
log.error("Error while converting to XMLGregorianCalendar. Cause " + e.getMessage());
// e.printStackTrace();
}
}
return xmlCalendar;
}
My server location timezone is +03:00. But in few random scenarios the timezone is being send as +04:00 in SOAP request.
<ns7:dateOfBirthField>1955-08-27T00:00:00.000+04:00</ns7:dateOfBirthField>
Due to this the service is receiving the date as one day lesser than actual date. If I send 03-06-2014 00:00:00 its reaching the service as 02-06-2014 11:00:00.
If I set the time as 12:00:00 instead of 00:00:00 will it fix the issue. But whats the reason for this timezone change?

Your SimpleDateFormat doesn't specify a time zone, so it's using your local time zone. I would suggest:
Not parsing a value at all. You've got the individual day, month and year - so use that directly with a calendar!
Pass a Calendar to convertToXMLCalendar instead of a date... if you need to at all (see below)
Specify the time zone of the calendar as UTC if you really want to... although fundamentally I'd expect a dateOfBirth value to be just a date, to be honest, e.g. 1955-08-27. That way you're not specifying a time zone at all.
In fact, given that you've got the year/month/day, I'd just create an XMLGregorianCalendar directly from those values:
XMLGregorianCalendar calendar = DatatypeFactory.newInstance()
.newXMLGregorianCalendar(adult.getDob_year(),
adult.getDob_month(),
adult.getDob_day(),
DatatypeConstants.FIELD_UNDEFINED); // No time zone
Then you're representing a date rather than a dateTime, which is what fits your data.

Your calendar does not specify the time zone. I believe, just by modifying the convertToXMLCalendar method, we can get rid of this problem
private static XMLGregorianCalendar convertToXMLCalendar(Date date) {
XMLGregorianCalendar xmlCalendar = null;
GregorianCalendar calendar = new GregorianCalendar();
// You can set GMT time zone or Default or whatever
//TimeZone myzone = TimeZone.getTimeZone("GMT");
TimeZone myzone = TimeZone.getDefault();
calendar.getInstance(myzone);
if (date != null) {
try {
calendar.setTime(date);
xmlCalendar = DatatypeFactory.newInstance().newXMLGregorianCalendar(calendar);
} catch (Exception e) {
e.printStackTrace();
}
}
return xmlCalendar;
}

Related

Any possibility to parse a string to date object without converting to your system timezone with simpleDateFormat?

I have a birthday (Date object) that I would like to convert to UTC time.
I am able to use formatting to convert my locale time to UTC time by SimpleDatePattern. However when I format it, it converts the Date object to String. I tried parsing it (which returns a Date object) but converts it to local time system again. Here is my code below. Any help on converting the birthday field to UTC time while remaining a Date object and not a string?
public Date getBirthDay() {
if (birthDay == null) {
return null;
}
DateFormat utcFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
utcFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
String formattedBirthDate = utcFormat.format(birthDay);
try {
System.out.println("I am here within try block" + utcFormat.parse(formattedBirthDate));
birthDay = utcFormat.parse(formattedBirthDate);
} catch (ParseException e) {
e.printStackTrace();
}
return (Date) birthDay.clone();
}

SimpleDateFormat not formatting offset date time correctly

I got a timestamp as follows, 2019-10-17T07:10:39.021+10:30 but when I parse through the SimpleDateFormat then print again, it appear as 2019-10-17T07:40:39.021+11:00
Looks like it added the 30min to time then change the time zone. Is there is a way to fix that.
Date date = null;
String value = "2019-10-17T07:10:39.021+10:30";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", Locale.getDefault());
System.out.println("input :" + value);
try {
date = sdf.parse(value);
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println("output :" + sdf.format(date));
Result
input :2019-10-17T07:10:39.021+10:30
output :2019-10-17T07:40:39.021+11:00
Should be same as input.
The date string you have 2019-10-17T07:10:39.021+10:30consists of offset, so from java-8 you can use OffsetDateTime
A date-time with an offset from UTC/Greenwich in the ISO-8601 calendar system, such as 2007-12-03T10:15:30+01:00.
OffsetDateTime dateTime = OffsetDateTime.parse(date);
System.out.println(dateTime.toString()); //2019-10-17T07:10:39.021+10:30
Why are you using Locale.getDefault(), that parameter is not necessary. Can you try just calling it as below,
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");

get java Timezone id from +0000 format

I'm only getting this string "+0800" for a timezone from ihealth api. How can I get the corresponding java timezone id (like "US/Central") from this.
Calendar cal = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("Z");
try {
Date date = sdf.parse("+0800");
cal.setTime(date);
System.out.println(cal.getTimeZone().getID());
} catch (Exception e) {
System.out.println("error" + e.getMessage());
}
but this always prints "Etc/UTC" which is not "+0800". what am I missing here?
The difficulty in what you are asking is that there are (almost?) always many timezone names associated with a given offset. So, for an offset of "+0800" we can do
int rawOffset = 8 * 3600000; // +0800 hours converted to milliseconds
String[] tzIds = java.util.TimeZone.getAvailableIDs(rawOffset);
for (String id : tzIds) {
System.out.println(id);
}
and see the list
Antarctica/Casey
Asia/Brunei
Asia/Choibalsan
Asia/Chongqing
Asia/Chungking
Asia/Harbin
Asia/Hong_Kong
Asia/Kashgar
Asia/Krasnoyarsk
Asia/Kuala_Lumpur
Asia/Kuching
Asia/Macao
Asia/Macau
Asia/Makassar
Asia/Manila
Asia/Shanghai
Asia/Singapore
Asia/Taipei
Asia/Ujung_Pandang
Asia/Ulaanbaatar
Asia/Ulan_Bator
Asia/Urumqi
Australia/Perth
Australia/West
CTT
Etc/GMT-8
Hongkong
PRC
Singapore
If you want "the corresponding java timezone id" (emphasis mine) then I guess you'll have to pick one. ;)
Provided you use Java 8 you can use ZoneOffset
For example
ZoneOffset zoneOffset = ZoneOffset.of("+0200");
TimeZone timezone = TimeZone.getTimeZone(zoneOffset));
Edit: ZoneOffset.of() accepts offsetId, which is different from the 4 digits representation, so this would not solve the problem.
Try this:
Calendar cal = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("Z");
try {
Date date = sdf.parse("-0600");
cal.setTime(date);
System.out.println(sdf.format(date));
} catch (Exception e) {
System.out.println("error" + e.getMessage());
}

Convert UTC time to local time java Android

Im retrieving some values from a json service and the retrieved datetime values are stored in UTC format.
i've tried a lot of sample codes to convert the datetime values to user local timezone but im still getting the same value after conversion.
This is what i have actually: (copied from other posts)
String sJsonDate = "2015-07-08T12:08:13.0625+00:00";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
try {
Date localDateTime = simpleDateFormat.parse(sJsonDate);
} catch (ParseException e) {
e.printStackTrace();
}
The result value (localDateTime) is the same as the original value.
I am in Paraguay (GMT-4) and the resulting values needs to be minus one hour diference, like this: ("2015-07-08 07:13:25") (The values are stored in Argentina)
Help please!
I've found the solution, we are using day light savings so i had to disccount one hour to the resulting datetime.
So, i share the code for someone else:
public Date getDateInTimeZone(Date currentDate, String timeZoneId) {
TimeZone timeZone = TimeZone.getTimeZone(timeZoneId);
Date localDateTime = new Date(currentDate.getTime() + timeZone.getOffset(currentDate.getTime()));
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(localDateTime.getTime());
if (timeZone.useDaylightTime()) {
// time zone uses Daylight Saving
cal.add(Calendar.MILLISECOND, timeZone.getDSTSavings() * -1);// in milliseconds
}
return cal.getTime();
}
Usage:
String sDate = "2015-07-08T12:08:13.0625+00:00";
try {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
Date theDate = simpleDateFormat.parse(sDate);
Date localDateTime = getDateInTimeZone(theDate, TimeZone.getDefault().getID());
} catch (ParseException e) {
e.printStackTrace();
}

from XMLGregorianCalendar to Date/Calendar adds extra time/unwanted

I’m developing a client to a web service which exposes (.wsdl) contract, which requires yyyy-MM-dd format for 1 on the request parameters , however auto generated POJOS based on the .wsdl create the date attribute as Type XMLGregorianCalendar.
My issue is NOT converting to or from XMLGregorianCalendar see my utility below:
public static XMLGregorianCalendar toXMLGregorianCalendar(Calendar c){
GregorianCalendar gc = new GregorianCalendar();
gc.setTimeInMillis(c.getTimeInMillis());
XMLGregorianCalendar xc= null;
try {
xc = DatatypeFactory.newInstance().newXMLGregorianCalendar(gc);
} catch (DatatypeConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return xc;
}
My issue is going from XMLGregorianCalendar to Date/Calendar adds extra time/unwanted data to my yyyy-MM-dd when calling calendar.getTime();
In a particular code segment I need to go from XMLGregorianCalendar to Date
if (repairOrderType.getCloseDate() != null) {
LOG.debug("ServiceHistoryMapper, processRepairOrders() , repairOrderType.getCloseDate() BEFORE:"
+ repairOrderType.getCloseDate());
String date = repairOrderType.getCloseDate().getYear() + "-"
+ repairOrderType.getCloseDate().getMonth() + "-"
+ repairOrderType.getCloseDate().getDay();
//Approach #1, trying to remove hour,minute,sec values by calendar.clear() method , not successful
Calendar calendar = Calendar.getInstance();
calendar.set(repairOrderType.getCloseDate().getYear(),
repairOrderType.getCloseDate().getMonth(),
repairOrderType.getCloseDate().getDay());
calendar.clear(Calendar.HOUR);
calendar.clear(Calendar.MINUTE);
calendar.clear(Calendar.SECOND);
calendar.clear(Calendar.MILLISECOND);
/*Approach#2 , trying to remove hour,minute,sec values using SimpleDateFormat ,
* also not successful. SimpleDateFormat or DateFormat are use to format String output NOT remove internal data
*
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
Calendar calendar = formatter.getCalendar();
calendar.set(repairOrderType.getCloseDate().getYear(),
repairOrderType.getCloseDate().getMonth(),
repairOrderType.getCloseDate().getDay());
*/
LOG.debug("ServiceHistoryMapper, processRepairOrders() , repairOrderType.getCloseDate() AFTER:"
+ calendar.getTime());
repairOrder.setCloseDate(calendar.getTime());
}
Output:
27-Nov-2012 18:10:39.743 DEBUG com.tms.owners.integration.nsh.mapping.ServiceHistoryMapper - ServiceHistoryMapper, processRepairOrders() , repairOrderType.getCloseDate() BEFORE:2012-04-30
27-Nov-2012 18:10:51.413 DEBUG com.tms.owners.integration.nsh.mapping.ServiceHistoryMapper - ServiceHistoryMapper, processRepairOrders() , repairOrderType.getCloseDate() AFTER:Wed May 30 18:00:00 PDT 2012
As you can see above BEFORE date is BEFORE:2012-04-30 and AFTER date is May 30 18:00:00 PDT 2012 with unwanted hours "18:00:00 PDT".
Below is my actual request XML sent to the service:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns4:VehicleServiceHistoryDetails
xmlns="urn:tms.toyota.com/Components" xmlns:ns2="urn://esb.ari.xxxxxx.com/2008/12/10/schemas/common/Customer"
xmlns:ns3="urn:incentives.ari.xxxxxx.com/StandardHeader"
xmlns:ns4="urn://esb.ari.xxxxxx.com/2008/12/10/schemas/History"
xmlns:ns5="http://ice.ari.xxxxxx.com/EMF" xmlns:ns6="urn:ari.xxxxxx.com/rtmheader">
<ns5:ApplicationArea>
<ns5:CreationDateTime>2012-11-27T18:11:23.071-08:00
</ns5:CreationDateTime>
<ns5:Sender />
<ns5:UserArea />
</ns5:ApplicationArea>
<ns4:VehicleServiceHistoryDataArea>
<ns4:VehicleServiceHistoryHeader>
<ns3:TimeStamp>2012-11-27T18:11:23.071-08:00</ns3:TimeStamp>
<ns3:SourceSystem>TOO</ns3:SourceSystem>
<ns4:SourceKey>TOY1TWXE</ns4:SourceKey>
</ns4:VehicleServiceHistoryHeader>
<ns4:VehicleServiceHistory>
<ns4:VIN>XXXXXXXXXXXXXXXX</ns4:VIN>
<ns4:RepairOrder>
<ns2:RepairOrderDealer>
<DealerNumber>29059</DealerNumber>
</ns2:RepairOrderDealer>
<ns2:RepairOrderNumber>0088745</ns2:RepairOrderNumber>
<ns2:CloseDate>2012-05-30-07:00</ns2:CloseDate>
</ns4:RepairOrder>
</ns4:VehicleServiceHistory>
</ns4:VehicleServiceHistoryDataArea>
</ns4:VehicleServiceHistoryDetails>
</S:Body>
</S:Envelope>
You can see in the request xml in the 2012-05-30-07:00 that extra "-07:00" data is added i just want 2012-05-30.
Thanks
The in context of XML datatypes the XMLGregorianCalendar is created via factory methods in javax.xml.datatype.DatatypeFactory which seems to have a method called newXMLGregorianCalendarDate(int year, int month, int day, int timezone);
So I created a utility method :
public static XMLGregorianCalendar toXMLGregorianCalendarDateOnly(Calendar c){
GregorianCalendar gc = new GregorianCalendar();
gc.setTimeInMillis(c.getTimeInMillis());
XMLGregorianCalendar xc= null;
try {
xc = DatatypeFactory.newInstance().newXMLGregorianCalendarDate(gc.get(Calendar.YEAR),Calendar.MONTH,Calendar.DAY_OF_MONTH,DatatypeConstants.FIELD_UNDEFINED);
} catch (DatatypeConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return xc;
}
The issue is resolved now, we are getting the desired yyyy-MM-ddd.
You can also write it in a following manner which is more readable:
GregorianCalendar gc = new GregorianCalendar();
gc.setTimeInMillis(c.getTimeInMillis());
XMLGregorianCalendar calendar = DatatypeFactory.newInstance().newXMLGregorianCalendar(gc);
calendar.setMillisecond(DatatypeConstants.FIELD_UNDEFINED);
calendar.setTimezone(DatatypeConstants.FIELD_UNDEFINED);
I used the below code to resolve the same problem.
public static XMLGregorianCalendar toXMLGregorianCalendarWithoutTimeStamp(String date) {
Date mDate = null;
GregorianCalendar cal = new GregorianCalendar();
XMLGregorianCalendar xmlGregorianCalendar;
DateFormat df = new SimpleDateFormat("dd-MM-yyyy");
try {
mDate = df.parse(date);
cal.setTime(mDate);
xmlGregorianCalendar = DatatypeFactory.newInstance()
.newXMLGregorianCalendarDate(cal.get(Calendar.YEAR),
cal.get(Calendar.MONTH) + 1,
cal.get(Calendar.DAY_OF_MONTH),
DatatypeConstants.FIELD_UNDEFINED);
return xmlGregorianCalendar;
} catch (DatatypeConfigurationException e) {
LOGGER.error("Error in getCustomerCDRResponse Date Formate Type Configuartion :: " + e);
} catch (ParseException e) {
LOGGER.error("Error in getCustomerCDRResponse Date Parsing :: " + e);
}
return null;
}
try this.
Date dob=null;
DateFormat df=new SimpleDateFormat("dd/MM/yyyy");
dob=df.parse( "10/02/2014 11:15:00" );
GregorianCalendar cal = new GregorianCalendar();
cal.setTime(dob);
XMLGregorianCalendar xmlDate3 = DatatypeFactory.newInstance().newXMLGregorianCalendarDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH)+1, cal.get(Calendar.DAY_OF_MONTH),DatatypeConstants.FIELD_UNDEFINED);
System.out.println(xmlDate3);
If you are using javax.xml.bind.Marshaller to prepare SOAP body then the root of the unwanted bahavior is in yours xlmns:ns2. The field ns2:CloseDate is of type (or some other type wichich include date and time):
{http://www.w3.org/2001/XMLSchema}dateTime
change it to (or other date type without hour and minute):
{http://www.w3.org/2001/XMLSchema}date
If you don't manage this xlmns, just accept that yours CloseDate must have time defined. Without it called web service would have unapropiate time declaration (I don't know exactly value, but I'm bet on 0:00)

Categories