1

Consider below string are UTC time and I want equivalent time in milliseconds using java.

String flcDate = "2018-09-07 05:45:00.0";
String geofenceDate = "2018-07-27 08:42:20";

I was trying the below code but it's changing the milliseconds on the basis of in which time zone I am.

public static long stringToMilliSeconds(String string) throws ParseException {

          SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
          Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
          TimeZone fromTimeZone = calendar.getTimeZone();
          TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
          calendar.setTimeZone(fromTimeZone);

          calendar.setTime(sdf.parse(string));
          System.out.println(calendar.getTime().toString());


          return calendar.getTime().getTime();
    }
Jens
  • 67,715
  • 15
  • 98
  • 113
amit singh
  • 23
  • 6
  • 4
    Do not use the old Clander API. Use the newer `java.time.*` classes. take a look at this answer: https://stackoverflow.com/a/33060590/3636601 – Jens Sep 10 '18 at 05:54
  • Can you subtract it from epoch in UTC to get a time duration, then get the number of milliseconds in that? A duration should not have a timezone. – TheBeardedQuack Sep 10 '18 at 05:56
  • It's not clear to me, can you send code snippet.:- subtract it from epoch in UTC to get a time duration. – amit singh Sep 10 '18 at 06:18
  • I recommend you avoid the `SimpleDateFormat` class. It is not only long outdated along with `Calendar`and `Date`, it is also notoriously troublesome. Today we have so much better in [`java.time`, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/) and its `DateTimeFormatter`. – Ole V.V. Sep 10 '18 at 06:18
  • Despite your time zone operations, your `SimpleDateFormat` uses your local time zone and therefore produces a point in time of 2018-09-07 05:45:00.0 in your local time zone, not in UTC. After that error is introduced, it propagates through your `Calendar` object and back out into your return value. – Ole V.V. Sep 10 '18 at 06:30
  • See [this similar question: Convert UTC date into milliseconds](https://stackoverflow.com/questions/12081417/convert-utc-date-into-milliseconds). – Ole V.V. Sep 10 '18 at 07:00

3 Answers3

3

This uses local date-time and instant to convert the string.

return LocalDateTime.parse("2018-09-07 05:45:00.0", 
                           DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S"))
     .toInstant(ZoneOffset.UTC)
     .toEpochMilli(); //1536299100000

The resulting long represents Epoch milliseconds for the input date/time (UTC time):

Instant.ofEpochMilli(1536299100000L)  ==> 2018-09-07T05:45:00Z

And for the second string, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") can be used as formatter.

ernest_k
  • 44,416
  • 5
  • 53
  • 99
  • Are you shure this is correct? You are reading the date in local time zone, aren't you? – keuleJ Sep 10 '18 at 06:18
  • 1536299100000 is giving me:- 9/7/2018, 11:15:00 AM. – amit singh Sep 10 '18 at 06:24
  • 2
    This is correct. The result quoted, `1536299100000`, equals 09/07/2018 @ 5:45am (UTC) (checked on https://www.unixtimestamp.com/index.php). “Local time” does not mean your local time, it means without time zone information, which is then added in the next line: `toInstant(ZoneOffset.UTC)`. – Ole V.V. Sep 10 '18 at 06:24
  • 1
    @amitsingh 9/7/2018, 11:15:00 AM in your time zone equals what UTC time? What is your time zone? It all seems correct to me. – Ole V.V. Sep 10 '18 at 06:32
  • How to get long value Millis equivalent to 2018-09-07T05:45:00Z – amit singh Sep 10 '18 at 06:46
  • 1
    @amitsingh The reverse: `Instant.parse("2018-09-07T05:45:00Z").toEpochMilli()`. By the way, `2018-09-07T05:45:00Z` is a better date/time format for you to use in this case. – ernest_k Sep 10 '18 at 06:48
1

Of course you should use the new java.time* Classes. But if its not possible, try this:

public static long stringToMilliSeconds(String string) throws ParseException {

          SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
          sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
          Date date = sdf.parse(string);
          System.out.println(date.getTime());

          return date.getTime();
    }
keuleJ
  • 3,418
  • 4
  • 30
  • 51
  • Of course it’s possible to use the four and a half years old java.time classes. If using Java 6 or 7 you will need [the ThreeTen Backport library](https://www.threeten.org/threetenbp/), though. From Java 8 and on java.time is built in. – Ole V.V. Sep 10 '18 at 06:20
  • 1
    This answer is correct, only it’s not recommended to use the outdated classes (BTW you aren’t using the `Calendar` object, so I think you could delete that line). – Ole V.V. Sep 10 '18 at 06:36
0

java.time

This one should be flexible enough to accept both of your strings:

private static DateTimeFormatter FORMATTER = new DateTimeFormatterBuilder()
        .append(DateTimeFormatter.ISO_LOCAL_DATE)
        .appendLiteral(' ')
        .append(DateTimeFormatter.ISO_LOCAL_TIME)
        .toFormatter();

public static long stringToMilliseconds(String string) {
    return LocalDateTime.parse(string, FORMATTER)
            .toInstant(ZoneOffset.UTC)
            .toEpochMilli();
}

Demonstration:

    String flcDate = "2018-09-07 05:45:00.0";
    System.out.println(stringToMilliseconds(flcDate)); // 1536299100000
    String geofenceDate = "2018-07-27 08:42:20";
    System.out.println(stringToMilliseconds(geofenceDate)); // 1532680940000

Output is in the comments.

The built-in DateTimeFormatter.ISO_LOCAL_DATE accepts a date string like 2018-09-10. DateTimeFormatter.ISO_LOCAL_TIME accepts a time string like 10:15 or 05:45:00.0. The seconds and fraction of second are optional, and the fraction may be up to 9 decimals. I use a DateTimeFormatterBuilder for building the two formatters into one with a space between the date and the time.

The ‘local’ in LocalDateTime (and other java.time class names) means “without time zone information”, so the use of this class makes sure that no unintended time zone, like your default one, interferes. And the use of ZoneOffset.UTC in the conversion to Instant makes sure we get the time in UTC.

What went wrong in your code?

Despite your time zone operations, your SimpleDateFormat uses your local time zone and therefore produces a point in time of 2018-09-07 05:45:00.0 in your local time zone, not in UTC. After that error is introduced, it propagates through your Calendar object and back out into your return value.

I recommend you don’t use SimpleDateFormat, Calendar and TimeZone at all. Those classes are long outdated, and SimpleDateFormat in particular is notoriously troublesome. Today we have so much better in java.time, the modern Java date and time API.

Link: Oracle tutorial: Date Time explaining how to use java.time.

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