Daylight saving time in java - java

please see if you can tell me how to handle the DST issue in my case.
first, my application is a logistic system and it is for global user,so it involves timezone problem,i will handle it as following when set user local date of booking:
1.when user login application,we could get user's timezone according to login IP,but is is just an offset (i don't remember the term of this stuff) e.g "GMT+08"(BeiJing) or "GMT-06"(Chicago) .
2.before user save booking ,we need to set booking local date,as i can't get user local date direct .so i will get the server date first(in my case,it is BeiJing time),then calculate local date according to server date and user timezone,e.g if user timezone is "GMT-08",server date is 2013-08-29 17:45:00. server timezone is "GMT+08",then i will use server date-8-8 and the result will be 2013-08-29 01:45:00.but as i don't consider the DST,the calculated local date will be difference from the actual date.e.g now in San Francisco,the actual local date will be earlier one hour than the result that i calculated using this way,
i find the java TimeZone have already considered the DST problem,but i need to provide "location" name(e.g US/Alaska,Pacific/Apia) when construct TimeZone . while in my case, what i can get is just the offset.so can you tell me how to fix the DST issue in my case?

Yes, you should use either Joda-Time or the new java.time package in Java 8 (inspired by Joda-Time).
An offset is the number hours-minutes-seconds from UTC (GMT) that is represented by a certain date-time value. West coast is -08:00 (ignoring Daylight Saving Time nonsense), meaning 8 hours behind UTC.
Beware that java.time in its initial release has a small bug where it fails to handle an offset of just hours (such as +08) without minutes (such as +08:00).
A time zone is a history of the past, present, and future changes to the offset used by the people of a particular region.
Use proper time zone names (mostly continent slash city). Avoid the 3 or 4 letter codes, such as EST, which are neither standardized nor unique.
A java.util.Date has no time zone, while a Joda-Time DateTime does.
To get a web browser's time zone, see this question. But often, this does not work well. As you've probably seen, many web sites ask the user to choose a time zone.
Your exact use-case is confusing. Generally the best approach is to use date-time values for UTC, then adjust to user's local time as needed. Usually best for your software to work and store date-times as UTC. Then present a local date-time adjusted to suit the user. In other words, think globally (UTC), present locally (local time zone adjusted).
Usually sysadmins keep their server computers set to UTC (no time zone offset). If your OS (like Mac OS X) does not offer UTC, then use Reykjavik as Iceland uses UTC year-round without any Daylight Saving Time. Likewise, database engines almost always convert date-time values to UTC for storage.
Joda-Time does offer a LocalDate class for when you truly do not care about time zone or time. But often it is better to use a date-time (a DateTime instance), and format for a date-only string as needed.
Example code in Joda-Time 2.3.
DateTimeZone timeZoneChina = DateTimeZone.forID( "Asia/Shanghai" );
DateTime dateTimeChina = new DateTime( 2013, 8, 29, 17, 45, 00, timeZoneChina );
DateTime dateTimeUtc = dateTimeChina.withZone( DateTimeZone.UTC );
DateTime dateTimeParis = dateTimeChina.withZone( DateTimeZone.forID( "Europe/Paris" ) );
DateTimeZone timeZoneUsWestCoast = DateTimeZone.forID( "America/Los_Angeles" );
DateTime dateTimeUnitedStatesWestCoast = dateTimeChina.withZone( timeZoneUsWestCoast );
DateTimeFormatter formatter = ISODateTimeFormat.date();
String outputDateOnlyForUnitedStatesWestCoast = formatter.withZone( timeZoneUsWestCoast ).print( dateTimeUtc );
Dump to console…
System.out.println( "dateTimeChina: " + dateTimeChina );
System.out.println( "dateTimeUtc: " + dateTimeUtc );
System.out.println( "dateTimeParis: " + dateTimeParis );
System.out.println( "dateTimeUnitedStatesWestCoast: " + dateTimeUnitedStatesWestCoast );
System.out.println( "outputDateOnlyForUnitedStatesWestCoast: " + outputDateOnlyForUnitedStatesWestCoast );
When run…
dateTimeChina: 2013-08-29T17:45:00.000+08:00
dateTimeUtc: 2013-08-29T09:45:00.000Z
dateTimeParis: 2013-08-29T11:45:00.000+02:00
dateTimeUnitedStatesWestCoast: 2013-08-29T02:45:00.000-07:00
outputDateOnlyForUnitedStatesWestCoast: 2013-08-29
java.time
Similar code in java.time.
Current moment in UTC.
Instant instant = Instant.now() ; // Capture the current moment as seen in UTC.
Adjust into a time zone for Chicago area, yielding a ZonedDateTime object.
ZoneId zChicago = ZoneId.of( "America/Chicago" ) ;
ZonedDateTime zdtChicago = instant.atZone( z ) ;
Adjust into China time zone.
ZoneId zShanghai = ZoneId.of( "Asia/Shanghai" ) ;
ZonedDateTime zdtShanghai = zdtChicago.withZoneSameInstant( zChicago ) ;
All three objects (instant, zdtChicago, and zdtShanghai) represent the same moment, the same point on the timeline. Simultaneous, but seen through various wall-clock times.
Apparently you want just the date portion for some purpose, without the time-of-day and without time zone. For that extract a LocalDate object.
LocalDate ld = zdtChicago.toLocalDate() ;
Of course that may be a different date than returned by zdtShanghai.toLocalDate().
You may need to construct a specific moment.
ZonedDateTime zdtShanghai = ZonedDateTime.of( 2013, 8, 29, 17, 45, 0, 0 , zShanghai ) ;
Location and time zone
You said:
i need to provide "location" name
Location has nothing to do with time zone. A businessperson from Québec might want to see a particular schedule in America/Montreal zone while physically traveling in Tokyo Japan.
You can ask the user’s web browser or local JVM for its current default time zone. But ultimately, if critical, you must confirm the desired/expected time zone with the user.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes. Hibernate 5 & JPA 2.2 support java.time.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….

It's a common source of headache
In my experience, location by IP address is not always reliable, for example when people are using corporate VPNs.
You are correct, region-based time zones ("Europe/Paris", "CET") are preferable for properly handling DST.
I solved a similar problem with the following approach :
You associate a precise timezone to each user in your server-side database. When user fills a booking form you display a TZ selector, pre-filled with his default TZ. So he can double check it (IMHO much safer than guessing by IP) and on server side, Dates can be safely converted from local to server time and back.

Joda time might be able to solve your problem:
http://joda-time.sourceforge.net/apidocs/org/joda/time/DateTimeZone.html

Related

How to save a java.nio.file.attribute.FileTime into a PostgreSQL's timestamp column?

I'm trying to understand how to save a file's modification date I received as a java.nio.file.attribute.FileTime into a column in PostgreSQL which is a timestamp.
Reading the PostgreSQL page relating to Java 8 dates & times: https://jdbc.postgresql.org/documentation/head/8-date-time.html
I can just pinpoint this: Note that ZonedDateTime, Instant and OffsetTime / TIME [ WITHOUT TIMEZONE ] are not supported.
In the matching table (see link above) PostgreSQL advices TIMESTAMP [ WITHOUT TIMEZONE ] LocalDateTime but some people discourage you to use this Java class, e.g. http://blog.schauderhaft.de/2018/03/14/dont-use-localdatetime/
And by the way, FileTime can only be converted into either a long (millisecongs) or an Instant (see Java doc).
So what am I supposed to do? I'm lost.
tl;dr
You asked:
how to save a file's modification date I received as a java.nio.file.attribute.FileTime into a column in PostgreSQL
Use the types TIMESTAMP WITH TIME ZONE and OffsetDateTime in JDBC 4.2 or later to store the moment represented by a FileTime object.
myPreparedStatement
.setObject(
… , // Specify number of placeholder `?` in your SQL code.
myFileTime // Your `java.nio.file.attribute.FileTime` object.
.toInstant() // Convert to a `java.time.Instant` object.
.atOffset( // JDBC 4.2 oddly does not require support for `Instant`, so simply convert to an `OffsetDateTime` object. Same moment, both in UTC, so no value added except to match JDBC spec.
ZoneOffset.UTC // We must specify *some* offset, so we might as well use an offset of zero hours-minutes-seconds. The constant `ZoneOffset.UTC` represents just that offset.
) // Returns an `OffsetDateTime` object we can use with JDBC 4.2 compliant drivers.
);
A moment
I can just pinpoint this: Note that ZonedDateTime, Instant and OffsetTime / TIME [ WITHOUT TIMEZONE ] are not supported.
That text is not a Postgres issue, it is a JDBC 4.2 issue. Let me explain.
The three classes Instant, OffsetDateTime, and ZonedDateTime all represent a moment, a specific point on the timeline. Representing a moment requires the context of an offset-from-UTC (a number of hours-minutes-seconds from UTC) or a time zone (a history of past, present, and future changes to the offset used by the people of a particular region).
Instant is always in UTC (an offset of zero hours-minutes-seconds).
OffsetDateTime is a date, a time-of-day, and an offset.
ZonedDateTime is a date, a time-of-day, and a time zone.
Logically, all three of these map to a TIMESTAMP WITH TIME ZONE column in Postgres. Postgres takes any time zone or offset info to adjust into UTC, stores the UTC value, and then discards any provided zone/offset.
So you would think the JDBC spec would require support for all three. But inexplicably, the JDBC team chose to require support only for OffsetDateTime. That was an unfortunate decision as the other two types are more commonly used. At any rate, you can easily convert. Look to the to…, from…, at…, and with… methods.
Instant instant = Instant.now() ;
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ; // Effectively the same thing as an `Instant`, a moment as seen in UTC.
myPreparedStatement.setObject( … , odt ) ;
A particular JDBC driver may support Instant and/or ZonedDateTime as well as OffsetDateTime. But use OffsetDateTime alone if your intention is to write portable code to be used with various drivers.
Storing java.nio.file.attribute.FileTime
Column type
You said:
'm trying to understand how to save a file's modification date I received as a java.nio.file.attribute.FileTime into a column in PostgreSQL which is a timestamp.
Check the type of your database column.
Your column must be of type TIMESTAMP WITH TIME ZONE.
The other type TIMESTAMP WITHOUT TIME ZONE cannot represent a moment, so it cannot store the value of your FileTime object.
Java type
As you mentioned, the java.nio.file.attribute.FileTime class added a toInstant method in Java 8 and later. Just what we need to store this moment in the database via JDBC 4.2 or later.
Same kind of code as seen above:
Instant instant = myFileTime.toInstant() ;
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ; // Effectively the same thing as an `Instant`, a moment as seen in UTC.
myPreparedStatement.setObject( … , odt ) ;
Or shorter, but not necessarily better:
myPreparedStatement.setObject( … , myFileTime.toInstant().atOffset( ZoneOffset.UTC ) ) ;
Retrieval.
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
If you need an Instant, convert.
Instant instant = odt.toInstant() ;
You said:
In the matching table (see link above) PostgreSQL advices TIMESTAMP [ WITHOUT TIMEZONE ] LocalDateTime
Those two types, TIMESTAMP WITHOUT TIMEZONE and LocalDateTime purposely lack any concept of time zone or offset-from-UTC. As such they cannot represent a moment. So they cannot store your FileTime value as value is a specific point on the timeline.
Adjusting into a time zone
If you want to see a moment through the wall-clock time of a particular time zone, apply a ZoneId to get a ZonedDateTime object. Same moment, same point on the timeline, different wall-clock time & date.
Instant instant = myFileTime.toInstant() ;
ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
Generate text to represent that value. We can ask java.time to automatically localize such text.
Locale locale = Locale.CANADA_FRENCH ;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime​( FormatStyle.FULL ).withLocale( locale ) ;
String output = zdt.format( f ) ;
See this code run live at IdeOne.com. Note how the date and hour differ yet represent the same moment.
instant.toString(): 2020-12-18T00:37:55.704644Z
output: jeudi 17 décembre 2020 à 19 h 37 min 55 s heure normale de l’Est
Date-time handling is tricky
You said:
So what am I supposed to do? I'm lost.
Date-time handling is surprisingly confusing. Our intuitive understanding and quotidian habits are not helpful and actually are counter-productive as programmers doing this work.
The main concept to get very clear is: A moment versus Not a moment.
The completion of a sale transaction, a record being created in the database, or a delivery being dropped at your front door — these are all moments.
Saying that Christmas this year starts on December 25th, 2020 this year is not a moment, as the beginning of that day varies around the world coming earlier in the east and later in the west. Santa starts deliveries in the Pacific islands, and flies westward as the calendar flips to a new day successively hour-by-hour.
Setting a dental appointment in six months that should start at 3 PM regardless of politicians changing that region’s offset-from-UTC — that is not a moment.
Another key concept is that programmers and sys-admins should think of UTC (an offset of zero hours-minutes-seconds) as the one true time. All time zones are but mere variations. While on the job, forget about your local parochial time; keep a clock on your desk set to UTC. Converting back and forth between parochial time and UTC will drive a person batty.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes. Hibernate 5 & JPA 2.2 support java.time.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 brought some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android (26+) bundle implementations of the java.time classes.
For earlier Android (<26), a process known as API desugaring brings a subset of the java.time functionality not originally built into Android.
If the desugaring does not offer what you need, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above) to Android. See How to use ThreeTenABP….

Storing appointments in a SQL database such as Postgres for use with java.time framework

Let's say that we have an appointment in Milan Italy happening on 01/23/2021 21:00 "Europe/Rome". This appointment is saved to the database in UTC in a column of a type akin to the SQL-standard type TIMESTAMP WITH TIME ZONE.
Now a user living in New York US needs to understand when this appointment will take place. We can show that user the date-time converted to "America/New_York" time zone, or instead, in "Europe/Rome" TZ. Once the user will fly from New York to Milan, he will find both info useful.
The point is to store everything converted into the same TZ reference (UTC), and the manipulate the date-time depending on the goal you have using the java.time framework bundled with modern Java.
Makes sense or there is something wrong/missing?
Makes sense or there is something wrong/missing?
It depends on the kind of appointment.
There are two kinds of appointments:
A moment, a specific point on the timeline, ignoring any changes to time zone rules.Example: Rocket launch.
A date and time-of-day that should adjust for changes to time zone rules.Example: Medical/Dental visit.
Moment
If we are booking the launch of a rocket, for example, we do not care about the date and the time-of-day. We only care about the moment when (a) the heavens align, and (b) we expect favorable weather.
If in the intervening time the politicians change the rules of the time zone in use at our launch site or at our offices, that has no effect on our launch appointment. If politicians governing our launch site adopt Daylight Saving Time (DST), the moment of our launch remains the same. If the politicians governing our offices decide to change the clock a half-hour earlier because of diplomatic relations with a neighboring country, the moment of our launch remains the same.
For such an appointment, yes, your approach would be correct. You would record the appointment in UTC using a column of type TIMESTAMP WITH TIME ZONE. Upon retrieval, adjust into any time zone the user prefers.
Databases such as Postgres use any time zone info accompanying an input to adjust into UTC, and then disposes of that time zone info. When you retrieve the value from Postgres, it will always represent a date with time-of-day as seen in UTC. Beware, some tooling or middleware may have the anti-feature of applying some default time zone between retrieval from database and delivery to you the programmer. But be clear: Postgres always saves and retrieves values of type TIMESTAMP WITH TIME ZONE in UTC, always UTC, and offset-from-UTC of zero hours-minutes-seconds.
Here is some example Java code.
LocalDate launchDateAsSeenInRome = LocalDate.of( 2021 , 1 , 23 ) ;
LocalTime launchTimeAsSeenInRome = LocalTime.of( 21 , 0 ) ;
ZoneId zoneEuropeRome = ZoneId.of( "Europe/Rome" ) ;
// Assemble those three parts to determine a moment.
ZonedDateTime launchMomentAsSeenInRome = ZonedDateTime.of( launchDateAsSeenInRome , launchTimeAsSeenInRome , zoneEuropeRome ) ;
launchMomentAsSeenInRome.toString(): 2021-01-23T21:00+01:00[Europe/Rome]
To see the same moment in UTC, convert to an Instant. An Instant object always represents a moment as seen in UTC.
Instant launchInstant = launchMomentAsSeenInRome.toInstant() ; // Adjust from Rome time zone to UTC.
launchInstant.toString(): 2021-01-23T20:00:00Z
The Z on the end of the above string example is standard notation for UTC, and is pronounced “Zulu”.
Unfortunately the JDBC 4.2 team neglected to require support for either Instant or ZonedDateTime types. So your JDBC driver may or may not be able to read/write such objects to your database. If not, simply convert to OffsetDateTime. All three types represent a moment, a specific point on the timeline. But OffsetDateTime has support required by JDBC 4.2 for reasons that escape me.
OffsetDateTime odtLaunchAsSeenInRome = launchMomentAsSeenInRome.toOffsetDateTime() ;
Writing to database.
myPreparedStatement.setObject( … , odtLaunchAsSeenInRome ) ;
Retrieval from database.
OffsetDateTime launchMoment = myResultSet.getObject( … , OffsetDateTime.class ) ;
Adjust to the New York time zone desired by your user.
ZoneId zoneAmericaNewYork = ZoneId.of( "America/New_York" ) ;
ZonedDateTime launchAsSeenInNewYork = launchMoment.atZoneSameInstant( zoneAmericaNewYork ) ;
launchAsSeenInNewYork.toString(): 2021-01-23T15:00-05:00[America/New_York]
You can see all of the above code run live at IdeOne.com.
By the way, tracking past events are also treated as a moment. When did the patient actually arrive for appointment, when did the customer pay the invoice, when did a new hire sign their documents, when did the server crash… all these are tracked as a moment in UTC. As discussed above, usually that would be an Instant, though ZonedDateTime & OffsetDateTime also represent a moment. For the database use TIMESTAMP WITH TIME ZONE (not WITHOUT).
Time-of-day
I expect most business-oriented apps are focused on appointments of the other type, where we aim at a date with a time-of-day rather than a specific moment.
If the user makes an appointment with their health care provider to review the results of a test, they do so for a particular time-of-day on that date. If in the meantime the politicians change the rules of their time zone, moving the clock ahead or behind an hour or half-hour or any other amount of time, the date and time-of-day of that medical appointment remain the same. In actuality, the point of the timeline of the original appointment will be changed after the politicians change the time zone, shifting to an earlier/later point on the timeline.
For such appointmentss, we do not store the date and time-of-day as seen in UTC. We do not use the database column type TIMESTAMP WITH TIME ZONE.
For such appointments, we store the date with time-of-day without any regard to time zone. We use a database column of type TIMESTAMP WITHOUT TIME ZONE (notice WITHOUT rather than WITH). The matching type in Java is LocalDateTime.
LocalDate medicalApptDate = LocalDate.of( 2021 , 1 , 23 ) ;
LocalTime medicalApptTime = LocalTime.of( 21 , 0 ) ;
LocalDateTime medicalApptDateTime = LocalDateTime.of( medicalApptDate , medicalApptTime ) ;
Write that to the database.
myPreparedStatement.setObject( … , medicalApptDateTime ) ;
Be clear on this: a LocalDateTime object does not represent a moment, is not a specific point on the timeline. A LocalDateTime object represents a range of possible moments along about 26-27 hours of the timeline (the range of time zones around the globe). To give real meaning to a LocalDateTime, we must associate an intended time zone.
For that intended time zone, use a second column to store the zone identifier. For example, the strings Europe/Rome or America/New_York. See list of zone names.
ZoneId zoneEuropeRome = ZoneId.of( "Europe/Rome" ) ;
Write that to the database as text.
myPreparedStatement.setString( … , zoneEuropeRome ) ;
Retrieval. Retrieve the zone name as text, and instantiate a ZoneId object.
LocalDateTime medicalApptDateTime = myResultSet.getObject( … , LocalDateTime.class ) ;
ZoneId medicalApptZone = ZoneId.of( myResultSet.getString( … ) ) ;
Put those two pieces together to determine a moment represented as a ZonedDateTime object. Do this dynamically when you need to schedule a calendar. But do not store the moment. If the politicians redefine the time zone(s) in the future, a different moment must be calculated then.
ZonedDateTime medicalApptAsSeenInCareProviderZone = ZonedDateTime.of( medicalApptDateTime , medicalApptZone ) ;
The user is traveling to New York US. They need to know when to call the health care provider in Milan Italy according to the clocks on the wall in their temporary location of New York. So adjust from one time zone to another. Same moment, different wall-clock time.
ZoneId zoneAmericaNewYork = ZoneId.of( "America/New_York" ) ;
ZonedDateTime medicalApptAsSeenInNewYork = medicalApptAsSeenInCareProviderZone.withZoneSameInstant( zoneAmericaNewYork ) ;
tzdata
Be aware that if the rules of your desired time zones may be changing, you must update the copy of time zone definitions on your computers.
Java contains its own copy of the tzdata, as does the Postgres database engine. And your host operating system as well. This particular code shown here requires only Java to be up-to-date. If you use Postgres to make time zone adjustments, its tzdata must also be up-to-date. And for logging and such, your host OS should be kept up-to-date. For proper clock-watching by the user, their client machine's OS must also be up-to-date.
Beware: Politicians around the world have shown a penchant for changing their time zones with surprising frequency, and often with little forewarning.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes. Hibernate 5 & JPA 2.2 support java.time.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 brought some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android (26+) bundle implementations of the java.time classes.
For earlier Android (<26), a process known as API desugaring brings a subset of the java.time functionality not originally built into Android.
If the desugaring does not offer what you need, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above) to Android. See How to use ThreeTenABP….
A very simple solution would be to leave the conversion to PostgreSQL. If you set the timezone parameter correctly for each session and use timestamp with time zone PostgreSQL will automatically show the timestamp to the New York user in New York time.

How to convert a local dateTime Object to a UTC java.util.Date

I'm all clear on the fact that java.util.Date doesn't have timezone and why so.
I've an application where the user has set his TimeZone, and when he selects Date in a DateTime picker, the component returns a Date object to me.
I then need to modify the date as to save the UTC equivalent in database.
It's pretty simple to get a Date object representing UTC date for a local timezone with org.joda.time :
public static final Date getTimeZoneDependantDate(Date pDateUtc, String pUserTimezoneValue) {
// Build the DateTime Object
DateTime originalDate = new DateTime(pDateUtc.getTime(), DateTimeZone.forID(PREF_TIMEZONE_DEF_VALUE));
// Convert the Date
DateTime convertedDate = originalDate.withZone(DateTimeZone.forID(pUserTimezoneValue));
// Return the localTime associated with the timeZone
return convertedDate.toLocalDateTime().toDate();
}
But I'm stuck on how to do the opposite, change the Date picked by the user (from his timezone perspective) to UTC.
Since LocalDateTime takes the instant and not the local Date as a parameter.
Is there any cleaner way than to parse String ?
tl;dr
You do not provide enough info. Report:
The results of this: myJavaUtilDate.toInstant().toString()
The inputs to the component
The current default time zone of the app
Details
You do not really give enough information about your problem. Are you getting a correct date-time value in UTC via the java.util.Date object from your GUI component or not?
If the user in Québec time zone of America/Montreal entered 9 AM on December 1, 2016, and your component is correctly adjusting those values into UTC while producing the java.util.Date object, then you have no problem. The UTC value would be 2 PM in the afternoon for UTC, as America/Montreal is five hours behind UTC on that particular date. Just pass the Date object to the database after converting to a java.sql.Timestamp object.
FYI, both the old date-time classes classes (Date & Calendar etc.) and Joda-Time are now supplanted by the java.time classes. Here is some example code in java.time showing the kind of behavior your component is hopefully employing.
LocalDate ld = LocalDate.of ( 2016 , Month.DECEMBER , 1 );
LocalTime lt = LocalTime.of ( 9 , 0 );
ZoneId z = ZoneId.of ( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.of ( ld , lt , z );
Instant instant = zdt.toInstant (); // UTC
System.out.println ( "zdt.toString(): " + zdt );
System.out.println ( "instant.toString(): " + instant );
zdt.toString(): 2016-12-01T09:00-05:00[America/Montreal]
instant.toString(): 2016-12-01T14:00:00Z
The Z on the end of the string is short for Zulu and means UTC.
Given the unfortunate behavior of java.util.Date::toString to apply your current default time zone while generating the string, I suggest you convert your Date to an Instant so you can get a clear reading of its value.
Instant instantConvertedFromDateOfComponent = myJavaUtilDate.toInstant();
If after this step you do indeed see 2 PM in the afternoon, then all is well and your component is performing well.
If your component is acting badly, ignoring the issue of time zone and reporting your user’s input as if the user intended UTC as their own zone, then you will see 2016-12-01T09:00:00Z. That is a problem. The workaround is to make the time zone adjustment yourself. Extract the “local” (zone-less) values, then apply the intended time zone.
To get the “local” date and time, first convert to OffsetDateTime object.
OffsetDateTime odt = instantConvertedFromDateOfComponent.atOffset( ZoneOffset.UTC );
LocalDateTime ldt = odt.toLocalDateTime(); // 2016-12-01T09:00:00Z
ZonedDateTime zdt = ldt.atZone( z ); // 2016-12-01T09:00-05:00[America/Montreal]
If your JDBC driver complies with JDBC 4.2 or later, you may be able to pass these java.time types directly. If not, convert to java.sql types via new methods added to the old classes. Discussed already many times on Stack Overflow, so search for more info.
The server’s current default time zone should be irrelevant to your programming. Always specify explicitly the desired/expected time zone in optional arguments rather than rely implicitly on default.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
Java SE 8 and SE 9 and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
The best way of transmitting and saving the date over network is in the form of timestamp (date in milliseconds) this timestamp does not need any timezone information. But after fetching the date in the form of timestamp use it create date object, If you want to show the date in the UTC format then only you need to convert it.

Timezone issue while constructing java.util.Date object from timestamp

I am facing an issue of Timezone. let me try to describe:
My Web application & DB is running on a server of having different timezone(Europe/Madrid i.e. UTC+1) than my local timezone(India/Kolkata i.e. UTC+5:30).
Lets say my local current time is: Wed Jan 15 14:35:00 IST 2014 and
that server current time is: Wed Jan 15 10:05:00 CET 2014 i.e. lag by 4:30 hrs.
Now when I am trying to save a date time on the DB using calendar selection from my web page (GUI) lets say, the date time I am selecting is: Wed Jan 15 18:30:00 , the final date that is getting saved in DB is becoming Wed Jan 15 14:00:00 (see the difference exactly 4:30 hrs lag time).
let me tell you the coding part of the above flow.
After selection from calendar of my web page -> passing the timestamp(in long) of the selected date time to my server side controller -> at server side, I am constructing java.util.Date object and saving to DB like below:
java.util.Date newDt = new java.util.Date(timeStampInMillis);
Here, timeStampInMillis is in long which I converted from the datetime selected in GUI.
Here it is saving the given timestamp in the current Timezone(UTC + 01:00) of that server and that is how the saved datetime is getting lagged by 4:30 Hrs.
But I want to save as it is i.e. the date time selected from calendar GUI.
I have some couple of solution like, instead of passing timestamp for constructing Date object in my server side controller, I can pass the String representation of the selected date time from my calendar GUI and then parse the format and save into DB.
But I am wondering if there is anything I can do with Timezone APIs.
Hope my problem is clear to you. If not, please clarify your doubt.
Need your help...
Thanks.
Unclear Question
Your question could be better written. You should try to narrow it down to a very specify example. You don't even specify the milliseconds value under discussion.
Server Time
Servers should almost always be set to a UTC/GMT time zone without Daylight Saving Time. On some systems such as Mac OS X, that is difficult. In that case, set time zone of machine to "Atlantic/Reykjavik" because Iceland stays on UTC/GMT year-round without any Daylight Saving Time nonsense.
Avoid java.util.Date
The java.util.Date & .Calendar classes bundled with Java are notoriously troublesome.
One of the pain points is that while a Date has no time zone assigned, its toString method uses the default time zone in rendering the string. So to the naïve programmer it seems like Date has a time zone when it does not.
Use either the Joda-Time library or the new java.time.* classes bundled with Java 8. Search StackOverflow for many examples of both.
Think Globally, Present Locally
Most of your business logic and your database storage should all be done in UTC/GMT (no time zone offset). A competent database such as Postgres will do so by default.
Only switch to a time zone for presentation to a user, as a general rule.
Time Zone
Always specify a time zone. Do not rely on default time zones as that causes surprises in production or any time machines change their time zone.
Avoid the three letter codes, as they are neither standardized nor unique. Use proper time zone names.
Look up your time zone names in a list like this one (slightly outdated, read details). Your mention of "India/Kolkata" in your question is, I believe, incorrect. Should be "Asia/Kolkata".
ISO 8601
If you must serialize, use only the ISO 8601 format. This format is human-readable, unambiguous, and clearly defined.
Example for India time zone: 2014-01-19T12:38:31+05:30
Example for UTC/GMT "Zulu": 2013-11-22T18:28.023Z
java.sql.* Classes
Use the java.sql.* classes for communicating to your database via JDBC.
You construct a java.sql.Timestamp object by passing the milliseconds since 1970 began. In Joda-Time, call getMillis to obtain a value to pass.
Avoid Milliseconds
Generally, I prefer to avoid dealing with milliseconds for tracking time. People tend to get into trouble since some systems track time from an epoch in seconds, milliseconds, or nanoseconds. Furthermore, there are many epochs in use, not always the Unix-style of first day of 1970.
I try to pass around either:
Date-time objects, such as Joda-Time DateTime instances
ISO 8601 strings.
Example Code
But if you are sure your milliseconds value represents the true number of milliseconds since the first day of 1970 in UTC/GMT, then use this kind of code with Joda-Time. Note the 'L' flagging the number as a long integer.
DateTime dateTime = new DateTime( 1390276603054L );
DateTime dateTimeSpain = dateTime.toDateTime( DateTimeZone.forID( "Europe/Madrid" ) );
DateTime dateTimeIndia = dateTime.toDateTime( DateTimeZone.forID( "Asia/Kolkata" ) );
DateTime dateTimeUtcGmt = dateTime.toDateTime( DateTimeZone.UTC );
// For database.
java.sql.Timestamp timestamp = new java.sql.Timestamp( dateTimeSpain.getMillis() );
Dump to console…
System.out.println( "dateTime (default time zone): " + dateTime );
System.out.println( "dateTimeSpain: " + dateTimeSpain );
System.out.println( "dateTimeIndia: " + dateTimeIndia );
System.out.println( "dateTimeUtcGmt: " + dateTimeUtcGmt );
System.out.println( "timestamp: " + timestamp ); // "toString" uses default time zone.
When run…
dateTime (default time zone): 2014-01-20T19:56:43.054-08:00
dateTimeSpain: 2014-01-21T04:56:43.054+01:00
dateTimeIndia: 2014-01-21T09:26:43.054+05:30
dateTimeUtcGmt: 2014-01-21T03:56:43.054Z
timestamp: 2014-01-20 19:56:43.054
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
timestamp in millis has no timezone. If you create new Date() at the same time in Kolkata and Madrid the Dates will have the same timestamp in millis. The problem can rise only when you interprete textual representation. Again, if textual represenation includes timezone like this Wed Jan 15 14:35:00 IST 2014 SimpleDateFormat.parse in Madrid and Kolkata will produce Date object with the same timestamp in millis.

Time zone in Java

This may be a very basic question, but i could'nt find any satisfactory answers.Hope my doubts gets clear on stackoverflow.
Q 1. Suppose i have time in a different timezone and i want to convert it to a different timezone, what is the way to do it in Java?
Q 2. Is there any way to get timezone using JavaScript?
Q 3. A timezone is just the representation of time in a particular zone, but actually every zone is at the same time,just representation wise it may be different depending on geographical conditions. - Is this understanding Correct?
possible duplicate link
Suppose i have time in a different timezone and i want to convert it to a different timezone, what is the way to do it in Java?
Create a formatter and set the timezone in there.
Internally, java.util.Date just stores milliseconds since the Epoch in the UTC timezone.
When you use Date.toString() or new SimpleDateFormat() without a timezone, then the default timezone of your VM is used.
So in a sense, Java always converts to your current/default timezone (unless you happen to be in UTC).
Is there any way to get timezone using Java Script?
It depends. You can use getTimezoneOffset() but that gives you only the offset. There is no API to get the client's OSs timezone ID (like UTC, Europe/Berlin, etc.)
A timezone is just the representation of time...
Not really. See above.
Q 1. Suppose i have time in a different timezone and i want to convert it to a different timezone, what is the way to do it in Java?
The modern way is with the java.time classes.
Firstly, do much of your work in UTC. Apply a time zone only where necessary, such as presentation to a user.
The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds.
Instant instant = Instant.now();
If you have only an offset-from-UTC rather than a time zone, apply a ZoneOffset to get a OffsetDateTime.
ZoneOffset offset = ZoneOffset.ofHours( -4 );
OffsetDateTime odt = instant.atOffset( offset );
A time zone is an offset-from-UTC (a specific number of hours, minutes, and seconds) plus a set of rules for handling anomalies such as Daylight Saving Time (DST). Represent a time zone with a ZoneId object. Specify a proper time zone name. 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(!).
Apply a ZoneId to get a ZonedDateTime.
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );
You can apply other time zones to either the Instant or the ZonedDateTime.
ZoneId zParis = ZoneId.of( "Europe/Paris" );
ZonedDateTime zdtParis = zdt.withZoneSameInstant( zParis );
Q 2. Is there any way to get timezone using JavaScript?
The issue of determining a time zone from a web browser has been handled countless times on Stack Overflow already.
So I'll skip this, except to say the upshot: No, not really in a reliable way; When important to know the time zone precisely you must ask the user herself.
Q 3. A timezone is just the representation of time in a particular zone, but actually every zone is at the same time,just representation wise it may be different depending on geographical conditions. - Is this understanding Correct?
No, a time zone is not a date-time moment.
A time zone adds meaningful context to a date-time in the same way that a currency designation adds meaningful context to an amount of money. A date-time without a time zone is just a rough idea of possible moments, not a precise point on the timeline. Noon at Auckland is earlier than noon in Kolkata which is earlier than noon in Paris which is earlier than noon in Montréal Québec.
You can think of it as pseudo-math statement:
Time Zone = ( Offset-from-UTC + set-of-rules-for-anomalies )
An example of an imaginary time zone:
An offset might be “one hour ahead of UTC”, plus
This set of rules: “On this date we will engage DST, on this date we will disengage DST, on this date during World War II we did shift ahead one hour, on this date after World War II we shifted back one hour, on this date our government shifted clocks forward a half-hour to make us distinct from our arch-rival neighbor country, …”.
You can apply a time zone to a point on the timeline. Like looking at art through a lens, it changes your perception but not the artifact itself. Looking at a point on the timeline through the lens of a time zone distorts the time-of-day and possibly the date into that of a particular community’s wall-clock time.
Another pseudo-math equation as a way of thinking about the class representations of a time zone and a moment on the timeline:
ZonedDateTime = Instant + ZoneId
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Using a JDBC driver compliant with JDBC 4.2 or later, you may exchange java.time objects directly with your database. No need for strings nor java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
I can answer to your second question and correct the Aaron Digulla very complete response
Is there any way to get timezone using Java Script?
try to use this library, it will return a TimeZone ID with particular limitation (menthioned in the developer's page):
https://bitbucket.org/pellepim/jstimezonedetect

Categories

Resources