1

I want to convert 2018-02-21 15:47:35 UTC to epoch UTC form. How do we do it? I am currently in PST.

SimpleDateFormat df = new SimpleDateFormat("YYYY-MM-DD HH:MM:SS");

df.setTimeZone(TimeZone.getTimeZone("UTC"));
date = df.parse(dateString).getTime();

The code above should return the number of milliseconds since January 1, 1970, 00:00:00 GMT, but I'm getting an incorrect value.

Rakshith R Pai
  • 202
  • 1
  • 5
  • 13
  • 1
    Don’t use `SimpleDateFormat`. It is not only long outdated, it’s also notoriously troublesome. [java.time, the modern Java date and time API,](https://docs.oracle.com/javase/tutorial/datetime/) is so much nicer to work with. And no matter which you use, watch the case of your format pattern letters, it matters. – Ole V.V. Mar 01 '18 at 08:53
  • Is there a way i can change epoch from time zone to other.I am in PST but i want my epoch to be in UTC as our database/server operates in UTC time.i am trying to test something locally as iam in PST.My system is calculation time stamp in PST formate only .Kinda confusing but running out of option over internet.. – Rakshith R Pai Mar 01 '18 at 08:59
  • 1
    Well, `SimpleDateFormat` does have a `setTimeZone` method. The "epoch" is something entirely different - you don't want to change those too often. – Dawood ibn Kareem Mar 01 '18 at 09:01
  • You can change your timezone globally for particular application, with flag `-Duser.timezone=UTC`, so you can run locally with UTC timezone – Ruslan Akhundov Mar 01 '18 at 09:07
  • As you already said, the epoch is always defined in GMT — let’s just regard it as the same as UTC for now. So the important part is that your time of 15:47:35 is in UTC too., – Ole V.V. Mar 01 '18 at 09:08
  • @OleV.V. thankyou :) your fix worked for me – Rakshith R Pai Mar 01 '18 at 09:36

4 Answers4

5

The only problem with your code is DateFormat

please check. https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html

    String dateString = "2018-02-21 15:47:35";
    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    df.setTimeZone(TimeZone.getTimeZone("UTC"));
    Date date = df.parse(dateString);
    long time = date.getTime();

    System.out.println(time);
    System.out.println(new Date(time));
    System.out.println(date);

I'm in PKT so output would differ...

1519228055000
Wed Feb 21 20:47:35 PKT 2018
Wed Feb 21 20:47:35 PKT 2018
rifaqat
  • 301
  • 2
  • 8
  • 1
    Is there a way to convert epoch from one zone format to other.I am writting a function to fetch data from db that were modified last 3 hrs.My data basse are in UST so not able to test this as im in PST time zone. – Rakshith R Pai Mar 01 '18 at 09:02
  • 1
    as Dawood said, epoch is entirely different thing, it is independent of timezones, i.e. "2018-02-21 15:47:35 UTC" "2018-02-21 20:47:35 PKT" have both same epoch value 1519228055000. – rifaqat Mar 01 '18 at 09:06
4

Expected: 2018-02-21 15:47:35 UTC is equivalent to 1 519 228 055 000 milliseconds since the epoch of January 1, 1970 at 0:00 UTC.

Observed: Your code in the question gives 1 514 818 800 035. So it’s 4 409 254 965 milliseconds off, a little over 51 days.

The solution:

    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
    date = LocalDateTime.parse("2018-02-21 15:47:35", dtf)
            .atOffset(ZoneOffset.UTC)
            .toInstant()
            .toEpochMilli();

This gives the correct 1 519 228 055 000.

What went wrong?

One of the many troublesome traits of SimpleDateFormat is that with its default settings, if you specify an incorrect format pattern string, it will very often give you an incorrect result and pretend all is well. The modern Java date and time API that I am using in my snippet, is trying somewhat harder to figure out when the pattern doesn’t make sense and tell you it’s wrong somehow. As an example, let’s try your format pattern with the modern DateTimeFormatter:

    final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("YYYY-MM-DD HH:MM:SS");
    LocalDateTime.parse(dateString, dtf);

This will throw a java.time.format.DateTimeParseException: Text '2018-02-21 15:47:35' could not be parsed at index 14. Index 14 is where 47 is in the string, it was supposed to be the minutes. Apparently 47 doesn’t match MM in the format. If you haven’t figured out yet, check the documentation. It says that uppercase M is for “month-of-year”. So what the formatter is trying to tell you is there are not 47 months in a year. In the documentation you will also find lowercase m for “minute-of-hour”. As you correct the case of the letters in the format pattern string, you will receive other exceptions until you end up with either yyyy-MM-dd HH:mm:ss or uuuu-MM-dd HH:mm:ss (lowercase yyyy is year or era while uuuu is a signed year, both work for years after year 0).

Links

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

Also can be done via java8 time library:

String dateString = "2018-02-21 15:47:35";

DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH);

dateTimeFormatter.withZone(ZoneId.of("UTC"));
LocalDateTime parsedDateTime = LocalDateTime.from(dateTimeFormatter.parse(dateString));
ZonedDateTime timeAtYourZone = parsedDateTime.atZone(ZoneId.systemDefault());

System.out.println(timeAtYourZone.toInstant().toEpochMilli());
System.out.println(timeAtYourZone);
Ruslan Akhundov
  • 2,178
  • 4
  • 20
  • 38
  • You can simplify your syntax by calling `LocalDateTime.parse( input , formatter )` rather than `LocalDateTime.from`. – Basil Bourque Mar 01 '18 at 17:47
  • 1
    Running your code in Europe/Copenhagen time zone I get 1 519 224 455, which is correct for 2018-02-21 15:47:35 in my time zone, but I believe the OP wanted the date-time to be interpreted in UTC, not the device time zone. Also I believe milliseconds were asked for, you give seconds. – Ole V.V. Mar 01 '18 at 17:47
  • 1
    @OleV.V. as I mentioned in the end of my post that can be achieved just by swapping ZoneId statements. – Ruslan Akhundov Mar 01 '18 at 17:48
  • 1
    @OleV.V. anyway, fixed the answer – Ruslan Akhundov Mar 01 '18 at 17:50
0

Your pattern must be yyyy-MM-dd HH:mm:ss, as the other answers told you:

SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

I just want to add some more details.

First of all, take a look at the patterns description in the javadoc: https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html

Note that a lowercase y is not the same as the uppercase Y (lowercase is the year, while uppercase is the week year - 2 different fields with completely different definitions)

Also note that uppercase D is the day of the year, while the day of the month (which is what you want) is the lowercase d. And uppercase M is the month, while lowercase m is the minute of hour.

And uppercase S is the milliseconds field, while the seconds are represented by lowercase s.

And SimpleDateFormat's design doesn't help: the class simply tries to parse the string, even if the month field (MM) appears twice in your pattern, while the minutes field doesn't appear (and it's set to a default value of zero - all behind the scenes, without any warning, no indication of error at all).

Conclusion: always read the docs :-)

For Java 8 or higher, consider using the new date API, which is much better because it doesn't have all these behind-the-scenes stuff:

DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
                           .withZone(ZoneOffset.UTC);
long epochMilli = Instant.from(fmt.parse("2018-02-21 15:47:35")).toEpochMilli();

This API will also throw an exception if you use a pattern like YYYY-MM-DD HH:MM:SS, because it will try to parse the minutes value 47 as a month (because uppercase MM will be in the respective position), and 47 is not a valid month.