6

I am trying to create a new object in my Parse.com database through Parse's REST API, using an HttpsUrlConnection. Their REST API only accepts JSON. I have gotten everything to work, where the database would accept the new object entry - except for when I attempt to include a Date field. When I do pass in a Date, the server rejects the object entirely.

I found this in their documentation this description for how to add a Date field in an object when using the REST API:

The Parse mobile client libraries also support dates, binary data, and relational data. In the REST API, these values are encoded as JSON hashes with the __type field set to indicate their type, so you can read or write these fields if you use the correct encoding.

The Date type contains a field iso which contains a UTC timestamp stored in ISO 8601 format with millisecond precision: YYYY-MM-DDTHH:MM:SS.MMMZ.

{
  "__type": "Date",
  "iso": "2011-08-21T18:02:52.249Z"
}

So if I want to create a new object and pass it to the database, I am assuming I need to create another JSONObject and pass it over in its corresponding field. However, when I tried that, it still rejected it. Below is my attempt at adding the Date object as a parameter to pass over, stored in its own JSONObject. What am I doing wrong? What is the right way of sendign a Date object in JSON, based on their docs?

//datePicked is a Calendar object
Date sendTime = datePicked.getTime();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
String sendTimeInUTC = formatter.format(sendTime);  

//Storing the Date object as a JSONObject, as specified
JSONObject dateAsObj = new JSONObject();
dateAsObj.put("__type", "Date");
dateAsObj.put("iso", sendTimeInUTC);

//jsonParam is the JSONObject that is being sent over to Parse's REST API
jsonParam.put("sendTime", dateAsObj);

Here is the full function which makes the http request, for context and reference:

private void runHttpRequest(final String emailAddress, final String password,
        String[] recipients, final String title, final String message) throws MalformedURLException {
    //Stores email in Parse DB, from Java servlet
    String url = "https://api.parse.com/1/classes/Email";
    URL obj = new URL(url);
    HttpsURLConnection con = null;
    try {
        con = (HttpsURLConnection) obj.openConnection();
    } catch (IOException e) {
        System.out.println("Failed to connect to http link");
        e.printStackTrace();
    }

    //add request header
    try {
        con.setRequestMethod("POST");
    } catch (ProtocolException e) {
        System.out.println("Failed to set to POST");
        e.printStackTrace();
    }
    con.setRequestProperty("X-Parse-Application-Id", "*****************");
    con.setRequestProperty("X-Parse-REST-API-Key", "*******************");
    con.setRequestProperty("Content-Type", "application/json");

    JSONObject jsonParam = new JSONObject();
    jsonParam.put("username", "******");
    jsonParam.put("emailID", 1);
    jsonParam.put("universalID", "******");
    Gson converter = new Gson();
    String recipientsInJson = converter.toJson(recipients);
    jsonParam.put("to", recipientsInJson);
    jsonParam.put("from", emailAddress);
    jsonParam.put("title", title);
    jsonParam.put("body", message);

    Date sendTime = datePicked.getTime();
    //jsonParam.put("sendTime", sendTime);
    SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
    String sendTimeInUTC = formatter.format(sendTime);
    System.out.println("UTC time" + sendTimeInUTC);

    JSONObject dateAsObj = new JSONObject();
    dateAsObj.put("__type", "Date");
    dateAsObj.put("iso", sendTimeInUTC);
    System.out.println(dateAsObj.toString());

    jsonParam.put("sendTime", dateAsObj);

    String urlParameters = jsonParam.toString();

    // Send POST request
    con.setDoOutput(true);
    DataOutputStream wr = null;
    try {
        wr = new DataOutputStream(con.getOutputStream());
    } catch (IOException e1) {
        System.out.println("Failed to get output stream");
        e1.printStackTrace();
    }
    try {
        wr.writeBytes(urlParameters);
    } catch (IOException e) {
        System.out.println("Failed to connect to send over Parse object as parameter");
        e.printStackTrace();
    }
    try {
        wr.flush();
    } catch (IOException e) {
        e.printStackTrace();
    }
    try {
        wr.close();
    } catch (IOException e) {
        System.out.println("Failed to connect to close datastream connection");
        e.printStackTrace();
    }

    int responseCode = 0;
    try {
        responseCode = con.getResponseCode();
    } catch (IOException e) {
        System.out.println("Failed to connect to get response code");
        e.printStackTrace();
    }
    System.out.println("\nSending 'POST' request to URL : " + url);
    System.out.println("Post parameters : " + urlParameters);
    System.out.println("Response Code : " + responseCode);

    BufferedReader in = null;
    try {
        in = new BufferedReader(
                new InputStreamReader(con.getInputStream()));
    } catch (IOException e) {
        System.out.println("Failed to get input stream");
        e.printStackTrace();
    }
    String inputLine;
    StringBuffer response = new StringBuffer();

    try {
        while ((inputLine = in.readLine()) != null) {
            response.append(inputLine);
        }
    } catch (IOException e) {
        System.out.println("Failed to read line");
        e.printStackTrace();
    }
    try {
        in.close();
    } catch (IOException e) {
        System.out.println("Failed to close input stream");
        e.printStackTrace();
    }

    //print result
    System.out.println(response.toString());
}

Any help or input would be appreciated.

2
  • You might to change the time format to fit ISO 8601: DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'"); Commented Aug 8, 2014 at 11:02
  • That is correct, that turned out to be the problem. I just did not format it properly. Commented Aug 8, 2014 at 12:44

3 Answers 3

5

Your format doesn't match the one they've required. For example:

Theirs: 2011-08-21T18:02:52.249Z
Yours:  2011-08-21 18:02:52.249

You're missing the T and the Z.

So try changing your format to:

SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");

To be honest, I'd be surprised if this weren't handled automatically though - have you tried just dateAsObj.put("iso", sendTime)?

Sign up to request clarification or add additional context in comments.

Comments

2

Standard Date Object is not stored in Parse. You have to set it as a JSON Object with "__type": "Date" and "iso": Date_String_you_want_to_set. with the date string formatted as below:

DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");

Comments

1

java.time

The java.util date-time API and their corresponding parsing/formatting type, SimpleDateFormat are outdated and error-prone. In March 2014, the modern Date-Time API supplanted this API. Since then, it has been strongly recommended to switch to java.time, the modern date-time API.

Before we talk about the solution

Before we talk about the solution, let's understand the difference between 'Z' and Z. While 'Z' is just a character literal, Z is the formatting code - a timezone designator for zero-timezone offset. It stands for Zulu and specifies the UTC offset (+00:00 hours). Check 'Z' is not the same as Z to learn more about it.

Solution:

// Replace new Date() with datePicked.getTime() in your case
Instant instant = new Date().toInstant();
OffsetDateTime odt = instant.atOffset(ZoneOffset.UTC);
System.out.println(odt);

// Format odt as per your requirement
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSX", Locale.ENGLISH);
String formatted = odt.format(formatter);
System.out.println(formatted);

Output from a sample run:

2023-09-09T08:44:38.863Z
2023-09-09T08:44:38.863Z

Online Demo

Note that I have used a DateTimeFormatter explicitly to meet the requirement of the specified format because the fraction-of-second part is omitted in the default implementation of toString method for java.time types when it is zero. If you are allowed to send your string without fraction-of-second part when it is zero, you can simply send the value of instant.toString().

Check this answer and this answer to learn how to use java.time API with JDBC.

Learn about the modern date-time API from Trail: Date Time

1 Comment

I prefer using the formatter just in case. toString() may also produce more than three decimals is the precision for it is there. It won’t be when converting from Date, but relying on this fact makes the code cryptic. And any day now the date picked time can come as an Instant with finer precision than milliseconds, and the code change that seems trivial will suddenly break things. The formatter is the clear and secure way to go.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.