I have a time value stored in my database in HH:mm:ss format (using MySQL's time type). This time is to be considered as a value of IST timezone. The server on which my Java code runs follows the UTC timezone.
How can I get a formatted datetime in yyyy-MM-dd HH:mm:ss in IST (or in UTC millis)? Following is what I've tried till now:
// ... Code truncated for brevity
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalTime time = resultSet.getTime("send_time").toLocalTime();
LocalDateTime datetime = time.atDate(LocalDate.now());
System.out.println(datetime.format(formatter));
The above correctly prints the datetime on my local machine, which is on IST, but I'm concerned about how it will behave on the remote server.
Your approach is fine and should work regardless of your computer's time zone since there is no time zone information in either LocalTime or LocalDateTime. One possible issue is with LocalDate.now() which returns today's date in the computer's local time zone, not in IST. You may want to replace it with LocalDate.now(ZoneId.of("Asia/Calcutta")).
Or as commented by #OleV.V. you could use the new driver facilities to derive a LocalTime directly:
LocalTime time = resultSet.getObject("send_time", LocalTime.class);
Note possible caveats with your approach:
if the time zone you use introduces DST, you may end up with two identical times in your DB that were actually different instants - using UTC to store times is probably more robust
time in mysql can store values smaller than 00:00 and larger than 23:59:59.999999, in which case you may experience unexpected behaviours on the Java side.
Related
Let's assume that I have client's time saved in my database as 2020-09-22T10:50:37.276240900
I need to present this date in web-service for client app depending on client timezone, for example I need to add 2 hours to saved date if client lives in UTC+2 timezone.
So what am I doing for ?
Getting date from entity and adding timezone to time taken from database (startDate: LocalDateTime)
entity.startDate.atZone(ZoneId.of("Europe/Vienna"))
what gives me the value of ZonedDateTime 2020-09-22T10:50:37.276240900+02:00[Europe/Vienna]
This value is what I'm expecting for, basically "initial time plus 2 hours". After that I would to format this time to have output with this 2 hours of being added, some kind of this
12:50 22.09.2020
but when I do format like this
entity.startDate
.atZone(ZoneId.of("Europe/Vienna"))
.format(DateTimeFormatter.ofPattern(NotificationListener.EUROPEAN_DATE_FORMAT, Locale.ENGLISH))
where const val EUROPEAN_DATE_FORMAT = "HH:mm dd.MM.yyyy"
I get this output 10:50 22.09.2020 which looks like my format is not applied properly, so I cannot see my 2 hours.
So my questions are:
am I correct to adding timezone of client app in described way ?
how to apply timezone in more precise way and format this date to see timezone zone applied ?
LocalDateTime.atZone does not "move" the point in time. In fact it tries to present the point in time where the local time in the given timezone is exactly what the LocalDateTime shows.
In other words: if your LocalDateTime represented 10:00 at some date, then the ZonedDateTime output of atZone will also represent 10:00 local time at the specified time zone (except in cases where that local time doesn't exist due to DST changes).
So if your stored time is actually in UTC, you need to add one more step:
ZonedDateTime utcTime = entity.startDate.atZone(ZoneOffset.UTC);
ZonedDateTime localTime = utcTime.withZoneSameInstant(ZoneId.of("Europe/Vienna"));
Alternatively you can avoid calculating the localTime each time and instead configure the DateTimeFormatter to use a given time zone (which means it'll do the necessary calculations internally) using DateTimeFormatter.withZone. If you do this then you can pass the utcTime to it directly.
I'am creating a date and store it into database, I want to get current time which is timezone = "Asia/Istanbul" not my local time.
I am creating the date in my local computer, my local timezone is also "Asia/Istanbul".
when i deploy it into my server, server timezone is utc, it is turning to utc everytime.
I have different 2 machine, 2 machines have different timezone so I need to set my data dates with the timezone.
here is what i have done. it is ok in my local computer, but fails on server which is UTC
LocalDateTime localDateTime = LocalDateTime.now();
// it gives my local date time, 2019-07-09T10:30:03.171
// local date is now 1:30 pm, UTC is 3 hours after, it looks ok.
ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, ZoneId.of("Asia/Istanbul"));
//2019-07-09T10:30:03.171+03:00[Asia/Istanbul]
// it looks +3. I dont want to see +3, I want the date like 01:30 which is shiefted
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
zonedDateTime.format(formatter);
//2019-07-09T07:30:03.171Z
// zone is disappeared, this is 3 hours before UTC
I expect the date like Asia/Istanbul when i created it.
I wouldn’t use LocalDateTime at all. Use ZonedDateTime throughout to eliminate any and all doubt about the time. Also always pass a ZoneId (if not a Clock) to the now method. This makes your code independent of the time zone settings of the computer and JVM.
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("Asia/Istanbul"));
System.out.println(zonedDateTime);
2019-07-09T14:14:17.280852+03:00[Asia/Istanbul]
You might have misunderstood the +03:00 part, people sometimes do. It means that the time shown is already 3 hours ahead of UTC. So the point in time shown is equal to 11:14:17 UTC.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
System.out.println(zonedDateTime.format(formatter));
2019-07-09 14:14:17
Your formatter does not include time zone, therefore it’s not shown. But it’s the time in İstanbul.
What went wrong in your code?
I am assuming that the comments in your code are from running on your server in UTC (it’s not perfectly clear) and that you ran the code around 10:30 UTC, the same as 13:30 in İstanbul.
A LocalDateTime is a date and time without time zone and without UTC offset. Its no-arg now method uses the JVM’s time zone setting, in this case UTC, so gives you 10:30 on the day in question. I think that ZonedDateTime.of is wrong here: it takes the 10:30 from the LocalDateTime and İstanbul time zone from the ZoneId object and gives you 10:30 in İstanbul, which is not what you wanted. You had wanted 13:30, AKA 1:30 PM.
I have time 12:00:00 in format HH:mm:ss.
I know that this time comes from server witch is setup with +3 offset.
If i use SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");, it parses time with regard to device, which can be in a different timezone.
Is there another way to parse it with regard to +3 offset except adding it to the original string?
First, should your server rather send the time in UTC? If clients are everywhere, this would seem more time zone neutral and standardized. However, the way to handle it in code wouldn’t be much different. In any case the server offset form UTC could be constant:
private static final ZoneOffset serverOffset = ZoneOffset.ofHours(3);
In real code you will probably want to make it configurable somehow, though. To parse:
OffsetTime serverTime = LocalTime.parse("12:00:00").atOffset(serverOffset);
System.out.println(serverTime);
This prints
12:00+03:00
Since your time format agrees with LocalTime’s default (ISO 8601), we need no explicit formatter. If a representation of the time with offset is all you need, we’re done. If you need to convert to the user’s local time, to do that reliably you need to decide both a time zone and a date:
LocalTime clientTime = serverTime.atDate(LocalDate.of(2018, Month.JANUARY, 25))
.atZoneSameInstant(ZoneId.of("Indian/Maldives"))
.toLocalTime();
System.out.println(clientTime);
With the chosen day and zone we get
14:00
Please substitute your desired time zone and date.
Just hypothetically, if you knew the user’s offset from UTC, you could use just that:
LocalTime clientTime = serverTime.withOffsetSameInstant(ZoneOffset.of("-08:45"))
.toLocalTime();
The example yields 00:15. However, no one knows when the politicians introduce summer time (DST) or other anomalies in the user’s time zone, so I discourage relying on an offset alone.
And yes, I too am using java.time. SimpleDateFormat is not only long outdated, it is also notoriously troublesome, so java.time is what I warmly recommend.
Set the timezone on your SimpleDateFormat object:
SimpleDateFormat fmt = new SimpleDateFormat("HH:mm:ss");
fmt.setTimeZone(TimeZone.getTimeZone("GMT+03:00"));
I recommend you use the Java 8 date and time API (package java.time) instead of the old API, of which SimpleDateFormat is a part.
Using the Java 8 DateTime API:
DateTimeFormatter formatter = DateTimeFormatter
.ofPattern("HH:mm:ss");
LocalTime clientLocalTime = LocalTime
.parse("12:00:00", formatter)
// Create an OffsetTime object set to the server's +3 offset zone
.atOffset(ZoneOffset.ofHours(3))
// Convert the time from the server timezone to the client's local timezone.
// This expects the time value to be from the same day,
// otherwise the local timezone offset may be incorrect.
.withOffsetSameInstant(ZoneId.systemDefault().getRules().getOffset(Instant.now()))
// Drop the timezone info - not necessary
.toLocalTime();
I've been scratching my head trying to understand why the FastDateFormat parser is returning a very incorrect time. The string timestamp I'm trying to convert is in GMT/UTC, and I'm trying to insert it into a Timestamp column in DB2.
Here's the code:
String gmtTimestamp = "2017-03-12 02:38:30.417000000";
FastDateFormat fdf = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss.SSSSSSSSS", TimeZone.getTimeZone("GMT"));
java.util.Date d = fdf.parse(gmtTimestamp);
Timestamp ts1 = new Timestamp(d.getTime());
System.out.println(ts1);
The time that's printed is: "2017-03-16 17:28:30.0", 4 days and nearly 15 hours off. What's happening here?
TL;DR
String gmtTimestamp = "2017-03-12 02:38:30.417000000";
DateTimeFormatter dtf
= DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSSSSSSSS");
Instant i1 = LocalDateTime.parse(gmtTimestamp, dtf)
.atOffset(ZoneOffset.UTC)
.toInstant();
System.out.println(i1);
This prints
2017-03-12T02:38:30.417Z
The implicit call to Instant.toString() produces date and time in UTC (for our purpose the same as GMT), so you recognize the date and time from your GMT string.
java.time
I recommend you drop the java.sql.Timestamp class. It is long outdated, and today we have so much better in java.time, the modern Java date and time API. The original purpose of Timestamp was to store and retrieve date-time values to and from SQL databases. With a sufficiently new JDBC driver (JDBC 4.2), you can and will want to take advantage of two classes from java.time for that purpose: Instant for a point on the timeline and LocalDateTime for date and time without time zone.
In case you do need a Timestamp (for instance for a legacy API or an older JDBC driver you don’t want to upgrade just now), convert the Instant from above to Timestamp just before handing it to the legacy API or the database:
Timestamp ts1 = Timestamp.from(i1);
System.out.println(ts1);
Running in America/Chicago time zone this prints:
2017-03-11 20:38:30.417
Timestamp.toString() grabs the JVM’s time zone setting and outputs the date and time in this time zone (which may be confusing).
What was happening in your code snippet?
FastDateFormat uses SimpleDateFormat format patterns. In SimpleDateFormat and FastDateFormat capital S means milliseconds. so 417000000 was taken as milliseconds (where you intended 417 milliseconds), it is rpughly the same as 4 days 20 hours, which were added to the date-time value up to the seconds. I reproduced your result using a SimpleDateFormat and setting my JVM to America/Chicago time zone. Other time zones that are -5 hours from UTC in March will produce the same result. Since the Timestamp was printed at offset -5:00, the apparent difference in the output was a bit less than the real difference of 4 days 20 hours, “only” 4 days 15 hours.
By contrast, though the modern DateTimeFormatter mostly uses the same format pattern letters, to it capital S means fraction of second, which is why we get 30.417 seconds as expected and desired.
Quotes
All patterns are compatible with SimpleDateFormat (except time zones
and some year patterns - see below).
(FastDateFormat documentation)
S Millisecond Number 978
(SimpleDateFormat documentation)
i'm building an android application which have a chat.
in this chat i each message to have its time sent signature.
my question is as follow:
lets say that the time in my country is X. my friend is abroad and his time is X minus 7 hours.
i'm sending him a message at 16:00 local time.
i want to avoid the situation that he will get at 09:00 a message which it signature will be 16:00 (which is a time in future if you're looking in the eyes of that friend in his country).
is there a way that in my phone the message will be written as 16:00 and in his phone it will be written as 09:00 ? i there a way to convert a time to a local time ?
System.currentTimeMillis() does give you the number of milliseconds since January 1, 1970 00:00:00 UTC. Date object does not save your local timezone.
You can use DateFormats to convert Dates to Strings in any timezone:
DateFormat df = DateFormat.getTimeInstance();
df.setTimeZone(TimeZone.getTimeZone("gmt"));
String gmtTime = df.format(new Date());
linked response
You should keep all time communications using UTC time. Then localize it for display based on the devices current timezone setting.
Use a long to save your time information as milliseconds since "epoch" (which is January 1, 1970, 00:00:00 GMT). It can be retreived with the Date.getTime() method and new Date objects are easily created using the Date(long millis) constructor. The Date objects are then displayed using the local timezone settings on each device.
EDIT:
Epoch is a defined point in time which is expressed differently in different time zones: 1970-01-01 00:00:00 GMT but
1969-12-31 19:00:00 EST. The timestamp is just the number of milliseconds elapsed since that time. So, for example the timestamp 1341169200 corresponds to 2012-07-01 19:00:00 GMT and 2012-07-01 14:00:00 EST.
You will need to save the time zone which your message will be saved in, and transfer it (or send the unix epoch time) and then on the other side make sure you read it in with the Locale time (using the Android documentation for things like http://developer.android.com/reference/java/util/Calendar.html can help).
Take a look at the answer over here:
https://stackoverflow.com/a/6094475/346232
You need to change the time to UTC and then convert on the device to the timezone.
Avoid java.util.Date/.Calendar
The java.util.Date/.Calendar classes bundled with Java (and Android) are notoriously troublesome, flawed in both design and implementation.
Joda-Time
The Joda-Time library is the way to go. This library inspired the java.time package now built into Java 8 (not available on Android).
UTC
As other answers suggested, the best practice (generally) is to keep your business logic and data storage/communication in UTC time zone (which some think of as no time zone or an "anti" time zone). Adjust to a specific time zone only when expected by the user or data-consumer.
Time Zone
The DateTime class in Joda-Time represents a date-time value along with an assigned time zone.
Note that it is best to specify a time zone in all your operations. Otherwise you will be implicitly relying on the JVM’s current default time zone. This is risky because that zone can change – even at runtime at any moment by any code in any thread of any app running within your app’s JVM. And use proper time zone names, never the 3-4 letter codes.
Example Code
Example code in Joda-Time 2.7.
DateTime sent = DateTime.now( DateTimeZone.getDefault() ) ;
DateTime sentUtc = nowMine.withZone( DateTimeZone.UTC ) ; // Generally, use this for your work, including communicating to other threads and apps and such.
When ready to display to the other user, adjust to the expected time zone.
DateTimeZone zone = DateTimeZone.forID( "America/Montreal" ) ; // Or DateTimeZone.getDefault() if you want to rely on their JVM’s current default. To be absolutely sure of expected time zone, you really must ask the user.
DateTime sentMontréal = sentUtc.withZone( zone );
To generate a textual representation of those date-time objects, search the many Questions and Answers on StackOverflow.com on that subject. Search for terms like "joda" and "DateTimeFormatter" and "DateTimeFormat".