I have in the form of String
the following:
month
which is in the form of 01-12
day
is is in the form of 01-31
year
which is in the form e.g. 2019
time
which I don't know the form if it can contain milliseconds or is just something like HH:MM
All this are supposed to represent a "timestamp" that is exact i.e. not relative to a timezone but e.g. if I did as a simplified example:
day/month/year time
it should be considered correct regardless of any timezone issues (I hope I explain this clearly).
My question is: what is the best way to create some LocalTime
or similar object from these so that it won't change due to some locale etc setting and I can do any string manipulation I need correctly or get an epoch?

- 3,845
- 3
- 22
- 47
-
The question seems too broad at the moment. Where are you storing the date? What kind of string manipulation you need to perform? Please share any code you might have written to exemplify the task at hand. – Mick Mnemonic Apr 07 '19 at 16:18
-
You can convert your localDateTime object to epoch milliseconds localDateTimeObj.toInstant(UTC).toEpochMilli(); – arseniyandru Apr 07 '19 at 16:19
-
@MickMnemonic: That is exactly the issue. How would I store this information properly. If I can convert it to a date object properly I think I should be able to store/retrieve later any way I need right? – Jim Apr 07 '19 at 16:24
-
@arseniyandru: I don't have a localDateTime object. My question is how can I create such an object properly based on this input – Jim Apr 07 '19 at 16:24
-
Creating a `LocalDateTime` object representing date and time of day is easy. For example `LocalDateTime.of(2019, 4, 7, 18, 59)`. But to convert it to seconds or milliseconds since the epoch you will need to know either a time zone or an offset from UTC. I can’t understand how year+month+day+hour+minute can be exact and not relative to any time zone. It doesn’t make sense to me. – Ole V.V. Apr 07 '19 at 16:59
-
It doesn’t seem to be what you are asking for, but I want to mention in case: an `Instant` is a point in time and translates directly to seconds or milliseconds since the epoch, and it’s independent of time zones. It is *not* date and time of day. Maybe if you give a quite concrete example of the string you’ve got and the epoch time you want, it would help understanding? – Ole V.V. Apr 07 '19 at 17:03
-
In any case I am convinced that java.time, the modern Java date and time API, will offer you all that you need. [Oracle tutorial here](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Apr 07 '19 at 17:10
-
@OleV.V.: May be my terminology is bad but when mentioning epoch I had in mind some numeric format that would make it easy to query if I store it in a database. If the epoch is only meaningful with some timezone and I don't have the timezone, then how could I store it in a way that could make it easy to query earlier and past dates? Sorry if I am confusing you, I think I haven't clear in my mind something related to date manipulation and end up with wrong tems – Jim Apr 07 '19 at 17:12
-
@OleV.V.: As an analogy, when you book a flight the time of arrival is mentioned to be in local time. So if you have that as a string it is not dependent of timezone, right? – Jim Apr 07 '19 at 17:16
-
Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/191404/discussion-between-ole-v-v-and-jim). – Ole V.V. Apr 07 '19 at 17:19
-
Possible duplicate of [Java Best Practice for Date Manipulation/Storage for Geographically Diverse Users](https://stackoverflow.com/questions/40075780/java-best-practice-for-date-manipulation-storage-for-geographically-diverse-user) – Ole V.V. Apr 07 '19 at 17:23
-
@OleV.V.: For some reason I can't write in the chat – Jim Apr 07 '19 at 17:33
-
@OleV.V. You are right about the example you provided. How would UTC help in that case? – Jim Apr 07 '19 at 17:36
-
Since Istanbul is at offset +03:00, you store 10:10 (UTC) in your database. Then it’s straightforward to compare with the other UTC times in your database, and you can safely ignore time zones while doing that. When you need to present the time to a user (for instance, print it on a ticket), you convert to Istanbul time (13:10). – Ole V.V. Apr 07 '19 at 18:12
-
@OleV.V.: So if I have the timezone along with the information I mentioned I could convert in UTC (that is epoch right?) and store in the database and convert as needed? – Jim Apr 07 '19 at 18:47
-
Basically correct, yes. UTC and epoch are not exactly the same, but contain the same information, so conversion both ways is unambiguous. – Ole V.V. Apr 07 '19 at 19:17
-
@OleV.V.: is is possible to instantiate a DateTime or LocalTime class with this data without any timezone and be able to use it properly? e.g store in milliseconds or convert to string? Or because of the missing timezone the object would not work properly? – Jim Apr 07 '19 at 19:33
1 Answers
It seems to me that you are asking the impossible or the senseless here.
Let’s take the example from the comments. A passenger books a flight with a time of arrival in İstanbul of 25/04/2019 13:10
. By convention arrival time is given in the local time of the arrival airport. Since İstanbul is at UTC offset +03:00, the arrival time is equal to 2019-04-25 10:10 UTC.
Commonly acknowledged good practice is to store dates and times in UTC in your database. If you are using an SQL database, you should normally use its timestamp with time zone
datatype (the “with time zone” part is a bit of a lie since you cannot store the timestamp with a time zone of your choice; it is always UTC, but I just said that this is good practice, so this is great).
Say that you’ve got this as input from a user: 25/04/2019 13:10
. Converting it to a LocalDateTime
is easy (when you know how; code example below). Storing it in UTC is impossible if we don’t know either a time zone (such as Europe/Istanbul or Asia/Istanbul) or a UTC offset (such as +03:00). Imagine that passenger John Doe Jr. has never flown before and doesn’t know of the convention to give arrival time in the local time of the arrival airport. So to him 13:10 could be 13:10 in his own time zone (America/Chicago, equal to 18:10 UTC), 13:10 in the departure time zone (America/New_York, equal to 17:10 UTC), 13:10 UTC, 13:10 in the arrival time zone (equal to 10:10 UTC) or something else.
Now let’s says that we do know that the input is in Europe/Istanbul time zone. Then conversion to UTC is straightforward. We store the time as 2019-04-25 10:10 UTC. Now it won't change due to any time zone setting of the computer or JVM. It’s straightforward to compare with the other UTC times in your database, and you can safely ignore time zones while doing that. When you need to present the time to a user (for instance, print it on a ticket), you convert to Istanbul time (13:10) (or to which time zone the user wants).
Don’t bother with epoch times unless you are using an API that requires them. The standard Java epoch is defined as January 1, 1970 at 00:00 UTC. Note that it is defined in UTC, so it is a well-defined point in time. An epoch time is a signed count of seconds or milliseconds since the epoch. Our example arrival time is 1 556 187 000 seconds since the epoch, so this is your epoch time. As you can see, it’s not meant for human readability. You won’t want to decipher a log file or run a debugging session where time is represented in this way. You don’t want to make any query to a database where time is represented in this way either.
Stay away from string manipulations. Do your date and time work in date and time objects only. When you receive a string, parse it into an appropriate date-time object. Only when you need to present it to a user or transmit it as a string to another system, format it into a string for that purpose.
Java date/time types
Java offers the following date and time types for us:
- A
LocalDateTime
is a date and a time of day without UTC offset or time zone, for example2019-04-25T13:10
. So it does not define a point in time. - An
Instant
on the other hand is a point in time without UTC offset or time zone. So it does not define a date and time of day. It prints in UTC (e.g.,2019-04-25T10:10Z
) and is internally represented as counts of seconds and nanoseconds since the epoch. - An
OffsetDateTime
is date and time of day with UTC offset, for example2018-04-25T13:10+03:00
. So this does define a point in time and does define date and time of day. - A
ZonedDateTime
is date and time of day with time zone, for example2018-04-25T13:10+03:00[Europe/Istanbul]
. So this too does define a point in time and does define date and time of day.
How it may look in code
DateTimeFormatter userInputFormatter = DateTimeFormatter.ofPattern("dd/MM/uuuu HH:mm");
String userInput = "25/04/2019 13:10";
ZoneId arrivalTimeZone = ZoneId.of("Europe/Istanbul");
// Parse into a LocalDateTime
LocalDateTime arrivalTimeLocal = LocalDateTime.parse(userInput, userInputFormatter);
System.out.println("Arrival time: " + arrivalTimeLocal);
Arrival time: 2019-04-25T13:10
// Convert to Instant in order to have a well-defined point in time
Instant arrivalTime = arrivalTimeLocal.atZone(arrivalTimeZone).toInstant();
System.out.println("Arrival point in time (printed in UTC): " + arrivalTime);
Arrival point in time (printed in UTC): 2019-04-25T10:10:00Z
// Convert to UTC for storing in SQL database
OffsetDateTime arrivalTimeUtc = arrivalTime.atOffset(ZoneOffset.UTC);
System.out.println("Arrival time in UTC: " + arrivalTimeUtc);
Arrival time in UTC: 2019-04-25T10:10Z
Edit: As I said, in your SQL database you would normally want to save your date and time in UTC in a column of datatype timestamp with time zone
. The details depend on your database and JDBC driver. I believe that in MySQL (and possibly other DBMSs) the type would be just timestamp
. This is a typical example:
// Save into a database column of datatype timestamp with time zone
PreparedStatement insert = yourDatabaseConnection.prepareStatement(
"insert into your_table (your_timestamp_with_time_zone_column) values (?);");
insert.setObject(1, arrivalTimeUtc);
int rowsInserted = insert.executeUpdate();
If SQLite hasn’t got a timezone or datetime datatype, prefer to store ISO 8601 format in a character column since this is more readable than epoch time in a numeric column. Instant.toString()
produces the string you need for that:
PreparedStatement insert = yourDatabaseConnection.prepareStatement(
"insert into your_table (your_varchar_column) values (?);");
insert.setString(1, arrivalTime.toString());
int rowsInserted = insert.executeUpdate();
Instant.parse
will parse the same string back after retrieval.
// Convert to arrival time zone, e.g., for printing on ticket
String arrivalTimeForUser = arrivalTime.atZone(arrivalTimeZone)
.format(userInputFormatter);
System.out.println("Formatted arrival time in local time: " + arrivalTimeForUser);
Formatted arrival time in local time: 25/04/2019 13:10
Links
- Mandatory read: Related question: Java Best Practice for Date Manipulation/Storage for Geographically Diverse Users
- Oracle tutorial: Date Time explaining how to use java.time.
- Documentation of

- 81,772
- 15
- 137
- 161
-
Thank you for your helpful answer. One question: where you have the example for `// Convert to UTC for storing in SQL database` shouldn't that be stored in milliseconds? – Jim Apr 08 '19 at 20:55
-
If you mean milliseconds since the epoch, I tried to argue against that in the paragraph “Don’t bother with epoch times…”. The details depend on the capabilities of your database and of your JDBC driver or what you use for accessing your database from Java. – Ole V.V. Apr 08 '19 at 22:10
-
What confuses me is the `OffsetDateTime` in your example. That is java specific, and if I need to store it in MySQL (timestamp) or SQLite (int utc time) etc I would need to convert it to something. My first thought is to convert to milliseconds to fit all cases. But from your comment seems it is not a good idea? Could you please explain this to me? – Jim Apr 09 '19 at 17:07
-
Yes it helps thank you. What about the case of exchanging it with other systems. E.g. receiving it from another system and storing it locally. What would be the format best for network API exchanges compatible to all? Also if I got you, as long as I save the UTC + timezone, I can do whatever I need with it right? – Jim Apr 09 '19 at 17:45
-
1The latter is correct. For exchanging use [ISO 8601 format](https://en.wikipedia.org/wiki/ISO_8601) wherever possible. – Ole V.V. Apr 09 '19 at 18:12
-
If I use `ISO 8601` as you mentioned, I can then store either `(2019-04-25T10:10Z, Europe/Istanbul)` or `2019-04-25T10:10Z+03:00`. But I am not sure if the second format will play well or not. I mean in the second format it is local time which is +03 offset from UTC so it is a complete piece of information. So which one to store? – Jim Apr 09 '19 at 20:08
-
It depends on the requirements. For future dates it’s safer to use the former to take the possibility into account that the politicians may change the offset before the date arrives. Otherwise if you need the offset (+03:00) and not the name of the time zone (Europe/Istanbul) store `2019-04-25T13:10+03:00`, so the local time with the offset. This is ISO 8601 and readily parsed into the correct `OffsetDateTime`. – Ole V.V. Apr 10 '19 at 03:37