1

I'm using the below code to get the timestamp in yyyy-MM-dd hh:mm:ss format.

val load_date = java.time.LocalDateTime.now.toString.replace("T", " ").substring(0,19)

But sometimes, the substring throws Exception like below.

at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.StringIndexOutOfBoundsException: String index out of range: 19
at java.lang.String.substring(String.java:1963)

I have constraints to get this as a one liner solution.

stack0114106
  • 8,534
  • 3
  • 13
  • 38
  • 2
    The easiest way to identify the problem would be to print out / log the former String (LocalDateTime.now.toString). This way you'll exactly know why the index 19 is out of range. – Niklas P Sep 18 '18 at 06:03
  • I can't reproduce your problem ([see here](http://rextester.com/DXEN56135)), and `String#substring` is robust with regard to a ending index which is greater than the string. You'll see in the demo that I took a substring with `(0, 30)`, and it still ran. – Tim Biegeleisen Sep 18 '18 at 06:05
  • 3
    Anyway, the proper way to implement this would be to use a date formatter to format your date, instead of replacing characters and taking a substring. – JB Nizet Sep 18 '18 at 06:07
  • The answers below may be more optimal than the OP, but I still don't see why the OP's code should every be failing. Perhaps someone can address this. – Tim Biegeleisen Sep 18 '18 at 10:11
  • Should this question be closed? No. @TimBiegeleisen’s comment convinced me that it’s not a duplicate. And my own answer convinced me that it can be reproduced. – Ole V.V. Sep 18 '18 at 10:36

3 Answers3

1

Please use DateTimeFormatter class to do this.

public static void main(String[] args) {
        System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
}

For more information on the patterns supported by DateTimeFormatter please follow this link :: https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html

Abhishek
  • 2,485
  • 2
  • 18
  • 25
  • Almost correct. Please watch the case of your format pattern letters (there is a difference between `yyyy` and `YYYY`, etc.). Using `DateTimeFormatter` is certainly the right way to go. – Ole V.V. Sep 18 '18 at 08:13
  • @OleV.V. thanks for pointing it out to me... i went through this answer and understood the difference better. https://stackoverflow.com/a/26431981/4626402 – Abhishek Sep 18 '18 at 09:11
  • Thanks for receiving my critical comment so well. I still believe that uppercase `SS` is incorrect… – Ole V.V. Sep 18 '18 at 09:15
1

You can also get this format by using SimpleDateFormat

SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date now = new Date();
String strDate = sdfDate.format(now);
Ryuzaki L
  • 37,302
  • 12
  • 68
  • 98
  • Please don’t teach the young ones to use the long outdated and notoriously troublesome `SimpleDateFormat` class. At least not as the first option. And not without any reservation. 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 18 '18 at 08:11
1

Use a formatter

Best to use a formatter:

    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
    LocalDateTime dateTime = LocalDateTime.now(ZoneId.of("Europe/Simferopol"));
    String loadDate = dateTime.format(dtf);
    System.out.println(loadDate);

When I ran this code just now I got:

2018-09-18 12:57:42

(and yes, the length is 19)

What went wrong in your code?

While LocalDateTime.now() usually returns a date and time with millisecond or even microsecond precision depending on the platform, for example 2018-09-18T12:57:42.959829, it may occasionally hit a whole minute. When this happens, the seconds and fraction of second are left out from the result of the toString method, for example 2018-09-18T12:57. This string has length 16. Trying to take a substring of the first 19 characters of a string of length 16 results in a StringIndexOutOfBoundsException.

was this documented anywhere?

The documentation of LocalDateTime.toString says:

The output will be one of the following ISO-8601 formats:

  • uuuu-MM-dd'T'HH:mm
  • uuuu-MM-dd'T'HH:mm:ss
  • uuuu-MM-dd'T'HH:mm:ss.SSS
  • uuuu-MM-dd'T'HH:mm:ss.SSSSSS
  • uuuu-MM-dd'T'HH:mm:ss.SSSSSSSSS

The format used will be the shortest that outputs the full value of the time where the omitted parts are implied to be zero.

We see that the first format has length 16 (all the others are 19 or longer).

For the sake of completeness, from the docs of String.substring(int, int) (emphasis mine):

Throws:
IndexOutOfBoundsException - if the beginIndex is negative, or endIndex is larger than the length of this String object, or beginIndex is larger than endIndex.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • Nice catch on explaining the actual problem +1. – Tim Biegeleisen Sep 18 '18 at 10:41
  • Hi Ole..Great!.. was this documented anywhere?. Thanks a lot for saving my time.. my friend suggested below workaround. Do you see any issue with it.. or should I go with DateTimeFormatter val load_date = java.time.LocalDateTime.now.truncatedTo(java.time.temporal.ChronoUnit.SECONDS).toString.replace("T"," ") – stack0114106 Sep 18 '18 at 11:48
  • For the documentation, see my edit, @stack0114106. Your friend’s workaround will also sometimes produce a string of length 16 (not 19). If that’s OK, I think the workaround is OK. – Ole V.V. Sep 18 '18 at 12:01
  • Thanks Ole.. I just changed the code to use DateTimeFormatter val load_date = java.time.LocalDateTime.now.format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:SS")) – stack0114106 Sep 18 '18 at 12:04
  • You want lowercase `ss` for seconds in your format pattern string. With uppercase `SS` I just got `2018-09-18 14:06:87` when the time was `2018-09-18T14:06:43.878528` because `SS` is for fraction of second. – Ole V.V. Sep 18 '18 at 12:08
  • Ole, thank you for your meticulous review. I updated the code. – stack0114106 Sep 18 '18 at 15:33