Epoch is not epoch if do a new Date(0L). Why?

2019-02-23 17:05发布

问题:

My problem is pretty straigtforward explained :

if I do this :

public class Main {

public static void main(String[] args) throws Exception {
        Date d = new Date(0L );
        System.out.println(d);
}

}

I get the following output : Thu Jan 01 01:00:00 CET 1970

According to the doc, I was expecting : Thu Jan 01 00:00:00 CET 1970

I would like was going wrong...

EDIT : Indeed, I read the doc too fast. I should have Thu Jan 01 00:00:00 GMT 1970

So, how can I force the use of GMT, and ignore all local time ?

Edit, Solution :

public static void main(String[] args) throws Exception {
    SimpleDateFormat sdf = new SimpleDateFormat("H:m:s:S");
SimpleTimeZone tz = new SimpleTimeZone(0,"ID");
sdf.setTimeZone(tz) ;
Date d = new Date(0L );
System.out.println( sdf.format(d));
}

回答1:

The Epoch is defined as 00:00:00 on 1970-1-1 UTC. Since CET is UTC+1, it's equal to 1AM your time.

If you look at the Date(long) constructor, you'll see that it expects the value to be the number of milliseconds since the epoch, UTC:

Allocates a Date object and initializes it to represent the specified number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT.

Regarding your desire to force GMT instead of your local time zone: In short, the Date instance always uses GMT. If you just want to format the output String so that it uses GMT have a the DateFormat class, and specifically, its setTimeZone() method.



回答2:

This might be related to your locale settings. Assuming you're French and not French-Canadian, it would seem as if your timestamp is being treated as timestamp without timezone, and the Date constructor attempts to correct for this, adding an hour to the date.

If this is undocumented behavior or not, I cannot tell you.

Edit: Read error: CET != UTC :/

So yeah, Locale time zone.

Reedit: For utter and absolute clarity.

Output: Thu Jan 01 01:00:00 CET 1970

Your expected output: Thu Jan 01 00:00:00 CET 1970

Actual expected output: Thu Jan 01 00:00:00 GMT 1970 ( ≡ Thu Jan 01 01:00:00 CET 1970)



回答3:

tl:dr

Instant.EPOCH
       .toString()

1970-01-01T00:00:00Z

Date::toString lies

You've learned one of the many reasons to avoid using the java.util.Date/Calendar classes: a Date instance has no time zone information, yet it's toString method uses your default time zone when rendering a string for display. Confusing because it implies the Date has a time zone when in fact it does not.

Avoid Date/Calendar

Instead of Date/Calendar, you should be using Joda-Time or the new Java 8 classes, java.time.* from JSR 310.

java.time

Use the Instant class as the equivalent of Date, a moment on the timeline in UTC.

Instant.now()

For the epoch reference date, use the constant.

Instant.EPOCH.toString()

1970-01-01T00:00:00Z

If by "ignore all time" you mean that you really want a date-only value without time-of-day, use the LocalDate class.

LocalDate.ofEpochDay( 0L )

1970-01-01

Joda-Time Example

Update: The Joda-Time project is now in maintenance mode with the team advising migration to the java.time classes.

In Joda-Time, a DateTime instance does indeed know its own time zone. You can use a formatter to create string outputs in other time zones, if desired.

Here's your code aiming at the Unix time Epoch, but using Joda-Time 2.3.

// © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.
// import org.joda.time.*;
// import org.joda.time.format.*;

DateTimeZone timeZone_Paris = DateTimeZone.forID( "Europe/Paris" );

DateTime epochParis = new DateTime( 0L, timeZone_Paris );
DateTime epochUtc = new DateTime( 0L, DateTimeZone.UTC );

Dump to console…

System.out.println( "epochParis: " + epochParis );
System.out.println( "epochUtc: " + epochUtc );

When run…

epochParis: 1970-01-01T01:00:00.000+01:00
epochUtc: 1970-01-01T00:00:00.000Z

Convert To UTC/GMT

So, how can i force the use of GMT, and ignore all local time ?

To use UTC/GMT (no time zone offset), either:

  • Convert a DateTime to another instance with a different time zone
    (Joda-Time makes things immutable for thread-safety, so we don't actually convert, we create new instances based on old ones.)
  • Use a formatter to create strings displayed for a specified time zone.
// To use UTC/GMT instead of local time zone, create new instance of DateTime.
DateTime nowInParis = new DateTime( timeZone_Paris );
DateTime nowInUtcGmt = nowInParis.toDateTime( DateTimeZone.UTC );

Dump to console…

System.out.println( "nowInParis: " + nowInParis );
System.out.println( "nowInUtcGmt: " + nowInUtcGmt );

When run…

nowInParis: 2013-12-22T08:40:01.443+01:00
nowInUtcGmt: 2013-12-22T07:40:01.443Z


回答4:

CET is one hour ahead of GMT, which is the time zone used to define the Epoch.



标签: java date epoch