[java] Get GMT Time in Java

In Java, I want to get the current time in GMT.

I tried various options like this:

Date date = new Date();
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
date1 = calendar.getTime();

But the date is always is interpreted in my local time zone.

What am I doing wrong and how can I convert a java Date to GMT?

This question is related to java date gmt

The answer is


You can’t

First, you are asking the impossible. An old-fashioned Date object hasn’t got, as in cannot have a time zone or GMT offset.

But the date is always is interpreted in my local time zone.

I suppose that you have printed the Date or done something else that implicitly calls it toString method. I believe that this is the only time that the Date is interpreted in your time zone. More precisely in the current default time zone of your JVM. On the other hand this is unavoidable. Date.toString() does behave in that way, it picks up the JVM’s time zone setting and uses it for rendering the string to be returned.

You can with java.time

You shouldn’t use a Date, though. That class is poorly designed and fortunately long outdated. Also java.time, the modern Java date and time API that replaces it, has a class or two for dates and times with offset from GMT or UTC. I am considering GMT and UTC synonymous for now, strictly speaking they are not.

    OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC);
    System.out.println("Time now in UTC (GMT) is " + now);

When I ran this snippet just now, the output was:

Time now in UTC (GMT) is 2019-06-17T11:51:38.246188Z

The trailing Z of the output means UTC.

Links


After java 8, you may want to get the formatted time as below:

DateTimeFormatter.ofPattern("HH:mm:ss.SSS").format(LocalTime.now(ZoneId.of("GMT")));

Useful Utils methods as below for manage Time in GMT with DST Savings:

public static Date convertToGmt(Date date) {
    TimeZone tz = TimeZone.getDefault();
    Date ret = new Date(date.getTime() - tz.getRawOffset());

    // if we are now in DST, back off by the delta.  Note that we are checking the GMT date, this is the KEY.
    if (tz.inDaylightTime(ret)) {
        Date dstDate = new Date(ret.getTime() - tz.getDSTSavings());

        // check to make sure we have not crossed back into standard time
        // this happens when we are on the cusp of DST (7pm the day before the change for PDT)
        if (tz.inDaylightTime(dstDate)) {
            ret = dstDate;
        }
    }
    return ret;
}

public static Date convertFromGmt(Date date) {
    TimeZone tz = TimeZone.getDefault();
    Date ret = new Date(date.getTime() + tz.getRawOffset());

    // if we are now in DST, back off by the delta.  Note that we are checking the GMT date, this is the KEY.
    if (tz.inDaylightTime(ret)) {
        Date dstDate = new Date(ret.getTime() + tz.getDSTSavings());

        // check to make sure we have not crossed back into standard time
        // this happens when we are on the cusp of DST (7pm the day before the change for PDT)
        if (tz.inDaylightTime(dstDate)) {
            ret = dstDate;
        }
    }
    return ret;
}

This is pretty simple and straight forward.

Date date = new Date();
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
Calendar cal = Calendar.getInstance(TimeZone.getDefault());
date = cal.getTime();

Now date will contain the current GMT time.


The following code will get the date minus timezone offset:

protected Date toGmt0(ZonedDateTime time) {
    ZonedDateTime gmt0 = time.minusSeconds(time.getOffset().getTotalSeconds());
    return Date.from(gmt0.toInstant());
}

@Test
public void test() {

    ZonedDateTime now = ZonedDateTime.now();
    Date dateAtSystemZone = Date.from(now.toInstant());
    Date dateAtGmt0 = toGmt0(now);

    SimpleDateFormat sdfWithoutZone = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
    SimpleDateFormat sdfWithZoneGmt0 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.ITALIAN);
    sdfWithZoneGmt0.setTimeZone(TimeZone.getTimeZone("GMT"));

    System.out.println(""
            + "\ndateAtSystemZone          = " + dateAtSystemZone
            + "\ndateAtGmt0                = " + dateAtGmt0
            + "\ndiffInMillis              = " + (dateAtSystemZone.getTime() - dateAtGmt0.getTime())
            + "\n"
            + "\ndateWithSystemZone.format = " + sdfWithoutZone.format(dateAtSystemZone)
            + "\ndateAtGmt0.format         = " + sdfWithoutZone.format(dateAtGmt0)
            + "\n"
            + "\ndateFormatWithGmt0        = " + sdfWithZoneGmt0.format(dateAtSystemZone)
    );

output :

dateAtSystemZone          = Thu Apr 23 14:03:36 CST 2020
dateAtGmt0                = Thu Apr 23 06:03:36 CST 2020
diffInMillis              = 28800000

dateWithSystemZone.format = 2020-04-23 14:03:36.140
dateAtGmt0.format         = 2020-04-23 06:03:36.140

dateFormatWithGmt0        = 2020-04-23 06:03:36.140

My system is at GMT+8, so diffInMillis = 28800000 = 8 * 60 * 60 * 1000?


I wonder why no one does this:

Calendar time = Calendar.getInstance();
time.add(Calendar.MILLISECOND, -time.getTimeZone().getOffset(time.getTimeInMillis()));
Date date = time.getTime();

Update: Since Java 8,9,10 and more, there should be better alternatives supported by Java. Thanks for your comment @humanity


From my experience, the bundled Calendar and Date classes in Java can yield undersired effect. If you wouldn't mind upgrading to Java 8, then consider using ZonedDateTime

like so:

ZonedDateTime currentDate = ZonedDateTime.now( ZoneOffset.UTC );

Odds are good you did the right stuff on the back end in getting the date, but there's nothing to indicate that you didn't take that GMT time and format it according to your machine's current locale.

final Date currentTime = new Date();

final SimpleDateFormat sdf =
        new SimpleDateFormat("EEE, MMM d, yyyy hh:mm:ss a z");

// Give it to me in GMT time.
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println("GMT time: " + sdf.format(currentTime));

The key is to use your own DateFormat, not the system provided one. That way you can set the DateFormat's timezone to what you wish, instead of it being set to the Locale's timezone.


tl;dr

Instant.now()

java.time

The Answer by Damilola is correct in suggesting you use the java.time framework built into Java 8 and later. But that Answer uses the ZonedDateTime class which is overkill if you just want UTC rather than any particular time zone.

The troublesome old date-time classes are now legacy, supplanted by the java.time classes.

Instant

The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).

Simple code:

Instant instant = Instant.now() ;

instant.toString(): 2016-11-29T23:18:14.604Z

You can think of Instant as the building block to which you can add a time zone (ZoneID) to get a ZonedDateTime.

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );

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 java.time.

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 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.


After trying a lot of methods, I found out, to get the time in millis at GMT you need to create two separate SimpleDateFormat objects, one for formatting in GMT and another one for parsing.

Here is the code:

 SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 format.setTimeZone(TimeZone.getTimeZone("UTC"));
 Date date = new Date();
 SimpleDateFormat dateParser = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 Date dateTime= dateParser.parse(format.format(date));
 long gmtMilliSeconds = dateTime.getTime();

This works fine. :)


To get the time in millis at GMT all you need is

long millis = System.currentTimeMillis();

You can also do

long millis = new Date().getTime();

and

long millis = 
    Calendar.getInstance(TimeZone.getTimeZone("GMT")).getTimeInMillis();

but these are inefficient ways of making the same call.