1

I have a linux machine in UTC timezone.

[user@test packages]$ date +'%:z %Z'
+00:00 UTC

Running cat /etc/localtime also seems to indicate that my machine is in UTC timezone;

[user@test ~]$ cat /etc/localtime
f2UTCTZif2UTC
UTC0

However calling logger.info(new Date()) in a application running tomcat under Java 1.7 returns something like Mon Oct 28 01:51:39 HDT 2019

This is very strange, so I created a simple Java program for testing:

import java.util.Date;

class Test
{
        public static void main (String args[])
        {
                Date dt = new Date();
                System.out.println(dt);
        }
}

Compile and run it

[user@test]$ /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.211.x86_64/bin/javac Test.java
[user@test]$ /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.211.x86_64/bin/java Test
Mon Oct 28 02:08:49 HDT 2019

My question is why my Linux utility is return date in UTC format, and yet my Java apps are returning dates in HDT format (I don't even know what HDT is).

Since the app I'm maintaining is legacy, I can't use Joda Time or upgrade to Java8 or higher as this would meant lots of code changes.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
Demeter P. Chen
  • 823
  • 1
  • 7
  • 16
  • What does `/etc/timezone` say? See [Check TimeZone on Linux host](https://cinhtau.net/2015/10/25/europebusingen-check-timezone-on-linux-host/) – Andreas Oct 28 '19 at 11:29
  • **HDT** stands for **Hawaiian Daylight Time**.... is the machine located (or set up as it was) in Hawaii? – Sterconium Oct 28 '19 at 11:29
  • @Sterconium The machines are in a company data center, The machines by rule must be in UTC – Demeter P. Chen Oct 28 '19 at 11:43
  • @Andreas I tried to overwriting `/etc/localtime` with `/usr/share/zoneinfo/UTC`. The machine a RedHat one doesn't have `/etc/timezone` – Demeter P. Chen Oct 28 '19 at 11:45
  • This is one of the points why there is `java.time` from Java 8. It will be a lot harder to get reliable dates and times using `java.util` than migrating to `java.time`. What does `System.out.println(Locale.getDefault().getDisplayCountry());` print on the system that prints the timestamp in HDT? What does `System.out.println(ZoneId.systemDefault().getDisplayName(TextStyle.FULL_STANDALONE, Locale.getDefault()));` print? – deHaar Oct 28 '19 at 11:46
  • 1
    Ok but this does not answer my question: are this machine (or set up as they were) in Hawaii? – Sterconium Oct 28 '19 at 11:46
  • @Sterconium The machines are somewhere in Texas, not Hawaii – Demeter P. Chen Oct 28 '19 at 12:44
  • I recommend you don’t use `Date`. That class is poorly designed and long outdated. Instead use `ZonedDateTime` or just `ZoneId`; both are from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Oct 28 '19 at 18:25
  • 2
    An old-fashioned `Date` hasn’t got a time zone. But that it prints as `HDT` is a sign that the JVM’s time zone setting may be Hawaiian-Aleutian Time. You can check by printing `ZoneId.systemDefault()` and `System.getProperty("user.timezone")`. – Ole V.V. Oct 28 '19 at 18:27

2 Answers2

2

I finally fix it by doing the following:

  • Run ln -fs /usr/share/zoneinfo/UTC /etc/timezone and
  • Modify /etc/sysconfig/clock

I got the idea of looking at /etc/sysconfig/clock after reading this https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6456628

Demeter P. Chen
  • 823
  • 1
  • 7
  • 16
1

tl;dr

Never use the legacy class Date.

  • Instant.now()
    For current moment as seen in UTC.
  • ZonedDateTime.now( ZoneId.of( "Pacific/Honolulu" ) )
    For current moment as seen in a particular time zone.

2020-02-18T05:28:11.146726Z

2020-02-17T19:28:11.146726-10:00[Pacific/Honolulu]

Details

Firstly, you should know that your java.util.Date is actually a moment in UTC but its toString method dynamically applies the JVM's current default time zone while generating the text. Very confusing. One of many reasons to never use this class.

Date, Calendar, and the other legacy date-time classes were supplanted by java.time years ago with the adoption of JSR 310.

Avoid depending on default time zone

Using the java.time classes, you can easily write code that does not depend on a default time zone. You can specify your desired offset-from-UTC or time zone explicitly, whether that be UTC itself (an offset of zero hours-minutes-seconds) or a time zone like Pacific/Honolulu.

UTC

If you want to track a moment in UTC, use Instant.

Instant instant = Instant.now() ;

The Instant::toString method generates text in standard ISO 8601 format. The formats defined by this standard are designed for data exchange.

String output = instant.toString() ;

output: 2020-02-18T05:28:11.146726Z

The Z on the end means UTC, and is pronounced “Zulu”.

Zoned

If you want to see that same moment by the wall-clock time used by the people in Hawaii, apply a ZoneId to get a ZonedDateTime.

Never use the 2-4 letter abbreviation such as HDT or EST or IST as they are not true time zones, not standardized, and not even unique(!).

Specify a proper time zone name in the format of Continent/Region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland.

ZoneId z = ZoneId.of( "Pacific/Honolulu" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

The ZonedDateTime::toString method wisely extends the ISO 8601 format by appending the name of the time zone is square brackets.

String output = zdt.toString() ;

See this code run live at IdeOne.com.

outputZdt: 2020-02-17T19:28:11.146726-10:00[Pacific/Honolulu]


Table of date-time types in Java, both modern and legacy


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.

Where to obtain the java.time classes?

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154