在 Java 中获取 GMT 时间

Posted

技术标签:

【中文标题】在 Java 中获取 GMT 时间【英文标题】:Get GMT Time in Java 【发布时间】:2011-07-11 07:11:13 【问题描述】:

在 Java 中,我想以 GMT 格式获取当前时间。

我尝试了这样的各种选项:

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

但日期总是以我的本地时区解释。

我做错了什么,如何将 java Date 转换为 GMT?

【问题讨论】:

System.currentTimeMillis(),或者只是新的 Date()。已经是格林威治标准时间了。 仅供参考,非常麻烦的旧日期时间类,如 java.util.Datejava.util.Calendarjava.text.SimpleDateFormat 现在是 legacy,被 Java 8 中内置的 java.time 类所取代,之后。见Tutorial by Oracle。 【参考方案1】:

很有可能您在获取日期时在后端做了正确的事情,但没有任何迹象表明您没有采用 GMT 时间并根据您机器的当前语言环境对其进行格式化。

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));

关键是使用你自己的DateFormat,而不是系统提供的。这样您就可以将 DateFormat 的时区设置为您想要的,而不是设置为 Locale 的时区。

【讨论】:

我想要以毫秒为单位的 GMT 日期有什么想法吗?? long millis = System.currentTimeMillis(); 将返回自 1 January 1970, 00:00:00.000 UTC 以来经过的毫秒数。 UTC 时间是大多数人在说“GMT 时间”时真正想要的时间。 java.util.Date 有一个 getTime() 方法,它对任意 Date 做同样的事情。根据您的需要,您可能需要使用java.util.Calendar 来构造Date 对象,如果是这样,Calendar's getTime() 方法将返回一个Date,然后您可以通过getTime() 获得毫秒偏移量。 【参考方案2】:

要获得格林威治标准时间的毫秒时间,您只需要

long millis = System.currentTimeMillis();

你也可以这样做

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

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

但这些都是进行相同调用的低效方式。

【讨论】:

这个答案不正确。尝试从 long millis = Calendar.getInstance(TimeZone.getTimeZone("GMT")).getTimeInMillis(); 打印新的 Date(millis)它仍然给出当前时区时间。 @JavaEnthusiast ideone.com/seLqnz 无论时区如何,它都会在此处提供 GMT 时间。 所有这些都给了我我的本地时区,它不是格林威治标准时间。 @Forseth11 这是不正确的。除非您的系统时钟设置不正确,否则它们都是 GMT。 @PeterLawrey 我的错。我使用本地时区中的日期格式来显示时间。对不起。【参考方案3】:

我想知道为什么没有人这样做:

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

更新: 由于 Java 8、9、10 及更高版本,Java 应该支持更好的替代方案。感谢您的评论@humanity

【讨论】:

我尝试了几个选项来实现这一点,但只有你的解决方案可以完美运行 这种方法的一个问题是它在时间序列化时不会更改时区。 仅供参考,非常麻烦的旧日期时间类,如 java.util.Datejava.util.Calendarjava.text.SimpleDateFormat 现在是 legacy,被 Java 8 中内置的 java.time 类所取代,之后。见Tutorial by Oracle。【参考方案4】:

根据我的经验,Java 中捆绑的 Calendar 和 Date 类会产生不理想的效果。 如果您不介意升级到 Java 8,请考虑使用 ZonedDateTime

像这样:

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

【讨论】:

【参考方案5】:

在尝试了很多方法后,我发现,要获得 GMT 的毫秒时间,您需要创建两个单独的 SimpleDateFormat 对象,一个用于在 GMT 中格式化,另一个用于解析。

代码如下:

 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();

这很好用。 :)

【讨论】:

【参考方案6】:

这非常简单直接。

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

现在日期将包含当前的 GMT 时间。

【讨论】:

【参考方案7】:

tl;博士

Instant.now()

java.time

Answer by Damilola 建议您使用 Java 8 及更高版本中内置的 java.time 框架是正确的。但是该答案使用 ZonedDateTime 类,如果您只想要 UTC 而不是任何特定的时区,那就过分了。

麻烦的旧日期时间类现在是遗留的,被 java.time 类所取代。

Instant

Instant 类表示UTC 中时间轴上的时刻,分辨率为nanoseconds(最多九 (9) 位小数)。

简单代码:

Instant instant = Instant.now() ;

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

您可以将Instant 视为可以添加时区 (ZoneID) 以获得ZonedDateTime 的构建块。

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

关于java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

Joda-Time 项目现在位于maintenance mode,建议迁移到 java.time。

要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310。

从哪里获得 java.time 类?

Java SE 8SE 9 及更高版本 内置。 标准 Java API 的一部分,带有捆绑实现。 Java 9 添加了一些小功能和修复。 Java SE 6SE 7 ThreeTen-Backport 中的大部分 java.time 功能都向后移植到 Java 6 和 7。 Android ThreeTenABP 项目专门针对 android 改编 ThreeTen-Backport(如上所述)。 见How to use…

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuarter 和more。

【讨论】:

【参考方案8】:

以下有用的 Utils 方法可通过 DST 节省来管理 GMT 时间:

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;

【讨论】:

A java.util.Date 已采用 UTC。这段代码对我来说毫无意义。【参考方案9】:

在 java 8 之后,你可能希望得到如下格式化的时间:

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

【讨论】:

【参考方案10】:

你不能

首先,你问的是不可能的事。一个老式的 Date 对象没有,因为不能有时区或 GMT 偏移量。

但日期总是以我的本地时区解释。

我想你已经打印了Date 或者做了其他隐含地调用它toString 方法的事情。我相信这是 Date 在您的时区中被解释的唯一一次。更准确地说是在您的 JVM 的当前默认时区。另一方面,这是不可避免的。 Date.toString() 确实以这种方式运行,它获取 JVM 的时区设置并使用它来呈现要返回的字符串。

你可以用 java.time

不过,您不应该使用 Date。该课程设计不佳,幸运的是早已过时。此外,java.time,替代它的现代 Java 日期和时间 API,有一两个类用于日期和时间 与 GMT 或 UTC 的偏移。我现在认为 GMT 和 UTC 是同义词,严格来说它们不是。

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

刚才运行这个sn-p的时候,输出是:

现在 UTC (GMT) 时间是 2019-06-17T11:51:38.246188Z

输出的尾随 Z 表示 UTC。

链接

Oracle tutorial: Date Time 解释如何使用 java.time。 The Difference Between GMT and UTC 在 timeanddate.com 上。

【讨论】:

【参考方案11】:

以下代码将得到日期减去时区偏移量:

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)
    );

输出:

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

我的系统是GMT+8,所以diffInMillis = 28800000 = 8 * 60 * 60 * 1000

【讨论】:

错了。从ZonedDateTime2020-04-22T00:00+08:00[Asia/Shanghai] 我得到Tue Apr 21 08:00:00 GMT 2020。这是一天中的同一个小时,但不是同一时间。还有一个老式的 Date 既没有时区偏移也没有时区,所以说它是或不是 GMT 没有任何意义。 虽然这段代码可以回答这个问题,但最好包含一些上下文,解释它是如何工作的以及何时使用它。从长远来看,纯代码的答案没有用处。【参考方案12】:

您可以使用 Java 8 java.time 包来实现它

在 Java 中获取当前 GMT 时间:

ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneOffset.UTC);
System.out.println("Print current time in GMT: "+zonedDateTime); // 2021-08-30T03:58:05.815942377Z

将 java.util.Date 转换为 GMT

// use a formatter
DateTimeFormatter customFormatter = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm:ss O");

Date date = new Date(); //; java.util.Date object
Instant instant = date.toInstant();
ZonedDateTime zonedDateTime = instant.atZone(ZoneOffset.UTC);
System.out.println("java.util.Date to GMT: "+customFormatter.format(zonedDateTime)); // 08/30/2021 03:58:05 GMT

参考

ZonedDateTime DateTimeFormatter Instant

【讨论】:

以上是关于在 Java 中获取 GMT 时间的主要内容,如果未能解决你的问题,请参考以下文章

如何在 java 中获取当前的 Linux GMT 时间戳?

java GMT时间转换为CST时间

Java - 存储 GMT 时间

如何在 Android 设备中使用 GMT 获取时区格式?

在Java中获取当前时区的日期

将 GMT 日期时间转换为本地时区日期时间