Unparseable date: "2017-10-30T02:00:00.000Z"

Asked

Viewed 3,811 times

2

I am setting up a register where I pass a date and, when saving, is showing this error:

java.text.ParseException: Unparseable date: "2017-10-30T02:00:00.000Z"
    at java.text.DateFormat.parse(Unknown Source) ~[na:1.8.0_144]
    at controller.saude.PacientesController.cadastrarPacientes(PacientesController.java:77) ~[classes/:na]

My save method:

@RequestMapping(method = RequestMethod.POST, value = "/pacientes")
    public HttpStatus cadastrarPacientes(@RequestBody ObjectNode json) throws ParseException  {
        
        SimpleDateFormat formato = new SimpleDateFormat("dd/MM/yyyy");
            
            Entidades entidades = new Entidades();
            entidades.setIdEntidade(json.get("pessoa").get("entidade").get("idEntidade").asLong());
            
            Pessoas pessoas = new Pessoas();
            pessoas.setNome(json.get("pessoa").get("nome").textValue());
            pessoas.setNomeSocial(json.get("pessoa").get("nomeSocial").textValue());
            pessoas.setFoto(json.get("pessoa").get("foto").textValue());
            pessoas.setNomeSocial(json.get("pessoa").get("nomePai").textValue());
            pessoas.setNomeMae(json.get("pessoa").get("nomeMae").textValue());
            pessoas.setDataNascimento(formato.parse(json.get("pessoa").get("dataNascimento").textValue()));
            pessoas.setEntidade(new Entidades());
            pessoas.setEntidade(entidades);
            pessoas.setTipoPessoa(json.get("pessoa").get("tipoPessoa").textValue());
    }

HTML and Angular use on the front end:

<div class="form-group col-md-3">
    <label>Data Nascimento :</label> <input   name="data" id="data"  type="date" class="form-control" ng-model="paciente.pessoa.dataNascimento" format-date />
</div>

And I’m using that directive:

app.directive("formatDate", function() {
    return {
        require: 'ngModel',
        link: function(scope, elem, attr, modelCtrl) {
            modelCtrl.$formatters.push(function(modelValue) {
                if (modelValue){
                    return new Date(modelValue);
                }
                else {
                    return null;
                }
            });
        }
    };
});

The JSON that is coming in the backend is like this:

{
    "pessoa": {
        "nome": "aa",
        "nomeSocial": "aa",
        "dataNascimento": "2017-10-30T02:00:00.000Z",
        "tipoPessoa": "F",
        "entidade": {
            "idEntidade": "1"
        },
        "nomeMae": "a"
    }
}

3 answers

6


The Pattern used in the SimpleDateFormat has to represent the format of the date you receive.

Instead of:

SimpleDateFormat formato = new SimpleDateFormat("dd/MM/yyyy");

Use:

SimpleDateFormat formato = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");

In the class documentation SimpleDateFormat there is a table relating each letter to the element it represents.

3

From Java 8 you can use the API java.time.

In this case, the string "2017-10-30T02:00:00.000Z" represents a date and time in UTC (is what the "Z" at the end indicates, which is in UTC), and in addition it is in the format defined by ISO 8601 standard, which is already directly accepted by the classes of this API.

As it is in UTC and you need to convert to java.util.Date, one option is to use java.time.Instant:

// obtém o java.time.Instant
Instant instant = Instant.parse("2017-10-30T02:00:00.000Z");
// converte para java.util.Date
Date date = Date.from(instant);

Don’t do like the another answer, that ignored the "Z". The code even "works" (in the sense of not giving error), but this happens because SimpleDateFormat is a very permissive class and does not usually make mistakes in many cases where it should - see some examples here and here.

The problem is that if you ignore the "Z", the date is no longer considered in UTC, but in Timezone default JVM. For example, my JVM is using as default the Timezone America/Sao_Paulo, which corresponds to the Time of Brasilia. What happens if we ignore the "Z"?

String s = "2017-10-30T02:00:00.000Z";

// ignorando o Z
SimpleDateFormat formato = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
System.out.println(formato.parse(s)); // Mon Oct 30 02:00:00 BRST 2017

// não ignorando o Z
formato = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
System.out.println(formato.parse(s)); // Mon Oct 30 00:00:00 BRST 2017

Note that the resulting time was different. In the first case, as "Z" was ignored, the date and time were considered to be in Timezone default of the JVM (in my case, at 2 am of Brasilia Time). In the second case, by not ignoring the "Z", the result was midnight in Brasilia Time (which corresponds to 2 am in UTC - the difference is 2 hours because on 30 October 2017, we were in Daylight Saving Time).

Using Instant, as in the first example above, "Z" is also not ignored (which is correct, because being in UTC is important information, and ignoring it can result in a date/time that corresponds to a completely different instant).


It was unclear if strings always come in UTC, or if they can have other strings offsets (as an example "2017-10-30T02:00:00.000-03:00", for a date and time 3 hours ago of UTC). If this is the case, you can use a java.time.OffsetDateTime:

// obtém o java.time.OffsetDateTime
OffsetDateTime odt = OffsetDateTime.parse("2017-10-30T02:00:00.000-03:00");
// converte para java.util.Date
Date date = Date.from(odt.toInstant());

OffsetDateTime also works for the original string ("2017-10-30T02:00:00.000Z").

0

For me without the Z in the end it worked:

SimpleDateFormat formato = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");

Browser other questions tagged

You are not signed in. Login or sign up in order to post.