Java时间:从1970年1月1日凌晨1点开始计算?

5
我错过了什么? Date() 是自 1970 年 1 月 1 日午夜以来经过的毫秒数。难道午夜不应该从零点开始吗? 参考资料: 我的测试程序:
package be.test.package.time;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

public class TimeWork {

    public static void main(String[] args) {    

        List<Long> longs = new ArrayList<>();
        List<String> strings = new ArrayList<>();

        DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss.SSS");

        //Now
        Date now = new Date();
        strings.add(formatter.format(now));

        //Test dates
        strings.add("01-01-1970 00:00:00.000");
        strings.add("01-01-1970 01:00:00.000");
        strings.add("31-11-1969 00:00:00.000");
        strings.add("01-01-2014 00:00:00.000");

        //Test data
        longs.add(-1L);
        longs.add(0L);
        longs.add(1L);
        longs.add(7260000L);
        longs.add(1417706084037L);
        longs.add(-7260000L);

        //Show the long value of the date
        for (String string: strings) {
            try {
                Date date = formatter.parse(string);
                System.out.println("Formated date : " + string + " = Long = " + date.getTime());
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }

        //Show the date behind the long
        for (Long lo : longs) {
            Date date = new Date(lo);
            String string = formatter.format(date);
            System.out.println("Formated date : " + string + " = Long = " + lo);        
        }
    }
}

这是结果:

Formated date : 05-12-2014 08:54:59.318 = Long = 1417766099318
Formated date : 01-01-1970 00:00:00.000 = Long = -3600000
Formated date : 01-01-1970 01:00:00.000 = Long = 0
Formated date : 31-11-1969 00:00:00.000 = Long = -2682000000
Formated date : 01-01-2014 00:00:00.000 = Long = 1388530800000
Formated date : 01-01-1970 12:59:59.999 = Long = -1
Formated date : 01-01-1970 01:00:00.000 = Long = 0
Formated date : 01-01-1970 01:00:00.001 = Long = 1
Formated date : 01-01-1970 03:01:00.000 = Long = 7260000
Formated date : 04-12-2014 04:14:44.037 = Long = 1417706084037
Formated date : 31-12-1969 10:59:00.000 = Long = -7260000

为什么会是这样:
Formated date : 01-01-1970 01:00:00.000 = Long = 0

这是在凌晨1点。我原以为是0点。


9
我的时区是什么? - Florent Bayle
1
我的时区是CET - 比利时布鲁塞尔时间。 - Dimitri Dewaele
2
你超前了自己的时代 :-) - David Brossard
3个回答

10

1970年1月1日UTC协调世界时午夜。你需要像 TimeZone 这样的时区。

public static void main(String[] args) {
    TimeZone tz = TimeZone.getTimeZone("UTC");
    Calendar cal = Calendar.getInstance(tz);
    cal.setTimeInMillis(0);
    DateFormat sdf = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss.SSS");
    sdf.setTimeZone(tz);
    System.out.println(sdf.format(cal.getTime()));
}

输出为

01-01-1970 12:00:00.000

当我在Calendar实例中没有设置时区时,我得到了相同的结果。但这是否意味着DateFormat依赖于时区? - GameDroids
@GameDroids 请记住,Calendar是一个高级结构,它基于自1970年1月1日12:00.000以来的毫秒数。是的,DateFormat包括您可能需要知道您所在地的时间,当我这里是下午3点时。 - Elliott Frisch
1
谢谢解释!我检查了日历字符串,它被设置为 HOUR_OF_DAY=1,所以 DateFormat 必须将其转换回 UTC 时间。 - GameDroids

3
另外两个答案是正确的。

java.time

顺便提一下,使用Joda-Time库或java.time(受Joda-Time启发)更容易处理这种日期时间工作。这两个库都有日期时间类,其具有明确指定的时区(不像java.util.Date/.Calendar)。

Joda-Timejava.time都使用相同的纪元1970-01-01T00:00:00Z

在生成其日期时间值的文本表示时,两者都使用ISO 8601标准格式。

Joda-Time

在Joda-Time 2.7中。

DateTime epoch = new DateTime( 0 , DateTimeZone.UTC );

java.time

在Java 8 Update 45的java.time中。

OffsetDateTime

OffsetDateTime类表示一个时刻,通过与UTC的偏移量来确定小时-分钟-秒数。

OffsetDateTime epoch = OffsetDateTime.ofInstant( Instant.EPOCH , ZoneOffset.UTC ) ;

1970年01月01日00:00Z

Instant

更简单的方法是使用常量 Instant.EPOCH

System.out.println( Instant.EPOCH.toString() ) ;

1970年1月1日00:00:00 Z

ZonedDateTime

为了通过某个特定地区的偏移量(时区)查看同一时刻,请应用ZoneId以获取ZonedDateTime

ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = Instant.EPOCH.atZone( z ) ;  // Returns a `ZonedDateTime` object. 
System.out.println( zdt.toString() ) ;

我们可以看到,在时代参考日期时间的那一刻,美洲人仍处于前一年,1969年与1970年不同。相同的时刻,时间轴上的同一点,不同的挂钟时间。

1969-12-31T19:00-05:00[美国/蒙特利尔]

请查看此 java.time 代码 在IdeOne.com上进行实时运行

Table of date-time types in Java, both modern and legacy


关于 java.time

java.time 框架内置于 Java 8 及更高版本。这些类取代了旧的 遗留 日期时间类,如 java.util.DateCalendarSimpleDateFormat 等。

了解更多,请查看Oracle教程。在Stack Overflow上搜索许多示例和解释。规范是JSR 310

Joda-Time项目现在处于维护模式,建议迁移到java.time类。

您可以直接使用与您的数据库兼容的JDBC 4.2或更高版本的JDBC驱动程序,直接交换java.time对象。无需使用字符串,也不需要java.sql.*类。Hibernate 5和JPA 2.2支持java.time

在哪里获取java.time类?


3
长整数0所代表的时间是UTC时区的1970年1月1日午夜。这恰好是CET时区的1970年1月1日凌晨1点。但是,如果您使用的是时区设置为CET的SimpleDateFormat,则:
  • 格式化日期时显示的时间是1970年1月1日凌晨1点;
  • 解析1970年1月1日凌晨1点会给出长整数0所代表的时间。
如果您有一个时区设置为UTC的SimpleDateFormat,则行为完全不同。
如果您想使用除CET以外的时区,则可以使用DateFormat的setTimeZone方法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接