-2
   def cleantz( time : String ) : String = {
    var sign_builder= new StringBuilder ++= time
    println(sign_builder)
    var clean_sign = ""
    if (sign_builder.charAt(23).toString == "-"){
      clean_sign= sign_builder.replace(23,24,"-").toString()
    }else{
      clean_sign = sign_builder.replace(23,24,"+").toString()
    }
    var time_builder= new StringBuilder ++= clean_sign
    if (time_builder.charAt(26).toString == ":"){
      val cleanz = time_builder.deleteCharAt(26)
      cleanz.toString()
    }else{
      time_builder.toString()
    }
  }

    val start = ISO8601Format.parse(cleantz(01/01/2017 6:54 PM))

I get this error:

java.lang.StringIndexOutOfBoundsException: String index out of range: 23

Joyce obi
  • 59
  • 1
  • 11
  • why am I getting java.lang.StringIndexOutOfBoundsException – Joyce obi Aug 28 '17 at 07:56
  • 3
    What do you suppose happens when you call `charAt(23)` on a `StringBuilder` that is less than 23 characters in length? – jwvh Aug 28 '17 at 08:09
  • i have edited the code, that is what i actually ran – Joyce obi Aug 28 '17 at 08:11
  • You're trying to get the character at position 23 when the string has less than 24 characters (because the first character is at position zero, the second is at position 1 and so on). So you should check the `length()` first. But anyway, if the string you have is in the format `01/01/2017 6:54 PM`, why do you need to check if the string contains `-`? You need to parse this to a date and then format with `ISO8601Format` –  Aug 28 '17 at 16:39
  • You tagged your question jodatime, and while Joda-Time is a good option, it also in maintenance mode, and its authors recommend we move on to `java.time`, which is developed by the same people drawing on all the experience from Joda-Time. So wouldn’t that be a still better option for you? – Ole V.V. Aug 29 '17 at 14:59
  • Possible duplicate of [What causes a java.lang.ArrayIndexOutOfBoundsException and how do I prevent it?](https://stackoverflow.com/questions/5554734/what-causes-a-java-lang-arrayindexoutofboundsexception-and-how-do-i-prevent-it) – Davis Broda Aug 30 '17 at 20:52

3 Answers3

2

java.time

For the sake of completeness I should like to contribute the modern answer. It’s quite simple and straightforward.

I am sorry that I can neither write Scala code nor test it on my computer. I have to trust you to translate from Java.

private static DateTimeFormatter inputFormatter 
        = DateTimeFormatter.ofPattern("MM/dd/yyyy h:mm a", Locale.US);

public static String cleantz(String time) {
    return LocalDateTime.parse(time, inputFormatter)
            .atOffset(ZoneOffset.ofHours(1))
            .toString();
}

Now cleantz("01/01/2017 6:54 PM") returns 2017-01-01T18:54+01:00, which is in ISO 8601 format. I would immediately suppose that you’re set. If for some reason you want or need the seconds too, replace .toString(); with:

            .format(DateTimeFormatter.ISO_OFFSET_DATE_TIME);

Now the result is 2017-01-01T18:54:00+01:00. In both cases the milliseconds would have been printed if there were any.

Since AM and PM are hardly used in other languages than English, I suggest you give an English-speaking locale to DateTimeFormatter.ofPattern() (in my example I used Locale.US). Failing to provide a locale will cause the code to fail on many computers with non-English language settings.

Why java.time?

  • SimpleDateFormat and friends are long outdated and notoriously troublesome. I cannot count the questions asked on Stack Overflow because SimpleDateFormat behaved differently from what every sane programmer would have expected, or offered no help to debug the simple errors we all make from time to time.
  • Joda-Time was good for a long time. Today the Joda-Time homepage says:

    Note that Joda-Time is considered to be a largely “finished” project. No major enhancements are planned. If using Java SE 8, please migrate to java.time (JSR-310).

  • java.time is the modern Java date & time API built using the experience from Joda-Time and under the same lead developer, Stephen Colebourne. It is built into Java 8 and later, and a backport exists for Java 6 and 7, so you can use the same classes there too.

Ole V.V.
  • 65,573
  • 11
  • 96
  • 117
  • This is a great feedback. I am knew to programming and scala in particular, so your answer has helped me understand why I should use each method and when to look for alternative. – Joyce obi Aug 29 '17 at 16:25
  • 1
    Good Answer. Also consider calling [`DateTimeFormatter.ofLocalizedDateTime`](https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ofLocalizedDateTime-java.time.format.FormatStyle-) rather than hard-coding a specific formatting pattern. – Basil Bourque Aug 29 '17 at 18:57
1

Assuming that your input string is 01/01/2017 6:54 PM: it has 18 characters. When you call charAt(23), it tries to get the character at position 23, which doesn't exist: the string has positions from zero (the first 0) to 17 (the M). If you try to get a position greater than that, it throws a StringIndexOutOfBoundsException.

But you don't need to do all this string manipulation. If you have a string that represents a date in some format, and want to convert it to another format, all you need is:

  1. parse the original string to a date
  2. format this date to another format

So you need 2 different Joda formatter's (one for each step). But there's one additional detail.

The input has a date (01/01/2017) and a time (6:54 PM), and the output has a date (2017-01-01), a time (18:54:00.000) and the UTC offset (+0100). So you'll have an additional step:

  1. parse the original string to a date
  2. add the +0100 offset to the parsed date
  3. format this date to another format

With Joda-Time, this can be achieved with the following code:

import org.joda.time.DateTimeZone
import org.joda.time.LocalDateTime
import org.joda.time.format.DateTimeFormat
import org.joda.time.format.ISODateTimeFormat

val fmt = DateTimeFormat.forPattern("dd/MM/yyyy h:mm a")
// parse the date
val localDate = LocalDateTime.parse("01/01/2017 6:54 PM", fmt)
// add the +01:00 offset
val dt = localDate.toDateTime(DateTimeZone.forOffsetHours(1))
// format to ISO8601
print(ISODateTimeFormat.dateTime().print(dt))

The output will be:

2017-01-01T18:54:00.000+01:00

Note that the offset is printed as +01:00. If you want exactly +0100 (without the :), you'll need to create another formatter:

val formatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
println(formatter.print(dt))

The output will be:

2017-01-01T18:54:00.000+0100

1

This is the code I used to achieve the same result. The error occurred because I was trying to parse the wrong date format.

   val inputForm = new SimpleDateFormat("MM/dd/yyyy h:mm a")
   val outputForm = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")

   val dateFormat1 = start_iso
   val dateFormat2 = stop_iso

   val start = outputForm.format(inputForm.parse(start_iso))
 val stop = outputForm.format(inputForm.parse(stop_iso))

   println(start)
println(stop)
Joyce obi
  • 59
  • 1
  • 11
  • 1
    Yeah, but why use the long outdated and notoriously troublesome `SimpleDateFormat`? The modern `java.time.format.DateTimeFormatter` is generally much nicer and more helpful. – Ole V.V. Aug 29 '17 at 14:55