Java convert data/time between timezone is inaccurate - java

TimeZone.setDefault(TimeZone.getTimeZone("Europe/Moscow"));
System.out.println("Default Timezone: " + TimeZone.getDefault());
String date = "08/04/2016 00:00:00";
SimpleDateFormat simpleDateFormatMoscow = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
Date moscowDt = simpleDateFormatMoscow.parse(date);
System.out.println("Moscow Date: " + simpleDateFormatMoscow.format(moscowDt));
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("Asia/Bangkok"));
System.out.println("Bangkok Date: " + simpleDateFormat.format(moscowDt));
Calendar calendar = new GregorianCalendar();
calendar.setTime(moscowDt);
calendar.setTimeZone(TimeZone.getTimeZone("Asia/Bangkok"));
System.out.println("Bangkok Date: " + simpleDateFormat.format(calendar.getTime()));
System.out.println("Test Timezone");
System.out.println(TimeZone.getTimeZone("America/New_York"));
System.out.println(TimeZone.getTimeZone("Europe/Moscow"));
System.out.println(TimeZone.getTimeZone("Asia/Bangkok"));
I tried to use the code this snippet to convert date/time between Moscow and Bangkok. The result is as followed:
Default Timezone:
sun.util.calendar.ZoneInfo[id="Europe/Moscow",offset=14400000,dstSavings=0,useDaylight=false,transitions=78,lastRule=null]
Moscow Date: 08/04/2016 00:00:00
//util date/time
Bangkok Date: 08/04/2016 03:00:00
//joda time
Bangkok Date: 08/04/2016 03:00:00
However, when I convert date/time using https://singztechmusings.wordpress.com/2011/06/23/java-timezone-correctionconversion-with-daylight-savings-time-settings/ or google the time is
Moscow Date: 08/04/2016 00:00:00
Bangkok Date: 08/04/2016 04:00:00
Could anyone please tell me the correct way to convert data/time using java?
And Could anyone please tell me what I did wrong and why the result is inaccurate?

Your Java have wrong timezone offset: "offset=14400000" is 4 hours, but Moscow is UTC+3 for last year and a half.
Upgrade your java with tzupdater.

Java is using its own timezone data which is independenct from the host operation system. It might be inaccurate if you are not using the latest version of Java cause Russia (Europe/Moscow) has switched from daylight saving time to permanent standard time two years ago

This is one way to do it using your local time zone first.
public static void main(String[] args) {
// Create a calendar object and set it time based on the local time zone
Calendar localTime = Calendar.getInstance();
localTime.set(Calendar.HOUR, 17);
localTime.set(Calendar.MINUTE, 15);
localTime.set(Calendar.SECOND, 20);
int hour = localTime.get(Calendar.HOUR);
int minute = localTime.get(Calendar.MINUTE);
int second = localTime.get(Calendar.SECOND);
// Print the local time
System.out.printf("Local time : %02d:%02d:%02d\n", hour, minute, second);
// Create a calendar object for representing a Bangkok time zone. Then we set
//the time of the calendar with the value of the local time
Calendar BangkokTime = new GregorianCalendar(TimeZone.getTimeZone("Asia/Bangkok"));
BangkokTime.setTimeInMillis(localTime.getTimeInMillis());
hour = BangkokTime.get(Calendar.HOUR);
minute = BangkokTime.get(Calendar.MINUTE);
second = BangkokTime.get(Calendar.SECOND);
// Print the local time in Bangkok time zone
System.out.printf("Bangkok time: %02d:%02d:%02d\n", hour, minute, second);
//Then do the same for the Moscow time zone
Calendar MoscowTime = new GregorianCalendar(TimeZone.getTimeZone("Europe/Moscow"));
MoscowTime.setTimeInMillis(localTime.getTimeInMillis());
hour = MoscowTime.get(Calendar.HOUR);
minute = MoscowTime.get(Calendar.MINUTE);
second = MoscowTime.get(Calendar.SECOND);
// Print the local time in Moscow time zone
System.out.printf("Moscow time: %02d:%02d:%02d\n", hour, minute, second);
}

Related

TimeZone offset shows invalid value

Unless I do something wrong...
I live in Poland (GMT+2). By the time I write this we are in daylight saving time. The following code, however, says that the GMT time offset is only 1 hour instead of 2.
Calendar mCalendar = new GregorianCalendar();
TimeZone mTimeZone = mCalendar.getTimeZone();
System.out.println(mTimeZone);
int mGMTOffset = mTimeZone.getRawOffset();
System.out.printf("GMT offset is %s hours", TimeUnit.HOURS.convert(mGMTOffset, TimeUnit.MILLISECONDS));
prints GMT offset is 1 hours
Same happens for other timezones, for example New York, which is GMT-4:
Calendar mCalendar = new GregorianCalendar(TimeZone.getTimeZone("America/New_York"));
prints GMT offset is -5 hours
There are two methods the TimeZone you have to use:
you can check if the a date is in DaylightSaveTime with:
mTimeZone.inDaylightTime(date)
And if this is True you have to add the value of
mTimeZone.getDSTSavings()
to the Offset:
Calendar mCalendar = new GregorianCalendar();
TimeZone mTimeZone = mCalendar.getTimeZone();
System.out.println("TimeZone: "+mTimeZone);
int mGMTOffset = mTimeZone.getRawOffset();
if (mTimeZone.inDaylightTime(mCalendar.getTime())){
mGMTOffset += mTimeZone.getDSTSavings();
}
System.out.printf("GMT offset is %s hours",
TimeUnit.HOURS.convert(mGMTOffset, TimeUnit.MILLISECONDS));
output:
GMT offset is 2 hours
Check whether DST is active in java .
TimeZone tz = TimeZone.getTimeZone("America/New_York");
boolean inDs = tz.inDaylightTime(new Date());
Below code give you with DST time
TimeZone zone = TimeZone.getTimeZone("America/New_York");
DateFormat format = DateFormat.getDateTimeInstance();
format.setTimeZone(zone);
System.out.println(format.format(new Date()));

Covert date time from one zone to another

This is continuation to one of my previous question where I am not able to parse the date which is resolved now. In the below code, I have a date string and I know the time zone for the date string even though the string itself doesn't contain it. Then I need to convert the date into EST time zone.
String clientTimeZone = "CST6CDT";
String value = "Dec 29 2014 11:36PM";
value=StringUtils.replace(value, " ", " ");
DateTimeFormatter df = DateTimeFormat.forPattern("MMM dd yyyy hh:mma").withZone(DateTimeZone.forID(clientTimeZone));
DateTime temp = df.parseDateTime(value);
System.out.println(temp.getZone().getID());
Timestamp ts1 = new Timestamp(temp.getMillis());
DateTime date = temp.withZoneRetainFields(DateTimeZone.forID("EST"));//withZone(DateTimeZone.forID("EST"));
Timestamp ts = new Timestamp(date.getMillis());
System.out.println(ts1+"="+ts);
When I am running the code I am expecting ts1 to remain same and ts to be up by 1 hr. But iam getting below which I don't understand. I thought EST is one hour ahead of CST and so if it is 11 in CST, it should be 12 in EST. Also there seems to be offset by about eleven and half hours. Any clues on what I am missing.
2014-12-30 11:06:00.0=2014-12-30 10:06:00.0
I think the below code will help you.
String clientTimeZone = "CST6CDT";
String toStimeZone = "EST";
String value = "Dec 29 2014 11:36PM";
TimeZone fromTimeZone = TimeZone.getTimeZone(clientTimeZone);
TimeZone toTimeZone = TimeZone.getTimeZone(toStimeZone);
Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(fromTimeZone);
SimpleDateFormat sf = new SimpleDateFormat("MMM dd yyyy KK:mma");
Date date = sf.parse(value);
calendar.setTime(date);
System.out.println(date);
calendar.add(Calendar.MILLISECOND, fromTimeZone.getRawOffset() * -1);
if (fromTimeZone.inDaylightTime(calendar.getTime())) {
calendar.add(Calendar.MILLISECOND, calendar.getTimeZone().getDSTSavings() * -1);
}
calendar.add(Calendar.MILLISECOND, toTimeZone.getRawOffset());
if (toTimeZone.inDaylightTime(calendar.getTime())) {
calendar.add(Calendar.MILLISECOND, toTimeZone.getDSTSavings());
}
System.out.println(calendar.getTime());
Copied from : http://singztechmusings.wordpress.com/2011/06/23/java-timezone-correctionconversion-with-daylight-savings-time-settings/
The method withZoneRetainFields() preserves the fields in the timezone CST (= UTC-06) hence your local timestamp (as LocalDateTime) but combines it with a different timezone (EST = UTC-05) which is one hour ahead in offset and result in a different instant. You should it interprete it this way: The same local time happens one hour earlier in New York compared to Chicago.
The rule is to subtract positive offsets and to add negative offsets in order to make timestamp representations of instants comparable (normalizing to UTC offset).
Alternatively: Maybe you don't want this but want to preserve the instant instead of the local fields. In this case you have to use the method withZone().
Side notice: Effectively, you compare the instants represented by the variables temp and date and finally use your default timezone to print these instants in the JDBC-escape-format (explanation - you implicitly use Timestamp.toString()). I would rather recommend to use a dedicated instant formatter for this purpose or simpler (to have the offsets in focus):
System.out.println(temp.toInstant() + " = " + date.toInstant());

Date to string is not correnct

Probably there will be simply and fast answer but I still cant find out why is the result of
Date date = new Date(60000); //one min.
SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
String dateStr = dateFormat.format(date);
dateStr - 01:01:00
Still one hour more. Time zone? How can I set it without it? Thanks.
Date represents a specific moment in time, not a duration. new Date(60000) does not create "one minute". See the docs for that constructor:
Initializes this Date instance using the specified millisecond value. The value is the number of milliseconds since Jan. 1, 1970 GMT.
If you want "one minute from now" you'll probably want to use the Calendar class instead, specifically the add method.
Update:
DateUtils has some useful methods that you might find useful. If you want the elapsed time in HH:mm:ss format, you might try DateUtils.formatElapsedTime. Something like:
String dateStr = DateUtils.formatElapsedTime(60);
Note that the 60 is in seconds.
Three ways to use java.util.Date to specify one minute:
1. Using SimpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC")) as shahtapa said:
Date date = new Date(60*1000); //one min.
SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
String dateStr = dateFormat.format(date);
System.out.println("Result = " + dateStr); //Result should be 00:01:00
2. Using java.util.Calendar as kabuko said:
Calendar calendar = Calendar.getInstance();
calendar.clear();
calendar.set(Calendar.MINUTE,1); //one min.
Date date = calendar.getTime();
SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
String dateStr = dateFormat.format(date);
System.out.println("Result = " + dateStr); //Result should be 00:01:00
Other calendar.set() statements can also be used:
calendar.set(Calendar.MILLISECOND,60*1000); //one min.
calendar.set(1970,0,1,0,1,0); //one min.
3. Using these setTimeZone and Calendar ideas and forcing Calendar to
UTC Time-Zone
as Simon Nickerson said:
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
calendar.clear();
calendar.set(Calendar.MINUTE,1); //one min.
Date date = calendar.getTime();
SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
String dateStr = dateFormat.format(date);
System.out.println("Result = " + dateStr); //Result should be 00:01:00
Note: I had a similar issue: Date 1970-01-01 was in my case -3 600 000 milliseconds (1 hour late) java.util.Date(70,0,1).getTime() -> -3600000
I recommend to use TimeUnit
"A TimeUnit represents time durations at a given unit of granularity and provides utility methods to convert across units, and to perform timing and delay operations in these units. A TimeUnit does not maintain time information, but only helps organize and use time representations that may be maintained separately across various contexts. A nanosecond is defined as one thousandth of a microsecond, a microsecond as one thousandth of a millisecond, a millisecond as one thousandth of a second, a minute as sixty seconds, an hour as sixty minutes, and a day as twenty four hours."
http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/TimeUnit.html
Date date = new Date(); // getting actual date
date = new Date (d.getTime() + TimeUnit.MINUTES.toMillis(1)); // adding one minute to the date

computing time based on TimeZones

my code computes the date and time correctly including the dayLightSaving time,when run on my local server from india. But when I run the same code from US server I am getting the time which is one hour ahead for the timeZoneId which is not abserving DST.
TimeZone tz = TimeZone.getTimeZone("America/Phoenix");
Date currTime = getDateByTZ(new Date(), tz);
System.out.println("currTime" + currTime);
public static Date getDateByTZ(Date d, TimeZone tz) throws Exception {
if (tz == null) {
tz = TimeZone.getDefault();
}
Integer tzOffSet = tz.getRawOffset();
Integer tzDST = tz.getDSTSavings();
Integer defOffSet = TimeZone.getDefault().getRawOffset();
Integer defDST = TimeZone.getDefault().getDSTSavings();
Calendar cal = Calendar.getInstance(tz);
cal.setTime(d);
if (tz.inDaylightTime(d)) {
cal.add(Calendar.MILLISECOND, -defOffSet);
cal.add(Calendar.MILLISECOND, -defDST);
cal.add(Calendar.MILLISECOND, +tzOffSet);
cal.add(Calendar.MILLISECOND, +tzDST);
} else {
cal.add(Calendar.MILLISECOND, -defOffSet);
cal.add(Calendar.MILLISECOND, tzOffSet);
}
return cal.getTime();
}
Results from Localserver:
currTime:Mon Oct 22 01:52:21 IST 2012
Results from USserver:
currTime:Mon Oct 22 02:52:21 IST 2012
This code doesn't make much sense. A Date object doesn't have to be transformed to be used in another time zone. It represents a universal instant.
What makes sense is to use the time zone when displaying (or formatting as a string) a Date object. In this case, you should simply set the time zone on the DateFormat instance, and the universal instant that constitutes a date will be formatted in order to make sense for the given time zone.
Date now = new Date(); // now, whatever the timezone is
DateFormat df = DateFormat.getDateTimeInstance();
df.setTimeZone(TimeZone.getDefault());
System.out.println("Now displayed in the default time zone : " + df.format(now));
df.setTimeZone(TimeZone.getTimeZone("America/New_York"));
System.out.println("Now displayed in the New York time zone : " + df.format(now));

How do I get date & time in a different time zone?

I am using Indigo Service Release 2. I have written following code:
TimeZone calcutta = TimeZone.getTimeZone("Asia/Calcutta");
Date now = new Date();
DateFormat format =
DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL);
format.setTimeZone(calcutta);
jlabel_IndiaTime.setText((format.format(now).toString()));
It is showing Monday, September 17,2012 1:13:23 PM IST, but in India the time is 10:14AM. I am trying this from New York. Could anyone please help me?
Here's some example code. I'm explicitly setting my server's default time zone to NY time, but you may want to follow Jon Lin's hint and determine for certain the default time zone of your own server. For example, if you're in NY, but are using a server hosted in SF and using Pacific time, then that could account for a 3 hour difference from the expected time in any zone.
public void testTodayInIndia() {
// For demonstration, make my system act as though it's in New York
TimeZone.setDefault(TimeZone.getTimeZone("America/New_York"));
long oneDay = 86400000;
long fourYears = (365 * 4 + 1) * oneDay;
// Calculate 42 years after 1/1/1970 UTC
Date now = new Date(fourYears * 10 + oneDay * 365 * 2 + 1);
TimeZone calcutta = TimeZone.getTimeZone("Asia/Kolkata");
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// Since unspecified, this output will show the date and time in New York
assertEquals("2011-12-31 19:00:00", formatter.format(now));
// After setting the formatter's time zone, output reflects the same instant in Calcutta.
formatter.setTimeZone(calcutta);
assertEquals("2012-01-01 05:30:00", formatter.format(now));
}
You can use SimpleDateFormat and Date classes such as below:
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat();
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("America/New_York"));
System.out.println(simpleDateFormat.format(date));
There are different time zones you can replace with "America/New_York" such "Asia/Calcutta".

Categories

Resources