Convert Timestamp as per TimeZone in java - java

I have a Timestamp object and a TimeZone object
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
TimeZone userTimeZone = preferenceService.getPreferredTimezone();
I want a function which modifies timestamp as per the userTimeZone . The function should return Timestamp. Could someone help ?

Your question is non-sensical. A Timestamp instance represent an instant in time. It doesn't have timezone info and isn't a timezoned stamp.
Instead, when showing a Timestamp to a user, in the step of 'convert this computer-time-kept concept to something to show the user', you'd do the job there. You wouldn't do that by first 'converting the timestamp to this timezone', you'd either do that in one go, or better yet, get to the java.time package as fast as possible because all other time libraries (including those in almost all DB engines) are non-sensical.
In java.time terms, you'd get to a ZonedDateTime, and hten you can convert that to another zone, and from there, potentially via a LocalDateTime, to rendering it to the user.
Given that you said the function must return a Timestamp, the code that uses this method is broken, so fix it there.

Related

Converting LocalDateTime to Timestamp format

Im converting date time string format to Timestamp (java.sql) from different format. I have converted it to LocalDateTime based on different format. Is there anyway to convert LocalDateTime object to Timestamp?
It’s more delicate than you think, so good you asked.
Since you can use java.time, the modern Java date and time API, you should not wish to apply the old-fashioned and poorly designed Timestamp class too.
I am assuming that you were asking for a Timestamp because you need something that you can store into an SQL database column of type timestamp (without time zone). Allow me to mention that for most purposes you don’t want such a column. The standard SQL datatype timestamp doesn’t live up its name. While the idea of a timestamp is that it should identify an unambiguous point in time when something happened, an SQL timestamp does not define such a point in time. It defines a date and time of day, and anyone is free to interpret it in any time zone, allowing for a variation of some 26 hours. Instead for a point in time you should use timestamp with timezone. It doesn’t live up to its name either in that it doesn’t let you choose the time zone. It stores times in UTC, so does identify a unique point in time.
On the Java side use an OffsetDateTime for storing into a timestamp with timezone column. Since you’ve got a LocalDateTime, you need to convert. And for the conversion you need to know the time zone intended behind your LocalDateTime. For example:
final ZoneId zone = ZoneId.of("Asia/Tehran");
LocalDateTime ldt = LocalDateTime.of(2019, 2, 25, 23, 45);
OffsetDateTime odt = ldt.atZone(zone).toOffsetDateTime();
System.out.println("As OffsetDateTime: " + odt);
As OffsetDateTime: 2019-02-25T23:45+03:30
Store into your database:
PreparedStatement ps = yourDatabaseConnection.prepareStatement(
"insert into your_table(your_ts_with_timezone) values (?)");
ps.setObject(1, odt);
ps.executeUpdate();
If either for some reason you do need a timestamp without time zone in your database or you cannot change it, you don’t need any conversion at all. Just store the LocalDateTime you had:
PreparedStatement ps = yourDatabaseConnection.prepareStatement(
"insert into your_table(your_ts_without_timezone) values (?)");
ps.setObject(1, ldt);
If you are programming to a legacy API that requires an old-fashioned java.sql.Timestampobject, things are getting even delicater. A Timestamp does define a point in time. So you will now need to convert from a LocalDateTime that does not define a point in time, to a Timestamp that does define one, then pass the Timestamp to an API that may store it in a database column that again does not define an unambiguous point in time. You will need to be sure which time zones are used for the conversions, and still there may be corner cases that fail or (worse) give incorrect results. However, as the_storyteller mentioned in a comment, the conversion is straightforward enough:
Timestamp ts = Timestamp.valueOf(ldt);
System.out.println("As old-fashioned Timestamp: " + ts);
As old-fashioned Timestamp: 2019-02-25 23:45:00.0
The conversion uses your JVMs default time zone. This setting is also used by TImestamp.toString(), so the output is as expected. This is shaky, though, since any program running in the JVM may change the default time zone setting at any time, so generally you don’t know what you get. To exercise control over the time zone used for conversion:
Instant i = ldt.atZone(zone).toInstant();
Timestamp ts = Timestamp.from(i);
Links
SQL- Difference between TIMESTAMP, DATE AND TIMESTAMP WITH TIMEZONE?
try it out with java 8 built in classes
public class Test {
public static void main(String[] args) {
Timestamp timestamp = Timestamp.valueOf(LocalDateTime.now());
// java timestamp class
System.out.println(timestamp);
// miliseconds
System.out.println(timestamp.getTime());
}
}

Convert from joda.Datetime to time.LocalDateTime is the right way?

I need timestamp format for my dates in database.
For now i have joda.Datetime in database , but also in my restApi application.
I tried to create a new column , and converted the existing joda.Datetime in the other column time.LocalDateTime. Also I replaced in all code joda.DateTime with time.LocalDateTime.
It works, but when i make a get call in postman, i received a json like:
{
seconds: x1,
minutes: x2,
hours: x3,
days: x4,
........
}
I think i need a convertor, to show the timestamp as "dd-mm-yy hh-mm-ss"
I want to have timestamp format in database to be able to execute SQL standard operation and named queries on time.
In my database I have bytea type for dates. I use PostgreSQL with DBeaver.
Is this the right way, or you could recommend me another option?
Is this the right way, or you could recommend me another option?
Without experience with PostgreSQL I should say that bytea is the wrong datatype for your dates or timestamps. timestamp with time zone is good and supports SQL operations and queries. It further has the advantage that you can store OffsetDateTime (perhaps even Instant, I am not sure) directly, so you avoid formatting your timestamp for storing it. That’ll be recommended.
For a time stamp to be a time stamp date and time of day is not enough. Date and time of day will be interpreted differently in different time zones (and is even ambiguous in the fall when summer time ends and the clocks are turned backward). As far as I have understood timestamp with time zone will make sure that time stamps are stored in UTC, so will be unambiguous points in time. In Java the Instant class represents a point in time independently of time zone, so is good for timestamps. Some JDBC drivers allow you to store an Instant directly into a timestamp with time zone column, others require you to convert to OffsetDateTime first. In the latter case use
OffsetDateTime dateTimeForDatabase = yourInstant.atOffset(ZoneOffset.UTC);
Edit: Please note that the with time zone bit is a bit of a lie, as #Jon Skeet points out in a comment. The database doesn’t store a time zone or offset, it only makes sure that dates and times are stored in UTC for removing ambiguity about the point in time.
Link: Date/Time Types in the PostgreSQL docs

Save TimeZone with Date in mongodb

I have java.util.Date field in my document class.
E:g:
#Document(collection = "testdoc")
public class TestDoc {
#Id
String id;
Date startDate;
}
Even if I set the Date with UTC and IST, it always save in my collection as below,
"startDate" : ISODate("2015-08-21T18:30:00.000Z")
How can I save the time zone also in mongo collection? What does Z stand in this case?
The 'Z' signifies that the time is stored in UTC. Mongo internally converts all local representations of time in UTC before storing. However, one suggestion would be to store the time along with the timezone which is received from your application. You can later reconstruct the local time from the UTC time and the timezone in your application logic.
Please go through this link. They have given an example on how to model local time data using JavaScript.
https://docs.mongodb.com/v3.2/tutorial/model-time-data/
Do the conversion before storing and save as UTC always. Then reconvert it in the timezone you want before displaying.
If you desperately want to store the timezone with the offset you may have to deal with it as a separate string in db, but it cannot go with date field for MongoDB.
As currently MongoDB doesn't allow saving of timezone.
Below is the open JIRA issue or the same.
https://jira.mongodb.org/browse/SERVER-6310
Dates in MongoDB are stored in UTC. There isn't timestamp with a timezone data type like in some relational databases. Applications that need to access and modify timestamps, based on local time, should store the timezone offset together with the date and offset dates on an application level.
In the MongoDB shell, this could be done using the following format with JavaScript:
let now = new Date();
db.page_views.save({date: now,
offset: now.getTimezoneOffset()});
Then you need to apply the saved offset to reconstruct the original local time, as in the following example:
let record = db.page_views.findOne();
let localNow = new Date( record.date.getTime() - ( record.offset * 60000 ) );
I guess here you'll find a good guideline how to handle timestamps in different scenarios for different data language independent.
As it's recommendet in the document, ALWAYS use UTC to save the data, even it is local timezone. If necessary, save the time zone in a seperate field ( JSON or xml) and follw the format guideline ISO 8601. ( like you did but there are many possible representations)
As far as I know, correct me if i'm wrong, JSOn does not deal with specific date formats but JS does. Microsoft docs recommends the followind format bases on ECMA YYYY-MM-DDTHH:mm:ss.sssZ this
The Z in the Timestamp shows that it's UTC format with zero offset +00:00
if nothing else is added.
If you want to use the "Z" notation, you have to add or substract the offset within the timestamp instead of writing the zero-offset and add the offset at the end.
I recommend you to follw the w3c guideline because it covers different scenatios for different time saving usecases.
Hope this helps

MySQL DATETIME and TIMESTAMP to java.sql.Timestamp to ZonedDateTime

I am wondering how the conversion works in this. MySQL server (5.6) treats TIMESTAMP as zone-adjusted (and internally stored in/retrieved from UTC). It also treats DATETIME as having no zone.
On the Java side, I am recommended to read into java.sql.Timestamp in either case. Is there a zone-type conversion taking place (when going through MySQL-connector 5.1.37) from MySQL's DATETIME to java.sql.Timestamp (such as to apply the client system zone) ?
In the end, there is only one zone for my server and clients, and so I maintain a specific ZoneId (in app code) to get to ZonedDateTime. But I would like to work with ZonedDateTime, going back and forth to the database stored as DATETIME. A simple example of conversion will be appreciated!
Let's address each question you have. First: Is there a zone-type conversion taking place (when going through MySQL-connector 5.1.37) from MySQL's DATETIME to java.sql.Timestamp (such as to apply the client system zone)?
First off, I presume that you are using the getTimestamp(int) method from the connector. I could not find an official source that showed me an enlightening answer; however, there was this question in which the answer stated: When you call getTimestamp(), MySQL JDBC driver converts the time from GMT into default timezone if the type is timestamp. It performs no such conversion for other types.
However, in this version of the method, it uses an underlying Calendar to convert the Timestamp to the TimeZone specified, if the underlying database doesn't store time zone information. This may be the solution to your second question, as long as you knew the time zone at which the value was stored (which you do). But if it is not, it seems that with the first method there is no conversion taking place, at least when it retrieves the DATETIME. Speaking about your second question:But I would like to work with ZonedDateTime, going back and forth to the database stored as DATETIME.
It makes me think that there is a way to do this as long as you knew which time zone you are converting from. As we have previously stated, you and your clients are only working with one ZoneId, which is totally fine. However, this answer is provided to work with more time zones. Multiple ZoneId's can be achieved if you were to store the ZoneId of the connection in the database; retrieving it as well as the DATETIME and finally processing these values into a ZonedDateTime. You could store the ZoneIds into the database using the ID's of the ZoneId class (if you wanted to).
Timestamp t = resultSet.getTimestamp(timestampColumnId);
ZoneId zoneId = ZoneId.of(resultSet.getString(zoneColumnId), ZoneId.SHORT_IDS);
ZonedDateTime d = ZonedDateTime.ofInstant(t.toInstant(), zoneId);
Or, you could just store the DATETIME as a TIMESTAMP in the database as ZZ Coder suggests in his answer stated above. But, you could just use the ZoneId you have hard-coded as such:
Timestamp t = resultSet.getTimestamp(timestampColumnId);
ZonedDateTime d = ZonedDateTime.ofInstant(t.toInstant(), zoneId);
EDIT
Looking at the source code, on get or set calls using the getTimestamp(int, Calendar) or the setTimestamp(int, Timestamp, Calendar) function, the timezone of the Calendar is used. However, in some cases with TIMESTAMP, when a Calendar is not used, the JDBC then uses the time zone of the server. And according to the original poster, it worked (see comment below).

Sql timestamp to Java date?

I have a database which is going to have UMT timestamps in standard sql format. How can I pull that data and set a java date object with it?
As far as I know mysql is yyyy-mm-dd hh:mm:ss As for java, the date / time stuff has always eluded me.
If anyone knows of a good library for this I am open to suggestions.
Why don't directly read it as Date
Date date = resultSet.getTimestamp("date_field");
Timestamp timestamp = resultSet.getTimestamp("date_time_field");
See
ResultSet.getTimeStamp()
A Timestamp is a subclass of a Date, which means it is usable everywhere where a Date is. The only difference is, Timestamp is more precise (due to the SQL specification) than Date is.
Just use:
Timestamp t = resultSet.getTimestamp("columnname");
Date d = t;
That having said, there are some benefits of converting the JDBC returned timestamp into a proper Date value, omitting nanoseconds. When you compare a Timestamp and a Date in some remote part of your app, the Timestamp and the Date won't be equal, even though they seem to be "rougly" the same time value. So if this could cause problem, create a new Date instance using only the .getTime() value returned by Timestamp)
More on this in my blog: Timestamp and Date equality when using Hibernate
(even though the blog entry is about Hibernate, it applies to your case as well)

Categories

Resources