24

I was expecting this to print 1970-01-01-00:00:00, but it prints 1970-12-31-19:00:00

What am I misinterpreting about how Date is counted from? It is one year off. I am running this on Windows 7 with JDK 1.6

System.out.println(new SimpleDateFormat("YYYY-MM-dd-HH:mm:ss").format(new Date(0)));
EdgeCase
  • 4,719
  • 16
  • 45
  • 73
  • That line of code doesn't run. The `YYYY` is invalid. By the way, are you sure that it isn't 1969 rather than 1970 because you're at UTC-5? – BalusC Oct 25 '11 at 20:07
  • @BalusC: YYYY isn't invalid - it's well-documented to give the week year... – Jon Skeet Oct 25 '11 at 20:17
  • 2
    @Jon: in this particular construct it **is** invalid. Also, the OP said to use Java 1.6, not 1.7. – BalusC Oct 25 '11 at 20:18
  • @BalusC: Ooh - I hadn't realized it wasn't in Java 1.6. The code does work in 1.7 though... – Jon Skeet Oct 25 '11 at 20:22
  • 1
    @Jon: all with all, it's simply a bad and confusing question :) OK, if we assume that you're right and that OP is *actually* running on Java 1.7, then you might want to improve your answer on that. – BalusC Oct 25 '11 at 20:24
  • @BalusC: I edited it to check that, and I've edited it again to make it clearer earlier... – Jon Skeet Oct 25 '11 at 20:42

6 Answers6

24

What am I misinterpreting about how Date is counted from?

new Date(0) is January 1, 1970 in UTC. Your timezone is not UTC.

It is one year off.

No, it's not. The printed value is only 5 hours behind. Let me guess - you're somewhere in the eastern part of the US?

Matt Ball
  • 354,903
  • 100
  • 647
  • 710
  • 1
    I figured the 1900 was due to EDT, but it is about to roll over to 1971, so it is nearly 365 days ahead, as I look at it. – EdgeCase Oct 25 '11 at 20:11
  • 1
    Jon, you're right (of course :). I've never even _heard_ of a "week year." – Matt Ball Oct 25 '11 at 20:17
  • It’s one year off alright. I for my part cannot understand how an answer claiming that it isn’t can be voted a close 2nd among 6 answers. – Ole V.V. Jul 11 '21 at 18:30
24

It's not just the time zone - it's a mixture of using the time zone and using YYYY which indicates the week year rather than the year (as of Java 7). Change it to yyyy and you'll see 1969.

The docs on week years state:

Values calculated for the WEEK_OF_YEAR field range from 1 to 53. The first week of a calendar year is the earliest seven day period starting on getFirstDayOfWeek() that contains at least getMinimalDaysInFirstWeek() days from that year. It thus depends on the values of getMinimalDaysInFirstWeek(), getFirstDayOfWeek(), and the day of the week of January 1. Weeks between week 1 of one year and week 1 of the following year (exclusive) are numbered sequentially from 2 to 52 or 53 (except for year(s) involved in the Julian-Gregorian transition).

The getFirstDayOfWeek() and getMinimalDaysInFirstWeek() values are initialized using locale-dependent resources when constructing a GregorianCalendar. The week determination is compatible with the ISO 8601 standard when getFirstDayOfWeek() is MONDAY and getMinimalDaysInFirstWeek() is 4, which values are used in locales where the standard is preferred. These values can explicitly be set by calling setFirstDayOfWeek() and setMinimalDaysInFirstWeek().

A week year is in sync with a WEEK_OF_YEAR cycle. All weeks between the first and last weeks (inclusive) have the same week year value. Therefore, the first and last days of a week year may have different calendar year values.

So the problem is that the last day of "normal year" 1969 is actually in the "week year" of 1970.

You should definitely use yyyy to avoid confusion - week years are relatively rarely useful, and can easily cause confusion, as we've seen :)

EDIT: As noted in comments, are you sure you're not using Java 7? The docs for SimpleDateFormat in 1.6 don't mention it... perhaps you're compiling in 1.6 but running in 7?

Community
  • 1
  • 1
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
14

To round up the correct answers about YYYY vs. yyyy and about timezone handling, here is the code that produces the output you expected:

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss");
    sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
    System.out.println(sdf.format(new Date(0))); //1970-01-01-00:00:00
Chris
  • 7,864
  • 1
  • 27
  • 38
0

java.time

I suggest that you use java.time, the modern Java date and time API, for your date and time work. On Java 1.6 and 1.7 this happens through the backport of java.time to those Java version, called the ThreeTen Backport (links at the bottom).

As has been discussed in the comments, you need to decide on a time zone for interpreting 0 milliseconds after the epoch into a date and time of day. Like one such comment I am picking America/New_York time zone as an example. Insert your own.

I am using these declarations:

private static final ZoneId ZONE = ZoneId.of("America/New_York");
private static final DateTimeFormatter FORMATTER
        = DateTimeFormatter.ofPattern("uuuu-MM-dd-HH:mm:ss", Locale.ROOT);

The rest is straightforward (when you know how):

    String epochString = Instant.EPOCH.atZone(ZONE).format(FORMATTER);
    System.out.println(epochString);

And output is:

1969-12-31-19:00:00

As has also been said already, at the epoch of 1970-01-01 UTC it is still December 31, 1969 on the western half of the globe including the Americas and a great part of the Pacific Ocean.

Pattern letter uuuu? With java.time you may use yyyy for year of era (always positive) or uuuu for a signed year. The latter is usually recommended so that you are sure to see the difference in case you (expectedly or not) come across a year from before the common era. The question uuuu versus yyyy in DateTimeFormatter formatting pattern codes in Java? linked to below covers the difference extensively.

Question: Doesn’t java.time require Java 8?

java.time just requires at least Java 6.

  • In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
  • In non-Android Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
  • On older Android either use desugaring or the Android edition of ThreeTen Backport. It’s called ThreeTenABP. In the latter case make sure you import the date and time classes from org.threeten.bp with subpackages.

Links

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
0

It probably has relation with your timezone. http://download.oracle.com/javase/1.4.2/docs/api/java/util/TimeZone.html

Miguel Prz
  • 13,718
  • 29
  • 42
-2

Just do * 1000L

 System.out.println(new SimpleDateFormat("YYYY-MM-dd-HH:mm:ss").format(new Date(0) * 1000L));
Gabriel Pereira
  • 580
  • 5
  • 9
  • It repeats the error from the question and furthermore does not compile: *The operator * is undefined for the argument type(s) Date, long* – Ole V.V. Jul 11 '21 at 18:08