-3

I'm a little stuck trying to parse a String into a Date. No matter what I do it throws me a ParseException.

This is what my Code looks like

public static double getDayTimeDouble(String timestamp){
        timestamp = "2020-12-20T09:12:41Z";
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
        Date date = formatter.parse(timestamp);
        double result = (date.getHours() * 60 + date.getMinutes()) / (24 * 60);
        return result;
    }

I have looked up how other people parse their Strings and found stuff on StackOverflow

        String input = "Thu Jun 18 20:56:02 EDT 2009";
        SimpleDateFormat parser = new SimpleDateFormat("EEE MMM d HH:mm:ss zzz yyyy");
        Date date = parser.parse(input);
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        String formattedDate = formatter.format(date);

but funnily enough using this code - without altering it to my needs - throws the very same exception trying to parse() it.

Now I'm kinda lost what the problem is and how to solve it ...

  • 2
    Why are you using the old deprecated SimpleDateFormat instead of classes from the java.time package? – Joakim Danielson Dec 20 '20 at 11:47
  • 1
    I recommend you don’t use `SimpleDateFormat` and `Date`. Those classes are poorly designed and long outdated, the former in particular notoriously troublesome. Instead use `Instant` or `OffsetDateTime`, both from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Dec 20 '20 at 11:49
  • For instance `LocalDateTime dt = LocalDateTime.parse(timestamp, DateTimeFormatter.ISO_DATE_TIME);` – Joakim Danielson Dec 20 '20 at 11:53
  • I cannot reproduce any exception from your first method. It returns 0.0 without throwing any exception. The problem with the second snippet is likely an incorrect locale. See [the comment by Nightingale7](https://stackoverflow.com/questions/999172/how-to-parse-a-date#comment23072591_999191) under the answer and/or [Java - Unparseable date](https://stackoverflow.com/questions/6154772/java-unparseable-date). – Ole V.V. Dec 20 '20 at 11:55

3 Answers3

1

java.time

I strongly recommend that you use java.time, the modern Java date and time API, for your time work.

private static final ZoneId ZONE = ZoneId.of("America/Vancouver");
private static final double MINUTES_PER_DAY = Duration.ofDays(1).toMinutes();

public static double getDayTimeDouble(String timestamp){
    timestamp = "2020-12-20T09:12:41Z";
    ZonedDateTime zdt = Instant.parse(timestamp)
            .atZone(ZONE);
    double result = zdt.get(ChronoField.MINUTE_OF_DAY) / MINUTES_PER_DAY;
    return result;
}

Since the time of day in Pacific Canada is 01:12:41 Pacific Standard Time (-08:00) at this time, the method returns

0.05

Please substitute your desired time zone if it differs.

As the code stands, it doesn’t take the seconds into the calculation. You may want to use a similar approach using ChronoField.SEOND_OF_DAY or one of the other XXX_OF_DAY fields. See the link below for available fields.

What went wrong in your code?

While I wasn’t able to get any exception from your method, there are some problems with is:

  • You were trying to use Date and SimpleDateformat. Those classes are poorly designed and long outdated, the former in particular notoriously troublesome. You shuold avoid them.
  • Worse yet, you were using Date.getHours() and Date.getMinutes(). These methods have been deprecated since Java 1.1 (February 1997) because they work unreliably across time zones.
  • Your parsing is incorrect. The Z, pronounced Zulu, in the string means UTC or an offset of zero from UTC. When you are hardcoding it as a literal, you are missing this important information and most probably getting an incorrect result.
  • Apparently you didn’t take time zone into account. It is never the same time of day in all time zones, so you need to decide on a time zone for you calculation. I recommend that you make this explicit in your code so the next person reading it also can understand what goes on. Use ZoneId.systemDefault() if you want and dare to rely on the JVM’s current time zone setting.
  • You were performing an integer division. The result of (date.getHours() * 60 + date.getMinutes()) is an int, and the result of (24 * 60) is an int too. The former is always less than the latter. So your division gives an int result and always 0. Then Java implicitly converts this 0 to a double, so you get 0.0 each time.

Links

Ole V.V.
  • 65,573
  • 11
  • 96
  • 117
0

What you want to achieve here?

I test below code on 11.0.7 and 8 and result I get as 0.0.
Also APIs date.getHours() and date.getMinutes() are DEPRECATED.

public class T {

    public static void main(String[] args) throws ParseException {
        String timestamp = "2020-12-20T09:12:41Z";
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
        Date date = formatter.parse(timestamp);
        double result = (date.getHours() * 60 + date.getMinutes()) / (24 * 60);
        System.out.println(result);
    }
}

Output: 0.0

shaILU
  • 1,838
  • 2
  • 18
  • 38
0

Address the following problems in your code:

  1. Do not put single quote around Z in the pattern. The Z in your example timestamp stands for Zulu which specifies date-time in UTC (i.e. a zone offset of +00:00 hours).
  2. Do not use Date#getHours and Date#getMinutes which have been deprecated as of JDK version 1.1 and replaced by Calendar#get(Calendar.HOUR_OF_DAY) and Calendar#get(Calendar.Calendar.MINUTE) respectively.
  3. In order to get the expected result in double while dividing an int with another one, either cast one of the variables into double or change one of the numbers into double e.g. change 60 to 60.0. Check this discussion to learn more about it.

Demo:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

public class Main {
    public static void main(String[] args) throws ParseException {
        System.out.println(getDayTimeDouble("2020-12-20T09:12:41Z"));
    }

    public static double getDayTimeDouble(String timestamp) throws ParseException {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
        Date date = formatter.parse(timestamp);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        double result = (calendar.get(Calendar.HOUR_OF_DAY) * 60.0 + calendar.get(Calendar.MINUTE)) / (24 * 60);
        return result;
    }
}

Output:

0.38333333333333336

Note that the date-time API of java.util and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API. For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Using the modern date-time API:

import java.time.OffsetDateTime;

public class Main {
    public static void main(String[] args) {
        System.out.println(getDayTimeDouble("2020-12-20T09:12:41Z"));
    }

    public static double getDayTimeDouble(String timestamp) {
        OffsetDateTime odt = OffsetDateTime.parse(timestamp);
        double result = (odt.getHour() * 60.0 + odt.getMinute()) / (24 * 60);
        return result;
    }
}

Output:

0.38333333333333336
Arvind Kumar Avinash
  • 50,121
  • 5
  • 26
  • 72
  • Thank you very much for that detailed answer. I'll be refactoring it accordingly. I did not know that this classes are depricated for so long already. I only searched for how to represent a date and that's what I came across. Since my application doesn't care for timezones I thought it may be smarter to just let it ignore these. – The ReportingChannel Dec 21 '20 at 05:09