0

I have a client written for Android and a Server written in Java. The server stores information, for example:

[{daysEpoch: ... , amount: 1}, {daysEpoch: ... , amount: 34},{daysEpoch: ... , amount: 76}] etc.... where daysEpoch is days from 01/01/1970.

Every day at midnight (+ 5 seconds), the client asks for the sum of items from epochDays=x where x is today. The problem is that "today" on the client is one day after (for example) the server which is UTC.

Obviously the return value is wrong. My first thought was to send the client's millis to the server, and it works but I wonder if there's a more proper way to handle this.

A bit more info: The items/amounts are there from a long time ago, Every day at midnight, the client asks for the sum of "today". If the client is gmt+1 (for example), midnight on the mobile is 11pm yesterday on the server. Only at 1am it will be "today" on the server. I hope it's clearer now.

Amos
  • 1,321
  • 2
  • 23
  • 44
  • It seems to me that a good solution would be if the client sends the request 5 seconds after midnight UTC rather than 5 seconds after midnight in its own time zone? It will get the freshest data in that way. – Ole V.V. Mar 22 '20 at 15:23
  • I have a widget that should be refreshed at midnight from the user perspective. – Amos Mar 22 '20 at 15:27
  • I didn’t quite get your wanted outcome. Even in the same time zone, at 5 seconds past midnight, are the results for “today” ready yet? And what if the device clock is 10 seconds ahead? – Ole V.V. Mar 22 '20 at 16:15
  • The items/amounts are there from a long time ago, Every day at midnight, the client asks for the sum of "today". If the client is gmt+1 (for example), midnight on the mobile is 11pm yesterday on the server. Only at 1am it will be "today" on the server. I hope it's clearer now. – Amos Mar 22 '20 at 16:19
  • Maybe you can turn it around and send a push to the clients when the data updated. – Maor Hadad Mar 22 '20 at 19:54
  • The data was updated a long time ago and it was irrelevant to the client :) Now the client wants to get the sum of the items that have amounts of today. – Amos Mar 22 '20 at 20:03

1 Answers1

4

ISO 8601

I am presenting two suggestions. I am not sure which one will best fulfil your goal. Both suggestions involve ISO 8601, the international standard for dates and times.

1. Send date and time in UTC: Since it works to send a point in time that is independent of time zone, I suggest that you do that by sending the date and time in UTC. For example:

 2020-03-22T19:04:57.110540Z

This is more human readable than a count of seconds or milliseconds since the epoch, yet perfectly machine readable too. The trailing Z means UTC.

2. Send just the date in UTC: The problem as I understood it was that the dates didn’t agree because of different time zones. However the client knows its own timezone and can fairly easily find the date in UTC and send it to the server, and then the server will understand.

2020-03-22

Again you may append Z to make it explicit that the date is in UTC if you prefer. It’s not much used, though occasionally. Again this format is readable by both humans and machines, which is why I’d prefer it over a count of days since the epoch day.

Edit: From the chat:

I want the data for "today" of the client.

And from the question:

The problem is that "today" on the client is one day after (for example) the server which is UTC.

Then I don’t understand how that is a problem. As far as I can see, you were getting what you say that you want.

I would still recommend sending the date in ISO 8601 rather than a count of days since the epoch.

How to write and read ISO 8601 in Java?

java.time, the modern Java date and time API, has been designed to work excellently with ISO 8601. To write date and time in UTC from a device in an arbitrary time zone:

    String dateTimeUtcString = Instant.now().toString();
    System.out.println(dateTimeUtcString);

Example output from running just now:

2020-03-22T19:34:48.034Z

In case you were wondering why I presented six decimals on the seconds before and only print three decimals this time: the number of decimals is free within the standard, you may even leave out the decimal part of the seconds completely if you don’t need it. It will all work.

To read this string on the server, parse back into an Instant:

    Instant i = Instant.parse(dateTimeUtcString);

If you wanted just the date, to write the UTC date from the device:

    String dateString = LocalDate.now(ZoneOffset.UTC).toString();
    System.out.println(dateString);

2020-03-22

Edit: since you want the client’s “today”, you should use ZoneId.systemDefault() instead of ZoneOffset.UTC in the call to LocalDate.now() above.

And to parse it on the server;

    LocalDate date = LocalDate.parse(dateString);

If you wanted Z to indicate UTC, it’s slightly longer:

    String dateUtcString = OffsetDateTime.now(ZoneOffset.UTC)
            .format(DateTimeFormatter.ISO_OFFSET_DATE);
    System.out.println(dateUtcString);

2020-03-22Z

To parse use the same formatter in the server:

    LocalDate date = LocalDate.parse(
            dateUtcString, DateTimeFormatter.ISO_OFFSET_DATE);

Question: Doesn’t java.time require Android API level 26?

java.time works nicely on both older and newer Android devices. It just requires at least Java 6.

  • In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
  • In non-Android Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
  • On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.

Links

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • The client shouldn't send the UTC time because it's yesterday (11pm). The client is on a new day (0am). What I can do, is send the client's epochDay. Am I missing something? – Amos Mar 22 '20 at 19:44
  • 1
    In the question you said that sending the client epoch day didn’t work because it was 1 day after the server date, but sending milliseconds worked, which corresponds to a unique UTC time (of 11 PM UTC in your example). I am getting confused about what the problem is. – Ole V.V. Mar 22 '20 at 19:49
  • Sorry for the confusion. At first I didn't send anything, I just told the server "give me now the sum of today (new day)" and it gave me back yesterday's sum because now it was still yesterday on the server. To fix this, I sent it the client's millis. I was wondering if there was a better way to accomplish that. – Amos Mar 22 '20 at 19:54
  • I would consider date and time in UTC better than milliseconds, but I have said that already. It’s the same information as the millis, only a different representation of it. – Ole V.V. Mar 22 '20 at 19:57
  • Maybe I'm missing something but utc is still yesterday at that point. – Amos Mar 22 '20 at 20:01
  • It is. But if the server hasn’t got the data for the date that the client considers “today”, what data do you expect from it? – Ole V.V. Mar 22 '20 at 20:04
  • As I wrote, the data was there from a long time ago. – Amos Mar 22 '20 at 20:38
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/210137/discussion-between-ole-v-v-and-amos). – Ole V.V. Mar 23 '20 at 05:21