PROBLEM SOLVED External device was computing and sending non-standard 2 hours shifted timestamp, which hugely confused me and started this thread. TIMESTAMP BY ITSELF IS NOT AFFECTED BY TIMEZONES , timezones apply only when converting in/from human readable forms.
I have timestamp (seconds from unix epoch) in UTC timezone - no DST (daylight saving time).
I want timestamp (seconds from unix epoch) in "Europe/Prague" timezone, that uses DST.
I used to think that unix timestamp is unbound by timezones, that timezones affect only process of converting timestamp to human readable formats. But it doesn't look like that. And the more I am trying to convert it (using Calendar and TimeZone classes), the more confused and lost I am getting.
this code DOES NOT work as expected:
Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone("UTC"));
cal.setTimeInMillis(ts*1000);
cal.setTimeZone(TimeZone.getTimeZone("Europe/Prague"));
return cal.getTimeInMillis()/1000;
There is not a way to "convert" a timestamp, it is always the number of milliseconds from the epoch.
You can use a DateFormat to format the timestamp into a format with a time zone applied, or use a Calendar to look at the hours, minutes, and seconds with a time zone applied.
getTimeInMillis() gets the timestamp back just the same as you put it in, the number of milliseconds from the epoch:
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Calendar.html#getTimeInMillis%28%29
Here is a sample code to convert epoch between timezones.
public static long convertTimeZone(long lngDate, String fromTimeZone,
String toTimeZone) {
Calendar fromTime = Calendar.getInstance();
fromTime.setTimeZone(TimeZone.getTimeZone(fromTimeZone));
fromTime.setTimeInMillis(lngDate);
Calendar toTime = new GregorianCalendar(
TimeZone.getTimeZone(toTimeZone));
toTime.set(Calendar.DATE, fromTime.get(Calendar.DATE));
toTime.set(Calendar.MONTH, fromTime.get(Calendar.MONTH));
toTime.set(Calendar.YEAR, fromTime.get(Calendar.YEAR));
toTime.set(Calendar.HOUR_OF_DAY, fromTime.get(Calendar.HOUR_OF_DAY));
toTime.set(Calendar.MINUTE, fromTime.get(Calendar.MINUTE));
toTime.set(Calendar.SECOND, fromTime.get(Calendar.SECOND));
toTime.set(Calendar.MILLISECOND, fromTime.get(Calendar.MILLISECOND));
LOG.debug("Converted " + fromTime.getTimeInMillis() + " to "
+ toTime.getTimeInMillis());
SimpleDateFormat sdf = new SimpleDateFormat(
"dd-MMM-yyyy HH:mm:ss.SSS z");
sdf.setTimeZone(TimeZone.getTimeZone(fromTimeZone));
SimpleDateFormat sdf1 = new SimpleDateFormat(
"dd-MMM-yyyy HH:mm:ss.SSS z");
sdf1.setTimeZone(TimeZone.getTimeZone(toTimeZone));
LOG.debug("Converted " + sdf.format(fromTime.getTime()) + " to " + sdf1.format(toTime.getTime()));
return toTime.getTimeInMillis();
}
Output:
System.out.println(convertTimeZone(new Date().getTime(),"America/New_York","Asia/Singapore"));
Converted 1384514879944 to 1384468079944
Converted 15-Nov-2013 06:27:59.944 EST to 15-Nov-2013 06:27:59.944 SGT
You can easily convert between two timezone like this:
1.Suppose this is a date and time in the EST timezone
String value = "2006-11-28 09:45:12";
DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
df1.setTimeZone(TimeZone.getTimeZone("EST"));
2.Parses the value and assumes it represents a date and time in the EST timezone
Date d = df1.parse(value);
DateFormat df2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
df2.setTimeZone(TimeZone.getTimeZone("CET"));
3.Formats the date in the CET timezone
System.out.println(df2.format(d));
It behaves as I would expect
public static void main(String... ignored) {
long ts = System.currentTimeMillis() / 1000;
Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone("UTC"));
printCalendar(cal);
cal.setTimeInMillis(ts * 1000);
printCalendar(cal);
cal.setTimeZone(TimeZone.getTimeZone("Europe/Prague"));
printCalendar(cal);
}
public static void printCalendar(Calendar calendar) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS ZZZ");
sdf.setTimeZone(calendar.getTimeZone());
System.out.println(sdf.format(calendar.getTime()));
}
prints
2013/04/22 13:28:06.451 +0000
2013/04/22 13:28:06.000 +0000
2013/04/22 15:28:06.000 +0200