我正在管理将其系统时钟报告为自午夜01-01-1900的秒数的设备。
我需要将其转换为时间戳。
到目前为止,我正在执行以下操作:
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
在本地PC(意大利,Windows 7)上运行此程序时,我得到以下信息:
java -cp . TestTime 3752388800
1900-01-01 00:00:00
3752388800 corresponds to 2018-11-28 10:13:20
这是完全正确的。
在Linux机器(仍在意大利)上运行时,得到的结果相同。
但是,在巴西的Linux机器上运行相同的程序,却得到了不同的结果:
java -cp . TestTime 3752388800
1900-01-01 00:00:00
3752388800 corresponds to 2018-11-28 11:19:48
无论我在命令行中传递什么值,区别始终是01:06:28。
知道这种差异来自何处吗?
顺便说一句,我不在乎时区。我只需要一个时间戳
更新1:
使用Java 6(这是我们在巴西的生产环境中使用的实际版本)时,也会发生同样的事情。
因此,问题不取决于Java版本
更新2:
输入低于441763200(对应于01-01-1914 00:00:00)的秒数时,不会发生此问题。
问题仍然是为什么我们对巴西有所作为?
答案 0 :(得分:4)
一种解决方案是确保您使用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);
输出(独立于JVM时区):
2018-11-28T10:13:20Z
输出中的结尾Z
表示UTC。在将JVM的默认时区设置为America / Sao_Paulo时,我进行了测试,这没有什么区别。如果需要,可以根据自己的喜好设置日期和时间,例如:
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
巴西有多个时区。我以圣保罗为例,并很轻松地复制了您的输出。 1900年世纪之交,圣保罗与格林尼治标准时间-03:06:28偏移。您的Calendar
使用JVM的默认时区,因此您确实将其一天中的时间设置为格林尼治标准时间03:06:28,这可以解释两者之间的区别。
也就是说,您使用的日期时间类(SimpleDateFormat
和Calendar
)存在设计问题,幸运的是,现代的Java日期和时间API java.time已替换为Java。近5年前的8年。现代API的一个特点是,我们自然而然地将时区明确化了,这使得避免像您这样的问题变得更容易,而且如果我们遇到这些问题,也可以更轻松地解决它们。
是的,java.time在Java 6上运行良好。已经被反向移植。
org.threeten.bp
导入日期和时间类。java.time
。java.time
。java.time
向Java 6和7(JSR-310的ThreeTen)的反向端口。答案 1 :(得分:3)
1914年1月1日,巴西更改了时间,从LMT到BRT的时间增加了6分28秒(参见Time Changes in São Paulo Over the Years, 1900-1924)。
另外一小时的差异可能是巴西跨越3个时区(UTC-4
,UTC-3
,UTC-2
),而您并未在代码中设置时区,具体取决于在JVM系统时区上。
答案 2 :(得分:3)
看看这个站点:https://www.timeanddate.com/time/zone/brazil/sao-paulo并导航到1900-1924的时区更改。在此,您可以看到在01-01-1914之前与UTC的偏移量为-03:06:28。这与Why is subtracting these two times (in 1927) giving a strange result?
中的原因完全相同