Timezone Problem in Java

TimeZone problem in Java

I'm not sure if this answers your question, but this is one way to get "now" in GMT.

import java.text.*
import java.util.*

Calendar cal = new GregorianCalendar();
Date date = cal.getTime();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss z");
formatter.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println(formatter.format(date));

See the Javadoc on SimpleDateFormat for different patterns. Also, you may want to consider Joda Time as it is far superior for dates and times.

java incorrect timezone

Ensure you set the timezone for the JVM when starting the application:

-Duser.timezone="Australia/Sydney"

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

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.

Java problem with Java.util.Date and Java.util.TimeZone

tl;dr

java.time.OffsetDateTime.parse( "2020-04-11T14:52:34.8121672+00:00" ) 

See this code run live at IdeOne.com.

Details

Never use java.util.Date. That flawed class was supplanted years ago by the modern java.time classes defined in JSR 310. Specifically replaced by java.time.Instant.

Avoid setting the JVM’s current default time zone. Doing so immediately affects all other code in all threads of all apps running in that JVM. Write your code such that you never depend on the default time zone. Always specify your desired/expected time zone.

No need to define this custom formatting pattern: "yyyy-MM-dd'T'HH:mm:ss.SSSSSSSXXX". That format is defined in the ISO 8601 standard, used by default in java.time when parsing/generating text.

By convention, the decimal fractions are written in groups of three digits. So suggest to the publisher of your data writing that textual value as 2020-04-11T14:52:34.812167200+00:00 rather than 2020-04-11T14:52:34.8121672+00:00. And congratulate the publisher on using both the hours and the minutes of the offset, as well as the colon. While technically optional in ISO 8601, including them maximizes compatibility with various date-time handling libraries in the real world.

Your format is asking for hundreds of nanoseconds. But the legacy date-time types resolve to mere milliseconds (thousandths of a second). So you were pressing a square peg into a round hole. Fortunately, java.time resolves to nanoseconds (billionths of a second). So we can handle parsing your input.

Parse your particular input as a OffsetDateTime.

OffsetDateTime odt = OffsetDateTime.parse( "2020-04-11T14:52:34.8121672+00:00" ) ;

Generate a string in standard ISO 8601 format.

String output = odt.toString() ;

2020-04-11T14:52:34.812167200Z

Convert to the terrible legacy java.util.Date only if you must. Find new conversion methods added to the old classes.

java.util.Date juDate = Date.from( odt.toInstant() ) ;

All of this has been addressed many many times on Stack Overflow. Please search more thoroughly before posting. And, search to learn more.

Timezone issue in webapp

1

Yes. Usually best practice is to store all your date-time values in UTC. Your business logic should work in UTC.

You may want to also store the value input by user or outside data source as an audit trail or debugging aid. But use UTC for the official record.

Yes the server's time zone should be set to UTC (or, if not possible, use Reykjavík Iceland). But do not depend on this in your programming. Specify your desired time zone in your code rather than rely on defaults.

2

Yes. Convert to a localized time for presentation. Unless, of course, the user prefers UTC.

Think of it as part of localization. When you internationalize, you work with key values in your code. Then upon presentation, you use the key value to look up a localized translation string to display to the user.

3

Non-issue. If by "DST" you mean Daylight Saving Time, the use of a decent date-time library will automatically handle adjustments for DST. Caveat: you need to keep the time zone definition list used by your library up-to-date as governments frequently change the rules.

If adjusting for DST (or time zones) causes confusion or misinformation with your users, then you should be displaying UTC in that case.

4

No. Do not store or work with milliseconds in most cases. Databases and date-time libraries may do so internally, but you should not.

Some nerdy types will suggest tracking milliseconds. But working with date-time as milliseconds is like working with text as byte arrays. We use libraries of code with higher levels of abstraction to handle all the complexities of text (UTF-8, Unicode normalization of diacriticals, etc.) and add helpful methods (search, replace, etc.). So it is with date-time.

Furthermore, using milliseconds will cause confusion and make debugging difficult as you cannot readily make sense of their value. Date-time work is inherently tricky and error-prone. Using milliseconds does not help.

And not all databases and other libraries use milliseconds internally. Some use whole seconds, or microseconds, or nanoseconds. Nor do they all use the same epoch.

5

In Java we have two good date-time libraries: Joda-Time and java.time (Java 8).

The java.time package was inspired by Joda-Time but is re-architected. They share similar concepts, but are not identical. You can use both in your code as long as you are careful with your import statements. Both have their own strengths and weaknesses.

Avoid j.u.Date/.Calendar

Do not use the java.util.Date and .Calendar classes bundled with Java. They are notoriously troublesome, flawed both in design and in implementation. They have been supplanted by Sun/Oracle with the new java.time package.

Both Joda-Time and java.time include handy methods to translate to/from a java.util.Date object for when some other class requires a j.u.Date object.

Bonus Tips

Regarding text formats:

  • Avoid that string format you used in your question. It is unwieldy and difficult to parse.
  • Learn about using various string formats defined by the ISO 8601 standard for textual representations of date-time values.
  • Do not drop that leading zero in the offsets, as you did in your question. That will break code in libraries, and violates standards requirements. Always write +05:30, never +5:30. Make that a habit even when writing prose, not just in your programming code.

Example Code

Example code with Joda-Time 2.3.

Instantiate the date-time, local to a +05:30 offset. I arbitrarily chose Kolkata time zone. You would replace with appropriate one of course.

DateTimeZone timeZoneKolkata = DateTimeZone.forID( "Asia/Kolkata" );
DateTime dateTimeKolkata = new DateTime( 2014, DateTimeConstants.JUNE, 30, 23, 30, 0, timeZoneKolkata );

Adjust the same moment to another time zone with a -03:00 offset. I arbitrarily chose America/Buenos_Aires.

DateTimeZone timeZoneBuenos_Aires = DateTimeZone.forID( "America/Buenos_Aires" );
DateTime dateTimeBuenos_Aires = dateTimeKolkata.withZone( timeZoneBuenos_Aires );

Convert to UTC.

DateTime dateTimeUtc = dateTimeKolkata.withZone( DateTimeZone.UTC );

Java Date problems with TIMEZONE

Solution to this issue.

We made an Custom Deserializer to every object of the type Date.

On ObjectMapperFactory, where we serialize or deserialize, i mapped to another class like this:

 module.addDeserializer(Date.class, new DateDeserializerByDefault());

Then, on this class we did:

private static SimpleDateFormat dateFormatWithoutTimezome = new SimpleDateFormat("yyyy-MM-dd");
private static SimpleDateFormat dateFormatWithTimezone= new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
private static Pattern pattern = Pattern.compile("([0-9]{4})-([0-9]{2})-([0-9]{2})");

@Override
public Date deserialize(JsonParser jparser, DeserializationContext ctxt) throws IOException, JsonProcessingException {
String content = jparser.getValueAsString();
DateFormat format=(pattern.matcher(content).matches()) ? dateFormatWithoutTimezome : dateFormatWithTimezone;

try {
return format.parse(content);
} catch (ParseException e) {
throw new JsonParseException("Date parse failed", jparser.getCurrentLocation(),e);
}
}

And with this, when we receive Dates on diferent format, or with timezone to be stor we can change it to what we want.

I Hope this solution can help, I was stuck on this for 3,5 days. Dates are a pain in the a**.



Related Topics



Leave a reply



Submit