I have a Java SE server application with a Saas website and registered users.
I have many events that occur on my server in different days.
Time is registered in localhost in a long number via SYSTEM.currentTimeMillis()/1000
Registered users can check these events time from their respective country and they need to see the correct time based on their timezone (not server timezone) through the website.
How do I show them the historical time of the events in their timezone?
Any idea about how you would deal with this situation?
Easiest way is to use http://momentjs.com/timezone/. Idea is following - you send sth like this in html markup
<div class="raw-datetime">2014-12-01 12:00:00 UTC+03:00</div>
And after page loads - you run javascript that adjusts all raw datetime to browser timezone.
java.time
First you need to determine the user’s time zone. Search on StackOverflow to learn that ultimately the best way to do that is to ask the user. You can try to use JavaScript on the browser to auto-detect a time zone, but there are issues.
You need to arrive at a proper time zone name, usually a continent/cityOrRegion such as America/Montreal or Asia/Kolkata. Never use those 3-4 letter codes like EST or IST as they are neither standardized nor unique.
To localize a date-time you need to know the user’s Locale, a human language and a set of cultural norms.
With a time zone in hand, use the new java.time framework built into Java 8 and later. Inspired by Joda-Time, defined by JSR 310, and extended by the ThreeTen-Extra project.
long epochSeconds = … ;
Instant instant = Instant.ofEpochSeconds( epochSeconds );
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant, zoneId);
Locale locale = Locale.CANADA_FRENCH;
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( locale );
String output = zdt.format( formatter );
First of all, we will use UTC as a default and unique time zone in the system. Because, the time never go back or go to the future in UTC. There is no time shift for daylight saving.
So, all applications (applications which we develop and has timezone support for their users) environment require a JVM parameter, which provides a UTC based environment.
Timezone JVM parameter usage
-Duser.timezone=UTC
For Views
For views, the date/time object should be rendered according to the specified time-zone. For Java world, this is handled by formatDate tld in jstl.
Every project contains its own timezone holding logic itself.
User.timeZone : for admin panels
Some fmt:formatDate example
<fmt:formatDate value="${someDateTime}" timeZone="${user.timeZone}" pattern="MMM dd, yyyy - HH:mm:ss.S"/>
For further information about formatDate taglib please see check the link or google it.
For Forms (Getting the date / time data from the user)
When you getting date information via forms the you need to consider time zone and perform the time conversion. The conversion direction is User Time zone to UTC.
The time in database should be in UTC time zone.
Motto is save it globally; show it locally :)
EDIT:
Hold timezone as a subfield of User object and set it to your formatter when you want to show the time, you can use it in JavaSE.
SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm");
formatter.setTimeZone(TimeZone.getTimeZone(user.getTimeZone()));
Related
I'm using IntelliJ (Kotlin and Java language), I'm trying to get a report of time by using query from my database and send that to the browser (I'm using Postman to see the result).
When I debug my code and go through the result from the query the timezone is ok like the way I want it, its even show -7 (the difference time between me and the UTC) but when it comes to the browser (Postman) it's showing UTC time and +0000, for example:
"date": "2017-10-12T15:00:33.000+0000"
instead of
"date": "2017-10-12T15:00:33.000+0007".
I tried many options and waste around 6 hours to find the solution but nothing work.
Postgres stores a TIMESTAMP WITH TIME ZONE in UTC, discarding the passed zone after using it to make the adjustment into UTC. Note that this is Postgres-specific behavior – databases vary widely in their date-time handling, and the SQL spec barely touches on the subject.
As commented by Marlowe, if you need to remember the time zone captured from data-entry, you will need to store that in another column. Capture a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
➠ Here's the rub: A Postgres session in an interactive tool such as pgAdmin dynamically applies a default time zone after fetching the UTC value. While well-intentioned, this is an anti-feature in my opinion as it obscures the true nature of the stored data.
Fetch the value in UTC using the modern java.time classes.
Instant instant = myResultSet.getObject( … , Instant.class ) ;
Adjust to your desired time zone.
ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
Generate a string for the web browser using the DateTimeFormatter class. Note the automatic localization features there.
All this has been covered many times on Stack Overflow. Search to learn more.
Solution: so i found the solution to my problem here:
Overriding BeanPropertyRowMapper to Support JodaTime DateTime
in shortly, timestamp type doesn't work well with timezone so i changed it to DateTime in Joda and wrapped the result of the query by costumed Bean (from the link i posted)
Greetings Stack Overflow,
I am running into a strange issue with an application I am implementing for a foreign office located in Athens. When built, the application is a .war file that gets deployed on a Tomcat instance.
Just for some background information, this same application works successfully on several different OS (Ubuntu 12.04, Windows Server 2012 R2, etc.) both in the US and other countries with different Java/Tomcat configurations.
However the OS I am using to install the application for Athens is Windows Server 2008 R2. Installed on this server is Java JRE 1.8.0_111 which is utilized by Tomcat 8.5.4. This server is located in Athens.
Everything works fine with the application except for anywhere I am submitting a date field to my controller methods. When attempting to submit the date string to my controller throughout various different sections of the application, I get the following message:
Failed to convert the value of 'java.lang.String' to required type'java.util.Date';
nested exception is java.lang.illegalArgumentException: Could not parse text
[7/28/2017 7:00 AM] into any available date input formats.
Keep in mind that when I deploy this application to a Tomcat instance on another server, everything works fine and I do not receive this error message.
In an attempt to get around this error, I decided to change the type of one of my Request Parameters from:
#RequestParam("date") Date date
to
#RequestParam("date") String dateString
I then used Java SimpleDateFormat to convert the String to a Date:
SimpleDateFormat sdf_date = new SimpleDateFormat("MM/dd/yyyy hh:mm a");
String startDate = dateString;
Date date = sdf_date.parse(startDate);
The date string being passed to the above function is:
11/25/2017 12:00 pm
I tested this on several test servers with different OS/Tomcat configurations and it worked like a charm. However when testing on the Windows 2008 R2 server located in Athens I still received an error. I no longer received the above error, but I did receive the following:
java.text.ParseException: Unparseable date: "11/25/2017 12:00 pm"
I am unsure why this same exact Java code would be able to parse the same date using the same SimpleDateFormat pattern on some servers but not others. This seems very strange to me.
Please let me know if you need any additional information and I will be happy to clarify.
Thank you!
EDIT: Screenshot of Server Side Debug on Server in Athens:
'dateString' that is being passed to the controller method
Greece doesn't use the same am/pm designations as many other countries that speak Latin based languages. Greece instead uses π.µ. and µ.µ. Consequently, when the SimpleDateFormat doesn't receive a locale, it assumes it is the same as the computer running the program.
To fix this, try something such as the below:
SimpleDateFormat sdf_date = new SimpleDateFormat("MM/dd/yyyy hh:mm a", new Locale("en", "US"));
String startDate = dateString;
Date date = sdf_date.parse(startDate);
This will use the English Language with US locale on this server. You'll still need to make sure this is the format being passed in the input in every scenario though.
tl;dr
Instant.parse( "2017-11-25T12:00:00Z" )
Details
The Answer by Smith is correct.
In addition, three more issues. Addressing these will eliminate your problems of wrestling localized text formats.
Time zones
You are ignoring crucial issue of time zone. If not specified, you are relying implicitly on the JVM’s current default time zone. That default can vary, even during runtime(!), so better to specify explicitly you desired/expected time zone.
Generally best to use UTC unless you have a specific reason.
ISO 8601
The ISO 8601 standard defines practical unambiguous formats for text representing date-time values.
For a moment in the timeline in UTC, use YYYY-MM-DDTHH:MM:SS.SSSSSSSSSZ where the T separates the date portion from the time portion, the Z is short for Zulu and means UTC, and the time uses 24-hour clock (no AM/PM).
Use these standard formats when serializing date-time values to text.
java.time
You are using troublesome old date-time classes that are now legacy, supplanted by the modern java.time classes.
The Instant class represents a moment in the timeline in UTC, similar to java.time.Date except with a resolution of nanoseconds rather than milliseconds.
Instant instant = Instant.now() ;
The java.time classes use ISO 8601 formats by default when parsing/generating strings.
String output = instant.toString() ;
And…
Instant instant = Instant.parse( "2017-01-23T12:34:56Z" ) ;
Perhaps you meant noon on the 25th in a certain time zone rather than in UTC.
LocalDateTime.parse( "2017-11-25T12:00:00" ) // LocalDateTime has no concept of time zone or offset-from-UTC. Not on the timeline. Has no real meaning until assigned a time zone.
.atZone( ZoneId.of( "America/New_York" ) ) // Assign a time zone to determine a moment on the timeline, a ZonedDateTime.
.toInstant() // Extract a Instant, always in UTC by definition.
.toString() // Generate a string in standard ISO 8601 format.
I have a jsp page that takes the value from a jquery datapicker and passes it into a search. The user of the site has the opportunity to change their timezone to fit where they are located in the world. I want to take the value searched which is based off the browsers time and format it and show it on screen with the user’s timezone.
The column is expireDate and I use datatables to display the results.
{
"mData":"expireDate",
"mRender":function(source,type,full){
if(-1==source)
return "";
var toDate = new Date(source);
var stringDate = toDate.toString(dateTableFormater);
return stringDate;
I get the value and pass in my own custom formatting, the formatting is based on where the person lives. Each format is different depending on where they live and prevents me from using the simpledateFormat.setTimezoneOffset();
$("#expireFrom").datepicker($.datepicker.regional[plannerLang]);
$("#expireFrom").datepicker( "option", "dateFormat",dateFormater);
$("#expireTo").datepicker($.datepicker.regional[plannerLang]);
$("#expireTo").datepicker( "option", "dateFormat",dateFormater);
I have a dto set up so it gets the users Timezone, I just cant figure out how to implemet that so when the time is sent back to the jsp the timezone has been included in the time.
How do you add/subtract the timezone difference from the date that the browser has gotten?
Adjust for Time Zone Offset
Computers track time in a universal manner, free of time zone information. They use a count of seconds/milliseconds/nanoseconds since an epoch. So adjusting for time zone is not a matter of adding or subtracting to the time itself. It's a matter of adjusting the expression of that time/count as a string.
Joda-Time
The bundled java.util.Date/Calendar classes are notoriously bad in both design and implementation. You should use a competent date-time library instead. Currently, that means Joda-Time. In the future, with Java 8, you can continue with Joda-Time or switch to the new bundled java.time.* classes defined by JSR 310. Those classes are inspired by Joda-Time but are entirely re-architected.
A DateTime instance in Joda-Time knows its own time zone, unlike a java.util.Date.
Server Time
Most programmers find it wiser to use the server's clock rather that obtain time from the user’s machine. Users’ machines are notorious for being out of sync with the correct time. That is less true today with the Internet and NTP servers. Nevertheless, I suggest you stick with server’s clock.
From the user’s machine you should obtain their Locale information, country (culture) and language.
By the way, usually best to work in UTC (no time zone offset) in your business logic and switch to a time zone only for presentation to user.
Example Code For Time Zone
// © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.
// import org.joda.time.*;
// import org.joda.time.format.*;
DateTimeZone timeZone = DateTimeZone.forID( "Europe/Athens" );
DateTime now_Athens = new DateTime( timeZone );
DateTime now_Seattle = now_Athens.toDateTime( DateTimeZone.forID( "America/Los_Angeles" ));
DateTime now_UTC = now_Athens.toDateTime( DateTimeZone.UTC );
Dump to console…
System.out.println( "now_Athens: " + now_Athens );
System.out.println( "now_Seattle: " + now_Seattle );
System.out.println( "now_UTC: " + now_UTC );
When run…
now_Athens: 2014-01-02T20:11:43.657+02:00
now_Seattle: 2014-01-02T10:11:43.657-08:00
now_UTC: 2014-01-02T18:11:43.657Z
Formatting Strings
Joda-Time has many features for rendering strings via formatting:
You can format with Locale-sensitive Long, Medium, Short formatters.
You can define your own formats.
You can go with standard ISO 8601 formats, the default, as seen above.
Example Code For Formatting
DateTimeZone timeZone_Paris = DateTimeZone.forID( "Europe/Paris" );
String nowLocalizedParis = DateTimeFormat.forStyle("LS").withLocale(Locale.FRANCE).withZone( timeZone_Paris ).print( now_UTC );
Dump to console…
System.out.println( "nowLocalizedParis: " + nowLocalizedParis );
When run…
nowLocalizedParis: 2 janvier 2014 19:11
I have users that set their timezone when they create their account. Their account can expire after so many days and the user is able to search for accounts expiring on X day. When the search is run it uses the browser's timezone instead of the users timezone. I have set the timezone like so:
CountryDAO countryDao = new CountryDAO();
String timezone = countryDao.findTimezone(advisor.getPlannerID());
TimeZone.setDefault(TimeZone.getTimeZone(timezone));
DateFormat sdf = new SimpleDateFormat();
sdf.setTimeZone(TimeZone.getDefault());
this code does not set the time zone to the server. I use datapicker to select the date and search but it still uses GMT and not the timezone that is set.
How do I use the time zone that is set?
As the correct answer by Meno Hochschild, java.util.TimeZone.setDefault() is a static method affecting your entire JVM. Not what you want.
Avoid using java.util.Date & Calendar classes. They are badly designed and implemented.
Instead, use the Joda-Time library to manipulate your date-times. Nearly all of Joda-Time is immutable and thread-safe. So it is good for use in servlets & JSP.
Generally you want to work in UTC/GMT, meaning no time zone offset. When presenting to the user, then localize to a particular time zone, format, and language.
I don't know how you are doing it, but it seems that you are determining the user's time zone. Good. (a) Be sure your time zone string is a name of a time zone rather than the outmoded 3-letter code. Those 3-letter codes are neither standardized nor unique. (b) If you are using some kind of JavaScript or other trick to detect and report system settings on the client machine, consider offering the user a way to select a time zone as well. The user may be "thinking" in one time zone while their machine is set for another.
Use that time zone name string to instantiate a DateTimeZone in Joda-Time. Pass that timeZone as an argument to various Joda-Time methods.
DateTimeZone timeZone = DateTimeZone.forId( timeZoneName );
In Joda-Time, a DateTime knows its own time zone (in contrast to a java.util.Date). If you do not specify a time zone, you get the JVM's default time zone. Big tip: Always specify a time zone rather than rely on default, to avoid surprises when running in production.
DateTime dateTimeInUTC = new DateTime( DateTimeZone.UTC );
DateTime dateTimeInParis = dateTimeInUTC.toDateTime( DateTimeZone.forId( "Europe/Paris" ) );
You can add and subtract years, months, days, hours, and such in Joda-Time. And comparison methods test if dates come before or after each other. To find the beginning of a day, call withTimeAtStartOfDay (do not just set hours to zero, as not all days in all zones start at midnight).
DateTime aWeekAgoDateTime = new DateTime( timeZone ).withTimeAtStartOfDay().minusWeeks( 1 ).withTimeAtStartOfDay();
…
boolean isMoreThanWeekOld = someDateTime.isBefore( aWeekAgoDateTime );
Beyond that, I cannot help any more. Your question is not clear. What search? A database? An array or other collection? In JavaScript on client? In Java on server?
TimeZone.setDefault(...) is statically setting the time zone of the JVM (here on the server) for all users. I assume you rather want to set the time zone of the current user session. If so, then you need a special jsp session attribute where you store and read the time zone preference of the user.
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".