I have a field that is defined as TIMESTAMP WITH TIME ZONE.
The value to be saved starts off as: "09-23-2019 10:03:11 pm" in the zone of US/Hawaii.
This is what I am trying to save to the DB (all of the date information plus the Zone)
The database stores time information in UTC format.
As of now, the date is being stored in the DB so that it looks like this:
DAYS
---------------------------------------------------------------------------
23-SEP-19 10.03.11.000000 PM -05:00
23-SEP-19 10.03.11.000000 PM -05:00
During the processing, it runs through this code:
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;
}
The calendar info that is returned is:
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]
It looks as though US/Hawaii is not being set in the RETURNED VALUE.
What can I do to be sure that this gets set?
After that, I can place it in the DB and see if the setting will "stick" and not revert back to America/Chicago
Update
#Patrick H - thanks for the input. I made the change with the pattern you specified and was able to save the data. It now looks like this:
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]]
The data in the DB looks like this:
23-SEP-19 10.03.11.000000 PM -05:00
The Zone is still America/Chicago even through US/Hawaii was specified. How can one get US/Hawaii to stick and not revert back to America/Chicago?
According to this output:
java.util.GregorianCalendar[time=1569294191000,...
The time value above (which means 1569294191000 milliseconds since unix epoch (1970-01-01T00:00Z)) is equivalent to 09-23-2019 10:03 PM in Chicago. That's because readFormat is using the system's default timezone (which is probably America/Chicago, just check the value of TimeZone.getDefault()).
To parse the input 09-23-2019 10:03:11 pm and consider it as the local time in Hawaii, you just need to set the corresponding timezone to the SimpleDateFormat instance (in this case, to readFormat, as it needs to know in what timezone the input date is - as you didn't set any, it uses the system's default). You also don't need the other formatters (writeFormat and sdf), only one formatter can be used to get the corresponding date:
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");
The date above will be equivalent to 10:03 PM in Hawaii. Actually, the date itself contains just the milliseconds from the unix epoch (date.getTime() returns 1569312191000) and has no format nor any timezone information.
You can then set it to a Calendar instance (don't forget to set the calendar's timezone):
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("US/Hawaii"));
cal.setTime(date);
It's been some time since I used oracle's timestamp with timezone type, but I think that'll be enough to save the correct values. The value of calendar is:
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 new Date/Time API
The old classes (Date, Calendar and SimpleDateFormat) have lots of problems and design issues, and they're being replaced by the new APIs.
One of the main problems is how hard and confusing it is to work with different timezones.
If you're using Java 8, consider using the new java.time API. It's easier, less bugged and less error-prone than the old APIs.
If you're using Java <= 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, there's the ThreeTenABP (more on how to use it here).
The code below works for both.
The only difference is the package names (in Java 8 is java.time and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp), but the classes and methods names are the same.
To parse the input 09-23-2019 10:03:11 pm you can use a DateTimeFormatter and parse it to a LocalDateTime - the input has no timezone information, so we consider only the date and time, and then we can convert it to a timezone.
// 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"));
The most recent JDBC drivers have support to the new API (but only for Java 8, I guess), but if you still need to work with Calendar, you can easily convert a ZonedDateTime to it:
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("US/Hawaii"));
calendar.setTimeInMillis(hawaiiDate.toInstant().toEpochMilli());
In Java 8, you can also do:
Calendar calendar = GregorianCalendar.from(hawaiiDate);
If you need interoperability with the old Calendar and Date API's, you can use the new API internally to do the calculations and convert from/to the API's when needed.
According to SimpleDateFormat, I think your formatting string is wrong. You can also see in the returned value that the month, and day are wrong. MONTH=11,DAY_OF_MONTH=29
This is what you currently have:
23-SEP-19 10.03.11.000000 PM -05:00
I think the formatting string should be: 'dd-MMM-yy hh.mm.ss.SSSSSS a Z'
It also looks like the timezone issue could be because there is a colon inside it. The documentation for SimpleDateFormat indicates it needs to be in this format instead for a RFC 822 time zone: -0500 You may find it easier to use the General time zone component instead.
I need to convert local time at a specific city to UTC.
For example ,
convert time in NYC to UTC .
If I pass the local time and country , the service should be able to return the UTC
Is there any library/utility which maps the city/country to timezone and then converts it to UTC ?
I am trying to avoid building a time zone master and do the conversion .
Since this is common problem, if there are any libraries which are already doing it - please revert back
Just need to use Calendar and TimeZone classes?
Define a TimeZone for UTC:
TimeZone tz = TimeZone.getTimeZone("UTC");
And then create the calendar
Calendar cal = Calendar.getInstance(tz);
To retrieve the Date object use calendar.getTime
cal.getTime()
If you already have your date in a Date object (localDate) you can use a formatter:
SimpleDateFormat formatter = new SimpleDateFormat(); formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
String dateinUTC = formatter.format(localDate)
Server side code (server timezone is UTC):-
Date aDate = new Date();
java.sql.Timestamp aTimestamp = new java.sql.Timestamp(aDate.getTime());
Client side (Mobile app, timezone GMT +5:30):-
Hitting a service request which runs above code on server side
The issue is when i debugged on server, found following values :-
aDate.getTime() prints to -> 1470472883877 milliseconds i.e., Sat Aug 06 2016 14:11:23 GMT+0530
but
aTimestamp prints to -> (java.sql.Timestamp) 2016-08-06 08:41:44.109
It's kinda weird, i've no idea what's going on in conversion !! please help
UTC and GMT are formats.
java.util.Date and java.sql.Timestamp are independent of the timezone. They store a long time in ms for representing their inner state.
For information, Calendar is timezone aware.
So with Date or Timestamp, to differentiate GMT or UTC format in an output, you have to use a formater which outputs the date into string by being aware the timezone.
In your output : 2016-08-06 08:41:44.109, you don't use a formater which is aware of the timezone. It's probably the result of a toString() on the java.sql.Timestamp instance or something of similar.
What you consider as a conversion is not a conversion but a formatting since the timestamp stays the same between the two objects.
If you want to display in the UTC format, use the appropriate formater with a
SimpleDateFormat for example :
SimpleDateFormat dt= new SimpleDateFormat("MM/dd/yyyy hh:mm:ss z");
dt.setTimeZone(TimeZone.getTimeZone("UTC"));
String dateStringInUTC = dt.format(new Date(yourSqlTimestamp.getTime()));
The following is probably what you are looking for:
Calendar cal = Calendar.getInstance(Locale.GERMANY); // use your locale here
Timestamp aTimestamp = new Timestamp(cal.getTimeInMillis());
System.out.println(aTimestamp);
System.out.println(cal.getTime());
And the output:
2016-08-06 19:12:54.613
Sat Aug 06 19:12:54 CEST 2016
Okay, so here's my issue in Android right now. On our Database there's a timestamp in this format 8/15/2013 2:00:48 PM and through a .NET WebService I get that same time like this in Android: 2013-08-15T14:00:48-07:00. Now I want to convert this format into a Date Time format that I can use for comparison (for example this webservice provides every instance where a device failed at logging in so we want to check the amount of time between occurances to see if there's any issues). Below I have this code where I'm trying to use JODA Time but it's still not returning the correct format:
public static Date convertStringToDate(String input) {
String pattern = "yyyy-MM-dd'T'HH:mm:ssZ";
DateTimeFormatter formatter = DateTimeFormat.forPattern(pattern);
DateTime dateTime = formatter.parseDateTime(input);
return dateTime.toDate();
//printout shows: Thu Aug 15 17:00:48 EDT 2013
}
I know that the server is returning some crappy time format that is hard to work with (it took a while to get this to work in the iOS App we have, and even there it's still rather clunky) so I don't mind changing the webservice or the query if that would make things easier.
I have a very similar format, and I parse it using SimpleDateFormat, try this:
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZZZ", Locale.US);
Date dateTime = format .parse(value);
What i understand is that you have your correct instance of date already and what you need is to parse it to String.
I suggest you use:
DateFormat formatter = new SimpleDateFormat("d/MM/yyyy hh:mm:ss a");
//this will give you the format '8/15/2013 2:00:48 PM'
String d = formatter.format(date);
Hope this helps.
EDIT:
Also seams you want to have your date instance in -07:00 timezone
So you can change your line
DateTime dateTime = formatter.parseDateTime(input);
for
DateTime dateTime = formatter.withZone(DateTimeZone.forID("-07:00")).parseDateTime(input);
I ran into a strange issue. Here is a snippet of code that describes it:
DateTimeZone dtz = DateTimeZone.forOffsetHours(0);
DateTime dt = new DateTime(dtz);
System.out.println(dt);
System.out.println(dt.toDate());
the output is:
2012-02-29T17:24:39.055Z
Wed Feb 29 19:24:39 EET 2012
I'm located UTC+2, but this action is supposed to create a java.util.Date object which is initialized for UTC time. What am I missing?
Date doesn't know about a time zone at all - it only represents an instant in time (like Joda Time's Instant type). It's just a number of milliseconds since the Unix epoch. When you call Date.toString(), it always uses the system local time zone for converting that into a readable text form.
So there's nothing wrong here - just an expectations failure over either the meaning of java.util.Date or its toString() behaviour, or both.
(As an aside, prefer DateTimeZone.UTC over creating your own.)
To get a JDK Date that matches Joda's DateTimeconvert to LocalDateTimefirst.
As explained in the other answers, the time in milliseconds does not change depending on the timezone:
DateTime local = DateTime.now()
Date localJDK = local.toDate()
assert localJDK.getTime() == local.toInstant().getMillis()
DateTime differentTimeZone = DateTime.now(DateTimeZone.forID('America/Chicago'))
Date localJDK2 = differentTimeZone.toDate()
assert differentTimeZone.toInstant().getMillis() == localJDK2.getTime()
assert localJDK.getTime() == localJDK2.getTime()
Converting a LocalDateTime to Date will change that:
Date differentTimeZoneJDK = differentTimeZone.toLocalDateTime().toDate()
assert localJDK.getTime() != differentTimeZoneJDK.getTime()
The behaviour you want is this:
Date jdkDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dt.toString("yyyy-MM-dd HH:mm:ss"));
Like Jon noted, JDK date is time zone agnostic. Hope this helps someone.