2

I have to convert a date for the purpose of comparison using junit. I get a date from DB which is "06/25/2021 10:26:33.0" and I have to convert it to "2021-06-25T10:26:33.000-04:00" before I use it in the asserts.

I am trying not to use SimpleDate in java and use the the inbuilt java.time instead. However, I don't think I really understand everything in it. Here is the code snippet I have been playing around with. I have tried many things with this and I always get an error when the parse happens.

 public String test() throws ParseException {
    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S");
    LocalDateTime ldt = LocalDateTime.parse("06/25/2021 10:26:33.0", dtf);
    //After the above line I have a date like: 2021-06-25T10:26:33.0
    ZoneId zone = ZoneId.of("UTC-04:00");
    ZonedDateTime zdt = ldt.atZone(zone);
    Instant instant = zdt.toInstant();
    return instant.toString();
}

In my mind, I think I have to first convert the date to an "acceptable" format because I feel like this format of the string - "yyyy-MM-dd HH:mm:ss.S" is not something that java.time can handle. it gives me an error such as "Text could not be parsed at index 19" and then probably in the second pass convert it to into this "2021-06-25T10:26:33.000-04:00".

I have consulted several articles regarding this on SO but haven't been able to find something that helps in converting custom formats. I am aware that "parse" and "format" are 2 API methods that have to be leveraged here but not sure how to go about it. Could someone pls nudge me in the right direction?

Monnie_tester
  • 439
  • 1
  • 6
  • 20
  • Confused… You're using a completely different format to your input string – g00se Aug 24 '21 at 16:51
  • Don’t get your date and time as a string from the database. Retrieve a `LocalDateTime` (if you cannot retrieve an `OffsetDateTime`). See [the good answer by Arvind Kumar Avinash here](https://stackoverflow.com/a/67505173/5772882). – Ole V.V. Aug 24 '21 at 18:46

2 Answers2

3

You can use LocalDateTime#atOffset to meet this requirement.

import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        String input = "06/25/2021 10:26:33.0";
        DateTimeFormatter dtfInput = DateTimeFormatter.ofPattern("M/d/u H:m:s.S", Locale.ENGLISH);
        LocalDateTime ldt = LocalDateTime.parse(input, dtfInput);
        OffsetDateTime odt = ldt.atOffset(ZoneOffset.of("-04:00"));
        System.out.println(odt);

        // Formatted output
        DateTimeFormatter dtfOutput = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ENGLISH);
        String formatted = dtfOutput.format(odt);
        System.out.println(formatted);
    }
}

Output:

2021-06-25T10:26:33-04:00
2021-06-25T10:26:33.000-04:00

ONLINE DEMO

Notes:

  1. If the fraction-of-second can be of zero to nine digits in the input, use the pattern, M/d/u H:m:s[.[SSSSSSSSS][SSSSSSSS][SSSSSSS][SSSSSS][SSSSS][SSSS][SSS][SS][S]] where optional patterns have been specified using the square bracket.
  2. OffsetDateTime#toString omits the second and the fraction-of-second part if they are zero. Use a DateTimeFormatter to get them in the formatted string.

Learn more about the modern Date-Time API* from Trail: Date Time.


* 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.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
  • 1
    Thanks for the information. This worked like a charm. While I was trying, I couldn't figure the meaning of all the methods mentioned in documentation. Thanks for the explanation as well – Monnie_tester Aug 24 '21 at 19:50
1

convert it to into this "2021-06-25T10:26:33.000-04:00".

I think you'll need a custom formatter for that. Maybe the following:

    public String test() {
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("MM/dd/uuuu HH:mm:ss.S");
        LocalDateTime ldt = LocalDateTime.parse("06/25/2021 10:26:33.0", dtf);
        ZoneOffset zoff = ZoneOffset.ofHours(-4);
        OffsetDateTime ldt2 = ldt.atOffset(zoff);
        DateTimeFormatter tsf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSxxx");
        return tsf.format(ldt2);
    }

g00se
  • 3,207
  • 2
  • 5
  • 9
  • 2
    `ZonedDateTime` is the wrong type here. You should use `OffsetDateTime` in case of the timezone offset value. However, I am wondering what value have you added to the existing answer which was posted 20 minutes before you have posted this answer. – Arvind Kumar Avinash Aug 24 '21 at 17:22
  • *However, I am wondering what value have you added to the existing answer which was posted 20 minutes before you have posted this answer* You'll need to read my prefacing comment and then look maybe at the requirement a little closer – g00se Aug 24 '21 at 17:32
  • The OP probably has got a time zone in mind, such as America/St_Vincent, for example. If so, converting to a `ZonedDateTime` first is correct. It can then be formatted using `DateTimeFormatter.ISO_OFFSET_DATE_TIME` or further converted to an `OffsetDateTime` object. Also @ArvindKumarAvinash – Ole V.V. Aug 24 '21 at 18:59
  • Right. But I noticed that `ISO_OFFSET_DATE_TIME` is not *quite* right for OP's desired format. Maybe I'm missing something though. – g00se Aug 24 '21 at 19:08
  • @OleV.V. - The problem is that the OP has not responded to any of the answers or the comments and therefore one can only guess. `UTC-04:00` is not different from `-04:00` in the sense that even though `UTC-04:00` is technically a timezone ID, we can not derive a standard timezone ID like `America/St_Vincent` from it. For all practical purposes, `UTC-04:00` is a **fixed timezone offset** and therefore `OffsetDateTime` is the best match for it. – Arvind Kumar Avinash Aug 24 '21 at 19:24
  • You are right, of course, only the OP can tell, and it will be very helpful when they do. I just can’t see any reasonable business need for the time at offset -04:00. The time in some named time zone (like America/Asuncion, America/Port_of_Spain, there are numerous possibilities) expressed in ISO 8601 format makes a lot of sense. – Ole V.V. Aug 24 '21 at 19:31
  • @g00se Correct, they seem to ask for 3 digits decimal fraction of second, which `ISO_OFFSET_DATE_TIME` does not give when the fraction is zero, as in the example. So your `tsf` makes good sense. It could also well be that they don’t need that fraction since according to ISO 8601 it is optional when it is zero. – Ole V.V. Aug 24 '21 at 19:35
  • 1
    you guys are right a time zone of "America/St_Vincent" makes more sense and in my case if we happen to implement it; it will be "America/New_York" but at the moment I get "-04:00" in my service and I am just trying to match the data so that I know the service is bringing right values from the DB. For this purpose, I am writing this function to convert the value in the DB so the right format so that the format matches the service. Your solution though solved my problem as well. Thanks for that appreciate it – Monnie_tester Aug 24 '21 at 20:03