Date to Timestamp with UTC in Java - java

I have to convert a date (that is already in UTC) to a java.sql.Timestamp.
Issue
But when doing that, the time is changed to machine time:
new Timestamp(date.getTime());
So I get another date on the server.
Expected
When I convert back to Date I want to have the same date as before conversion.
I want to keep the same date (in UTC).
How could I do that?

It does not change the time. Timestamp and Date don't have a concept of a timezone, they represent an instant of time since the Epoch(1970-01-01T00:00:00Z).
Their .toString() methods on the other hand, have the bad habit of applying the default timezone of the JVM, when generating the string representation. I would advise to stay away from those classes, and instead use java.time, the modern java datetime API, it's available since java 8.

Related

How can I get the UTC-converted Java timestamp of current local time?

Could somebody please help with getting UTC-converted Java timestamp of current local time?
The main goal is to get current date and time, convert into UTC Timestamp and then store in Ignite cache as a Timestamp yyyy-MM-dd hh:mm:ss[.nnnnnnnnn].
My attempt was Timestamp.from(Instant.now()). However, it still considers my local timezone +03:00. I am getting '2020-02-20 10:57:56' as a result instead of desirable '2020-02-20 07:57:56'.
How can I get UTC-converted Timestamp?
You can do it like this :
LocalDateTime localDateTime = Instant.now().atOffset(ZoneOffset.UTC).toLocalDateTime();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
System.out.println(localDateTime.format(formatter));
Don’t use Timestamp
You most probably don’t need a Timestamp. Which is good because the Timestamp class is poorly designed, indeed a true hack on top of the already poorly designed Date class. Both classes are also long outdated. Instead nearly 6 years ago we got java.time, the modern Java date and time API. Since JDBC 4.2 this works with your JDBC driver too, and also with your modern JPA implementation.
Use OffsetDateTime
For a timestamp the recommended datatype in your database is timestamp with time zone. In this case in Java use an OffsetDateTime with an offset of zero (that is, UTC). For example:
OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC);
System.out.println(now);
PreparedStatement statement = yourDatabaseConnection
.prepareStatement("insert into your_table (tswtz) values (?);");
statement.setObject(1, now);
int rowsInserted = statement.executeUpdate();
Example output from the System.out.println() just now:
2020-02-22T13:04:06.320Z
Or use LocalDateTime if your database timestamp is without time zone
From your question I get the impression that the datatype in your database is timestamp without time zone. It’s only the second best option, but you can pass a LocalDateTime to it.
LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC);
The rest is the same as before. Example output:
2020-02-22T13:05:08.776
If you do need an old-fashioned java.sql.Timestamp
You asked for a Timestamp in UTC. A Timestamp is always in UTC. More precisely, it’s a point in time independent of time zone, so converting it into a different time zone does not make sense. Internally it’s implemented as a count of milliseconds and nanoseconds since the epoch. The epoch is defined as the first moment of 1970 in UTC.
The Timestamp class is a confusing class though. One thing that might have confused you is when you print it, thereby implicitly calling its toString method. The toString method uses the default time zone of the JVM for rendering the string, so prints the time in your local time zone. Confusing. If your datatype in SQL is timestamp without time zone, your JDBC driver most probably interprets the Timestamp in your time zone for the conversion into an SQL timestamp. Which in your case is incorrect since your database uses UTC (a recommended practice). I can think of three possible solutions:
Some database engines allow you to set a time zone on the session. I haven’t got any experience with it myself, it’s something I have read; but it may force the correct conversion from your Java Timestamp to your SQL timestamp in UTC to be performed.
You may make an incorrect conversion in Java to compensate for the opposite incorrect conversion being performed between Java and SQL. It’s a hack, not something that I would want to have in my code. I present it as a last resort.
LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC);
Timestamp ts = Timestamp.valueOf(now);
System.out.println(ts);
2020-02-22 13:05:08.776
You notice that it only appears to agree with the UTC time above. It‘s the same result you get from the answer by Vipin Sharma except (1) my code is simpler and (2) you’re getting a higher precision, fraction of second is included.
Have you database generate the current timestamp in UTC instead of generating it in Java.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Related question: Java - Convert java.time.Instant to java.sql.Timestamp without Zone offset
Despite what the Ignite docs say you can pass in a 24hr time.
The docs says yyyy-MM-dd hh:mm:ss[.nnnnnnnnn] so you may be tempted in your code to use this to format your dates but this will lead to times after midday being wrong. Instead, format your dates with yyyy-MM-dd HH:mm:ss[.nnnnnnnnn].
Notice the upper case HH. If you're using ZonedDateTime or Joda's DateTime when you call now with UTC now(UTC) and then toString("yyyy-MM-dd HH:mm:ss") will store the correct time in UTC.

Java 8 epoch-millis time stamp to formatted date, how?

Before Java-8 I got accustomed to always keep anything date/time related as milliseconds since Epoch and only ever deal with human readable dates/times on the way out, i.e. in a UI or a log file, or when parsing user generated input.
I think this is still safe with Java-8, and now I am looking for the most concise way to get a formatted date out of a milliseconds time stamp. I tried
df = Dateformatter.ofPattern("...pattern...");
df.format(Instant.ofEpochMilli(timestamp))
but it bombs out with Unsupported field: YearOfEra in Instant.getLong(...) which I half understand. Now what to use instead of Instant?
LocalDateTime.ofEpoch(Instant, ZoneId) seems wrong, since I don't care to have local time. I just want to see the local time zone when applying the formatter. Internally it should be just the Instant.
The same goes for ZonedDateTime.ofInstant(Instant, ZoneId), I thought to apply the ZoneId only when formatting. But I notice that the DateTimeFormatter does not itself deal anymore with time zones, it seems, so I reckon I need to use one of the above.
Which one is preferred and why? Or should I use yet another way to format an epoch-millis time stamp as a date/time with time zone?
An Instant does not contain any information about the time-zone, and unlike in other places, the default time-zone is not automatically used. As such, the formatter cannot figure out what the year is, hence the error message.
Thus, to format the instant, you must add the time-zone. This can be directly added to the formatter using withZone(ZoneId) - there is no need to manually convert to ZonedDateTime *:
ZoneId zone = ZoneId.systemDefault();
DateTimeFormatter df = DateTimeFormatter.ofPattern("...pattern...").withZone(zone);
df.format(Instant.ofEpochMilli(timestamp))
* regrettably, in early Java 8 versions, the DateTimeformatter.withZone(ZoneId) method did not work, however this has now been fixed, so if the code above doesn't work, upgrade to the latest Java 8 patch release.
Edit: Just to add that Instant is the right class to use when you want to store an instant in time without any other context.
The error you have when formatting an Instant using a formatter built with a year or other fields is expected; an Instant does not know which year or month or day it is, it only knows how much milliseconds have elapsed since the Epoch. For the same instant, it could be 2 different days on 2 different places of the Earth.
So you need to add a time zone information if you want to print the day. With an Instant, you can call atZone(zone) to combine it with a ZoneId in order to form a ZonedDateTime. This is very much like an instant, only that it has a time zone information. If you want to use the system time zone (the one of the running VM), you can get it with ZoneId.systemDefault().
To print it, you can use the two built-in formatter ISO_OFFSET_DATE_TIME or ISO_ZONED_DATE_TIME. The difference between the two is that the zoned date time formatter will add the zone id to the output.
Instant instant = Instant.now();
DateTimeFormatter formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
System.out.println(formatter.format(instant.atZone(ZoneId.systemDefault())));
System.out.println(formatter.format(instant.atZone(ZoneId.of("America/Los_Angeles"))));
when run on my machine, which has a system time zone of "Europe/Paris", you'll get:
2016-07-31T18:58:54.108+02:00
2016-07-31T09:58:54.108-07:00
You can of course build your own formatter if those one do not suit you, using ofPattern or the builder DateTimeFormatterBuilder.
I agree that this is somewhat confusing, especially when compared with it's predecessor Joda DateTime.
The most confusing thing is that the documentation for LocalDateTime says that it is "A date-time without a time-zone", and yet LocalDateTime.ofInstant method takes both an instant and a timezone as parameters.
That said, I think that you can achieve what you want by using Instant and LocalDateTime.ofInstant by using the UTC timezone.
public LocalDateTime millisToDateTime(long millis) {
return LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), ZoneId.of("Z");
}

UTC time different for local and server

I am saving time with other data to show in my app . I am storing the time in utc in db . Now when i run the program locally it works fine but when i run code on server the time is different from utc . My code to get utc timestamp is
private Timestamp getUTCTimestamp() throws ParseException
{
SimpleDateFormat sdf = new SimpleDateFormat(DATEFORMAT);
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
String utcTime = sdf.format(new Date());
SimpleDateFormat dateFormat = new SimpleDateFormat(DATEFORMAT);
Timestamp dateToReturn = new Timestamp(((Date)dateFormat.parse(utcTime)).getTime());
return dateToReturn;
}
It returns acurate utc time but when i run it on server it doesn't give the utc time e.g i ran the program locally and it gave me "2016-04-17 20:58:55" which was right and then after 10 mins i ran the code on server and it saved the time "2016-04-17 16:02:46" which was different .My server location is in netharlands. I don't understand , shouldn't the utc time be same everywhere??
Why are you formatting and then parsing the formatted string? Just use:
private Timestamp getUTCTimestamp() throws ParseException
{
return new Timestamp(new Date().getTime());
}
As to the issue you're seeing, I think #Stanislav Palatnik's comment is correct. You need to set the timezone on your format that is parsing the time string. Or just use the same format for formatting and parsing.. but again, why do you even need to go through that work?
If you are going to save current time on DB, it is much better to save with NOW() function of MySQL to make sure wherever the code runs, as far as the DB is the same, NOW() values will be consistent and you don't need to create time objects and lines of code to handle current time on java side.
see: https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_now
You are using old troublesome classes that are now outmoded. Avoid using SimpleDateFormat, java.util.Date/.Calendar and such, and minimize use of java.sql types.
Among their many problems is the behavior of toString method, applying a default time zone while generating the string. This confuses debugging efforts.
java.time
The java.time classes supplant the old date-time classes. Built into Java 8 and later, available as back-ports to Java 6 & 7 and to Android.
Do your business logic in java.time. Use java.sql only until JDBC drivers are updated to handle java.time types directly.
Define your column as something close to the SQL standard TIMESTAMP WITH TIME ZONE. Not "WITHOUT".
An Instant is a moment on the timeline in UTC.
Instant instant = Instant.now();
Convert to java.sql.Timestamp for storage in database.
java.sql.Timestamp ts = java.sql.Timestamp.from( instant );
Going the direction.
Instant instant = ts.toInstant();
The toString methods in java.time classes do not apply mysterious time zones when generating the textual representation of their date-time value. And they use standard ISO 8601 formats to further clarity.
So we go in and out of the database
all in UTC, no time zones, very simple, very clear.
When you need a wall-clock value such as far presentation to user, Apple a time zone to the instant to get a ZonedDateTime. Covered in detail in many other pages in Stack Overflow.
Your servers should be assigned a time zone of UTC (or Iceland). But never depend on that. Using the approach shown above makes the server’s time zone irrelevant.
No answer could have helped me because i found the reason and it had nothing to do with the code . I ran this command Date -u on putty and realized that the time isn't synchronized with utc and i don't know why . This post helped me in getting to this reason. I haven't tried the solution so if someone has a better solution feel free to tell me :) This is the
link

What is the most accurate joda-time representation for "DateUTC"?

Up until now we have been using joda-time class DateTime to represent date-time data with UTC timezone, and this meets our requirements nicely.
Example: 2014-11-07T14:10:00Z
Now, we have a requirement to represent "date" data (in UTC timezone).
Example: 2014-11-07
There exists a LocalDate joda-time class, and a method to convert from DateTime via DateTime.toLocalDate().
I looked for a joda-time class which I thought would exist DateUTC - but it doesn't seem to exist!
Can someone please point me in the right direction, or in fact specify what is the best joda-time class for representing "date-UTC" data (without timestamp) ?
P.s. we are not ready to move to java 8 yet, since we have a lot of code using joda-time library
If your DateTime object is in UTC, converting it to LocalDate is fine if you don't care about time. If it's not already in UTC, you can convert it to UTC using DateTime.withZone(DateTimeZone.UTC).toLocalDate()
LocalDate represents only the date components, without timezone information. Therefore, your code can just use it and assume it's in UTC, as long as you're consistent. For a string representation, you can use LocalDate.toString().
However, if all you want is to format your existing DateTime object so that the string representation only shows the date components, then you shouldn't need to use LocalDate. Just format it to only show the dates: DateTime.toString("yyyy-MM-dd").

Java data type to hold only date

Which data type in Java can hold just the date and doesn't require a time component? For example, just to store 12/07/2012. I'm working with persisting the data to/from a database that has a date-only data type, so I'm looking for the best equivalent data type in Java.
from the JDK: java.sql.Date:
A thin wrapper around a millisecond value that allows JDBC to identify
this as an SQL DATE value. A milliseconds value represents the number
of milliseconds that have passed since January 1, 1970 00:00:00.000 GMT.
To conform with the definition of SQL DATE, the millisecond values
wrapped by a java.sql.Date instance must be 'normalized' by setting
the hours, minutes, seconds, and milliseconds to zero in the
particular time zone with which the instance is associated.
or from JodaTime: DateMidnight or LocalDate (thanks
#cdeszaq)
DateMidnight defines a date where the time component is fixed at
midnight. The class uses a time zone, thus midnight is local unless a
UTC time zone is used.
It is important to emphasise that this class represents the time of
midnight on any given day. Note that midnight is defined as 00:00,
which is at the very start of a day.
The other answers are out-dated.
The old date-time classes are notoriously troublesome and should be avoided.
java.time
The java.time framework is built into Java 8 and later. See Oracle Tutorial. Much of the java.time functionality is back-ported to Jave 6 & 7 and further adapted to Android.
The LocalDate class represents a date-only value without time-of-day and without time zone.
LocalDate localDate = LocalDate.of( 2012 , 12 , 7 );
Textual representation
The toString method generates a String using standard ISO 8601 format.
localDate.toString() → 2012-12-07
For other formats use DateTimeFormatter.
SQL
JDBC drivers compliant with JDBC 4.2 can use the getObject and setObject methods to directly fetch/pass the java.time types such as LocalDate to SQL type DATE.
If your driver cannot do so, fall back to using the java.sql types. New methods have been added to the old classes to facilitate conversion.
java.sql.Date sqlDate = java.sql.Date.valueOf( localDate );
And the other direction.
LocalDate localDate = sqlDate.toLocalDate();
Search Stack Overflow
Search Stack Overflow for many more discussions and examples of using java.time. For example, my answer to this similar Question.
Date class. It holds a UNIX timestamp. In most databases, you can specify a field to hold a timestamp as well. You can use DateFormat to format the timestamp however you want.
If you are using Java 8, you can use java.time.LocalDate.
Use Date class that is available.
It shows how hold only date(without time)
formatter = new SimpleDateFormat("dd/MM/yyyy");
Date date= new Date();
Date todayWithOutTime =formatter.parse(formatter.format(date));
Unfortunatelly, java.util.Date is something, that in SQL have name Timestamp. There's no pure type for Date only, javax.sql.Date extends java.util.Date and using this type for date manipulation in Java gives you no advantage.
I'm dealing with this using apache commons-lang class DateUtils:
Date myDate = DateUtils.truncate(timestamp, Calendar.DAY_OF_MONTH);
This will remove the time part and leave only date part.
Use Date class. This is the better way.

Categories