I'm looking for a Java 6 compatible way of generating Seconds since epoch in GMT / UTC (aka UNIX Timestamp) out of a java.sql.Date
Object.
My Java 8 code is:
Long seconds = dateObject.toLocalDate().atStartOfDay(ZoneId.of("GMT")).toEpochSecond()
My Java 6 code is:
final Calendar cal = Calendar.getInstance();
cal.setTime(dateObject);
final int year = cal.get(Calendar.YEAR);
final int month = cal.get(Calendar.MONTH);
final int day = cal.get(Calendar.DAY_OF_MONTH);
final GregorianCalendar c = new GregorianCalendar();
c.clear();
c.setGregorianChange(new Date(Long.MIN_VALUE));
c.setTimeZone(TimeZone.getTimeZone("GMT"));
c.set(Calendar.YEAR, year);
c.set(Calendar.MONTH, month);
c.set(Calendar.DAY_OF_MONTH, day);
Long seconds = c.getTimeInMillis() / 1000
Unfortunally, the Java 6 code is around as half as fast as the Java 8 code. I had a Java 6 solution with less code in the past (and therefor faster) but it was wrong when it came to unusual dates as "0001-01-01" where setGregorianChange()
is needed and a second GergorianCalendar
came in.
Any idea what I could do to get a fast Java 6 implementation?
- I need Thread safety
- "2010-01-01" must result in 1262304000
- "0001-01-01" must result in -62135596800
- "2999-12-31" must result in 32503593600
EDIT 1
I also tried the following Java 6 code:
final TimeZone tz = TimeZone.getDefault();
Long seconds = (dateObject.getTime() + tz.getRawOffset()) / 1000;
This works with "2010-01-01" and "2999-12-31" but not with "0001-01-01" (expected: -62135596800, actual: -62135769600) - guess the missing "setGregorianChange" is what troubles here.
EDIT 2
The code is running in a JsonSerializer. I have an application presenting those UNIX timestamps inside a JSON. The consuming side expects the timestamps as GMT Timestamps and will create a date by this timestamps hardcoding the timezone to GMT but use it later as it where local timezone.
To make the problem more clear, I'll present an example.
- Date on my side: 2010-01-01 (UTC+100)
- milliSeconds: 1262300400000
- seconds: 1262300400
the consumer now takes this seconds and forms a date out of it:
- Thu, 31 Dec 2009 23:00:00 GMT
Of course - this is 100% correct, but the consumer does use this date as if it where a local timezone date...
The seconds I expect to be transfered are 1262300400 + 3600 (my TZ Offset) for this example.
EDIT 3
I got the GregorianCalendar
-thing down to a 4liner - but even this is much slower than the Java 8 thing. The problem is the creation of a new GregorianCalendar
Object each time the code is executed. But this is a must-do since Calendar
not threadsafe.
So a fast solution must somehow work without any object-instantiation.
The example below is mostly like EDIT 1 and is even faster than the Java 8 code. It just does not work correctly with dates before the Julian -> Gregorian switch (15-Oct-1582).
public class UnixTimestampSerializer extends JsonSerializer<Date> {
@Override
public void serialize(final Date dateObject, final JsonGenerator jgen, final SerializerProvider provider)
throws IOException, JsonProcessingException {
jgen.writeNumber((dateObject.getTime() - dateObject.getTimezoneOffset() * 60 * 1000) / 1000)
}
}
Unfortunally it works a) with a deprecated method and b) does not work correctly with dates before 1582 :(. Using a static TimeZone.getDefault().getRawOffset()
to solve a) is not an option, as the TimeZone may change (summer- vs. wintertime) on each date.