I'm managing devices that report their system clock as seconds since midnight 01-01-1900.
I need to convert this into a timestamp.
So far, I'm doing this as follows:
import java.text.SimpleDateFormat;
import java.util.Calendar;
public class TestTime
{
// Pass seconds since 01-01-1900 00:00:00 on the command line
public static void main(String[] args)
{
// ---------------------
// Create time formatter
// ---------------------
SimpleDateFormat format;
format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// ---------------------------
// Compose 01-01-1900 00:00:00
// ---------------------------
Calendar cal;
cal = Calendar.getInstance();
cal.set(Calendar.YEAR, 1900);
cal.set(Calendar.MONTH, Calendar.JANUARY);
cal.set(Calendar.DAY_OF_MONTH, 1);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
// -------------------
// Show what we've got
// -------------------
System.out.println(format.format(cal.getTime()));
// ---------------------------------------------
// Add the seconds as passed on the command line
// ---------------------------------------------
long secs = Long.parseLong(args[0]);
while (secs > Integer.MAX_VALUE)
{
cal.add(Calendar.SECOND, Integer.MAX_VALUE);
secs -= Integer.MAX_VALUE;
}
cal.add(Calendar.SECOND, (int)secs);
// -------------------
// Show what we've got
// -------------------
System.out.println(args[0] + " corresponds to " + format.format(cal.getTime()));
} // main
} // class TestTime
When running this on my local PC (Italy, Windows 7), I get the following:
java -cp . TestTime 3752388800
1900-01-01 00:00:00
3752388800 corresponds to 2018-11-28 10:13:20
This is perfectly correct.
I get the same results when running this on a Linux machine (still in Italy).
However, running the very same program on a Linux machine in Brazil, I get different results:
java -cp . TestTime 3752388800
1900-01-01 00:00:00
3752388800 corresponds to 2018-11-28 11:19:48
Whatever value I pass on the commandline, the difference is always 01:06:28.
Any idea where this difference is coming from?
BTW, I'm not concerned about the timezone. I just need a timestamp
Update 1:
The very same thing happens also when using Java 6 (which is the actual version used within our production environment in Brazil).
So, the problem does not depend on the java version
Update 2:
The problem does not occur when entering a number of seconds below 441763200 (which corresponds to 01-01-1914 00:00:00)
The question remains why we get a difference for Brazil?
A solution is to make sure you do your conversion in UTC:
Instant base = LocalDate.of(1900, Month.JANUARY, 1)
.atStartOfDay(ZoneOffset.UTC)
.toInstant();
String secsSince1900String = "3752388800";
long secsSince1900 = Long.parseLong(secsSince1900String);
Instant target = base.plusSeconds(secsSince1900);
System.out.println(target);
Output (independent of JVM time zone):
2018-11-28T10:13:20Z
The trailing Z
in the output means UTC. I have tested while setting my JVM’s default time zone to America/Sao_Paulo, it made no difference. If you want, you can formate the date and time to your liking, for example:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formattedDateTime = target.atOffset(ZoneOffset.UTC).format(formatter);
System.out.println(formattedDateTime);
2018-11-28 10:13:20
There are a number of time zones across Brazil. I took São Paulo as an example and reproduced your output readily. At the turn of the century in 1900, São Paulo was at offset -03:06:28 from GMT. Your Calendar
uses the JVM’s default time zone, so you really set its time of day to 03:06:28 GMT, which explains the difference.
That said, the date-time classes you were using — SimpleDateFormat
and Calendar
— have design problems and have fortunately been replaced by java.time, the modern Java date and time API, with Java 8 nearly 5 years ago. One trait of the modern API is we more naturally make time zone explicit, which makes it easier to avoid issues like yours, and also to fix them if we run into them anyway.
Yes, java.time works nicely on Java 6. It has been backported.
org.threeten.bp
with subpackages.java.time
.java.time
was first described.java.time
to Java 6 and 7 (ThreeTen for JSR-310).If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With