如何在Java中获得当前的UTC或GMT日期和时间?

当我创建一个新的Date对象时,它被初始化为当前时间,但在本地时区。如何获得当前的GMT日期和时间?

1131714 次浏览

java.util.Date没有特定的时区,尽管它的值通常被认为与UTC有关。你凭什么认为现在是当地时间?

准确地说:java.util.Date内的值是自Unix epoch(发生在UTC时间1970年1月1日午夜)以来的毫秒数。同样的纪元也可以用其他时区来描述,但是传统的描述是用UTC来表示的。因为它是从一个固定的纪元开始的毫秒数,所以在任何特定的时刻,java.util.Date内的值在世界各地都是相同的,而不考虑当地的时区。

我怀疑问题是,您通过使用本地时区的Calendar实例来显示它,或者可能使用也使用本地时区的Date.toString()实例,或者默认情况下也使用本地时区的SimpleDateFormat实例。

如果这不是问题,请发布一些示例代码。

不过,我还是建议您使用Joda-Time,它提供了更清晰的API。

:

Calendar cal = Calendar.getInstance();

cal有当前日期和时间 你也可以用

获取当前时区的日期和时间
Calendar cal2 = Calendar.getInstance(TimeZone.getTimeZone("GMT-2"));
你可以问cal.get(Calendar.DATE);或其他日历常量关于其他细节 日期和时间戳在Java中已弃用。不是日历类

你可以使用:

Calendar aGMTCalendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));

然后,使用aGMTCalendar对象执行的所有操作都将使用GMT时区完成,并且不会应用夏令时或固定偏移量。我认为之前的帖子是正确的,Date()对象总是返回GMT,直到你对Date对象做一些事情,它才被转换为本地时区。

    Calendar c = Calendar.getInstance();
System.out.println("current: "+c.getTime());


TimeZone z = c.getTimeZone();
int offset = z.getRawOffset();
if(z.inDaylightTime(new Date())){
offset = offset + z.getDSTSavings();
}
int offsetHrs = offset / 1000 / 60 / 60;
int offsetMins = offset / 1000 / 60 % 60;


System.out.println("offset: " + offsetHrs);
System.out.println("offset: " + offsetMins);


c.add(Calendar.HOUR_OF_DAY, (-offsetHrs));
c.add(Calendar.MINUTE, (-offsetMins));


System.out.println("GMT Time: "+c.getTime());
SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
dateFormatGmt.setTimeZone(TimeZone.getTimeZone("GMT"));


//Local time zone
SimpleDateFormat dateFormatLocal = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");


//Time in GMT
return dateFormatLocal.parse( dateFormatGmt.format(new Date()) );

Calendar aGMTCalendar = Calendar. getinstance (TimeZone.getTimeZone("GMT")); 然后,使用aGMTCalendar对象执行的所有操作都将使用GMT时区完成,并且不会应用夏令时或固定偏移量

错了!

Calendar aGMTCalendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
aGMTCalendar.getTime(); //or getTimeInMillis()

而且

Calendar aNotGMTCalendar = Calendar.getInstance(TimeZone.getTimeZone("GMT-2"));aNotGMTCalendar.getTime();

会在同一时间回来。同上的对

new Date(); //it's not GMT.

其实不是时间,而是它的表现形式可以改变。

SimpleDateFormat f = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
f.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(f.format(new Date()));

地球上任何地方的时间都是一样的,但我们对时间的感知可能会因地点的不同而不同。

SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MM-dd");
dateFormatGmt.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println(dateFormatGmt.format(date));

这肯定会返回UTC时间:作为字符串和日期对象!

static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";


public static Date getUTCdatetimeAsDate() {
// note: doesn't check for null
return stringDateToDate(getUTCdatetimeAsString());
}


public static String getUTCdatetimeAsString() {
final SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
final String utcTime = sdf.format(new Date());


return utcTime;
}


public static Date stringDateToDate(String StrDate) {
Date dateToReturn = null;
SimpleDateFormat dateFormat = new SimpleDateFormat(DATEFORMAT);


try {
dateToReturn = (Date)dateFormat.parse(StrDate);
}
catch (ParseException e) {
e.printStackTrace();
}


return dateToReturn;
}

以特定时区和特定格式呈现系统时间的示例代码。

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;


public class TimZoneTest {
public static void main (String[] args){
//<GMT><+/-><hour>:<minutes>
// Any screw up in this format, timezone defaults to GMT QUIETLY. So test your format a few times.


System.out.println(my_time_in("GMT-5:00", "MM/dd/yyyy HH:mm:ss") );
System.out.println(my_time_in("GMT+5:30", "'at' HH:mm a z 'on' MM/dd/yyyy"));


System.out.println("---------------------------------------------");
// Alternate format
System.out.println(my_time_in("America/Los_Angeles", "'at' HH:mm a z 'on' MM/dd/yyyy") );
System.out.println(my_time_in("America/Buenos_Aires", "'at' HH:mm a z 'on' MM/dd/yyyy") );




}


public static String my_time_in(String target_time_zone, String format){
TimeZone tz = TimeZone.getTimeZone(target_time_zone);
Date date = Calendar.getInstance().getTime();
SimpleDateFormat date_format_gmt = new SimpleDateFormat(format);
date_format_gmt.setTimeZone(tz);
return date_format_gmt.format(date);
}


}

输出

10/08/2011 21:07:21
at 07:37 AM GMT+05:30 on 10/09/2011
at 19:07 PM PDT on 10/08/2011
at 23:07 PM ART on 10/08/2011

你可以直接用这个

SimpleDateFormat dateFormatGmt = new SimpleDateFormat("dd:MM:yyyy HH:mm:ss");
dateFormatGmt.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println(dateFormatGmt.format(new Date())+"");

如果你想要一个Date对象,字段调整为UTC,你可以用Joda的时间这样做:

import org.joda.time.DateTimeZone;
import java.util.Date;


...


Date local = new Date();
System.out.println("Local: " + local);
DateTimeZone zone = DateTimeZone.getDefault();
long utc = zone.convertLocalToUTC(local.getTime(), false);
System.out.println("UTC: " + new Date(utc));

这里还有一个获取GMT时间戳对象的建议:

import java.sql.Timestamp;
import java.util.Calendar;


...


private static Timestamp getGMT() {
Calendar cal = Calendar.getInstance();
return new Timestamp(cal.getTimeInMillis()
-cal.get(Calendar.ZONE_OFFSET)
-cal.get(Calendar.DST_OFFSET));
}

为了简单一点,在UTC中创建Date,你可以使用Calendar:

Calendar.getInstance(TimeZone.getTimeZone("UTC"));

它将使用“UTC”TimeZoneCalendar构造一个新实例。

如果你需要日历中的Date对象,你可以使用getTime()

下面是乔恩·斯基特的回答中似乎不正确的地方。他说:

java.util.Date总是UTC。你凭什么认为它是本地的 时间吗?我怀疑问题在于您通过 使用本地时区的Calendar实例,或者可能使用 Date.toString()也使用本地时区

然而,代码:

System.out.println(new java.util.Date().getHours() + " hours");

给出本地时间,而不是GMT (UTC时间),没有使用CalendarSimpleDateFormat

这就是为什么看起来有些事情是不正确的。

把这些回答放在一起,代码如下:

System.out.println(Calendar.getInstance(TimeZone.getTimeZone("GMT"))
.get(Calendar.HOUR_OF_DAY) + " Hours");

显示格林尼治时间而不是本地时间——请注意,getTime.getHours()缺失,因为这将创建一个Date()对象,理论上它以GMT存储日期,但返回本地时区的小时。

下面是另一种以字符串格式获取GMT时间的方法

String DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss z" ;
final SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
String dateTimeString =  sdf.format(new Date());

简单来说。一个日历对象存储关于时区的信息,但是当你执行cal.getTime()时,时区信息将会丢失。所以对于时区转换,我建议使用DateFormat类…

这为我工作,返回格林尼治时间戳!

    Date currDate;
SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
dateFormatGmt.setTimeZone(TimeZone.getTimeZone("GMT"));
SimpleDateFormat dateFormatLocal = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");


long currTime = 0;
try {


currDate = dateFormatLocal.parse( dateFormatGmt.format(new Date()) );
currTime = currDate.getTime();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

这适用于在Android中获取UTC毫秒。

Calendar c = Calendar.getInstance();
int utcOffset = c.get(Calendar.ZONE_OFFSET) + c.get(Calendar.DST_OFFSET);
Long utcMilliseconds = c.getTimeInMillis() + utcOffset;

此代码打印当前UTC时间。

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;




public class Test
{
public static void main(final String[] args) throws ParseException
{
final SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
f.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(f.format(new Date()));
}
}

结果

2013-10-26 14:37:48 UTC

博士tl;

Instant.now()   // Capture the current moment in UTC.

生成一个String来表示该值:

Instant.now().toString()

2016 - 09 - 13 - t23:30:52.123z

细节

正如乔恩·斯基特的正确答案所述,java.util.Date对象具有没有时区__。但是它的toString实现在生成日期-时间值的String表示时应用JVM的默认时区。让naïve程序员感到困惑的是,Date 似乎有时区,但没有。

与Java捆绑的java.util.Datej.u.Calendarjava.text.SimpleDateFormat类是出了名的麻烦。相反,使用这些有效的日期时间库中的任何一个:

java。时间(java8)

Java 8带来了一个优秀的新java.time。*包,以取代旧的java.util。日期/日历类。

获取当前UTC/GMT时间是一个简单的一行程序…

Instant instant = Instant.now();

Instant类是java中的基本构建块。time,表示UTC中的时间轴上的一个时刻,分辨率为纳秒

在Java 8中,当前时刻的捕获分辨率只有毫秒。Java 9带来了一个全新的实现Clock捕获当前时刻,最高达到这个类的全部纳秒能力,这取决于主机计算机的时钟硬件的能力。

它的toString方法使用一个特定的ISO 8601格式生成其值的String表示形式。该格式根据需要输出0、3、6或9位数字(毫秒微秒纳秒)来表示秒的分数。

如果您想要更灵活的格式或其他附加特性,那么为UTC本身(# EYZ0常数)应用0的offset-from-UTC来获得OffsetDateTime

OffsetDateTime now = OffsetDateTime.now( ZoneOffset.UTC );

转储到控制台…

System.out.println( "now.toString(): " + now );

运行时……

now.toString(): 2014-01-21T23:42:03.522Z

现代和传统Java日期-时间类型表。


关于# EYZ0

< em > java.time < / em >框架内置于Java 8及更高版本中。这些类取代了麻烦的旧的遗产日期-时间类,如java.util.DateCalendar, &# EYZ7。

要了解更多信息,请参阅< < em >甲骨文教程/ em >。搜索Stack Overflow可以找到很多例子和解释。规格是JSR 310

< em > Joda-Time < / em >项目,现在在维护模式中,建议迁移到java.time类。

您可以直接与数据库交换java.time对象。使用与JDBC 4.2或更高版本兼容的JDBC驱动程序。不需要字符串,不需要java.sql.*类。

从哪里获取java。时间类?

  • Java SE 8Java SE 9Java SE 10 . Java SE 10 . Java SE 10 . Java SE 10Java SE 11,以及以后-带有捆绑实现的标准Java API的一部分。
    • Java 9增加了一些小特性并进行了修复。
    • 李< / ul > < / >
    • Java SE 6Java SE 7
      • java.time的大部分功能都被向后移植到Java 6 &7在<强> < em > ThreeTen-Backport < / em > < / >强
      • 李< / ul > < / >
      • 安卓

        表的java。时间库使用哪个版本的Java或Android

        EYZ3项目扩展了java。额外的课程时间。这个项目是未来可能添加到java.time的一个试验场。您可以在这里找到一些有用的类,如IntervalYearWeekYearQuarter更多的


        Joda-Time

        更新:Joda-Time项目,现在在维护模式,建议迁移到java.time类。

        使用Joda-Time第三方开源免费库,只需一行代码就可以获得当前日期-时间。

        Joda-Time启发了新的java.time。类,但具有不同的架构。您可以在较旧版本的Java中使用Joda-Time。Joda-Time继续在Java 8中工作,并继续积极维护(截至2014年)。然而,Joda-Time团队建议迁移到java.time。

        System.out.println( "UTC/GMT date-time in ISO 8601 format: " + new org.joda.time.DateTime( org.joda.time.DateTimeZone.UTC ) );
        

        更详细的示例代码(Joda-Time 2.3)…

        org.joda.time.DateTime now = new org.joda.time.DateTime(); // Default time zone.
        org.joda.time.DateTime zulu = now.toDateTime( org.joda.time.DateTimeZone.UTC );
        

        转储到控制台…

        System.out.println( "Local time in ISO 8601 format: " + now );
        System.out.println( "Same moment in UTC (Zulu): " + zulu );
        

        运行时……

        Local time in ISO 8601 format: 2014-01-21T15:34:29.933-08:00
        Same moment in UTC (Zulu): 2014-01-21T23:34:29.933Z
        

        有关执行时区工作的更多示例代码,请参阅针对类似问题的我的答案

        时区

        我建议您始终指定一个时区,而不是隐式地依赖JVM当前的默认时区(它随时都可能改变!)。这种依赖似乎是日期时间工作中混乱和错误的常见原因。

        当调用now()时,传递要分配的期望/期望时区。使用DateTimeZone类。

        DateTimeZone zoneMontréal = DateTimeZone.forID( "America/Montreal" );
        DateTime now = DateTime.now( zoneMontréal );
        

        该类保存了一个协调世界时常数时区。

        DateTime now = DateTime.now( DateTimeZone.UTC );
        

        如果您确实希望使用JVM的当前默认时区,那么可以显式调用,以便代码是自文档化的。

        DateTimeZone zoneDefault = DateTimeZone.getDefault();
        

        ISO 8601

        阅读ISO 8601格式。java。time和Joda-Time使用该标准的合理格式作为解析和生成字符串的默认值。


        实际上,java.util.Date 有一个时区,深埋在源代码层之下。对于大多数实际目的,该时区将被忽略。因此,作为速记,我们说java.util.Date没有时区。此外,埋藏的时区是,即Date的toString方法所使用的时区;该方法使用JVM的当前默认时区。因此更有理由避免这个令人困惑的类,并坚持使用Joda-Time和java.time。

使用这个类从在线NTP服务器获得正确的UTC时间:

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;




class NTP_UTC_Time
{
private static final String TAG = "SntpClient";


private static final int RECEIVE_TIME_OFFSET = 32;
private static final int TRANSMIT_TIME_OFFSET = 40;
private static final int NTP_PACKET_SIZE = 48;


private static final int NTP_PORT = 123;
private static final int NTP_MODE_CLIENT = 3;
private static final int NTP_VERSION = 3;


// Number of seconds between Jan 1, 1900 and Jan 1, 1970
// 70 years plus 17 leap days
private static final long OFFSET_1900_TO_1970 = ((365L * 70L) + 17L) * 24L * 60L * 60L;


private long mNtpTime;


public boolean requestTime(String host, int timeout) {
try {
DatagramSocket socket = new DatagramSocket();
socket.setSoTimeout(timeout);
InetAddress address = InetAddress.getByName(host);
byte[] buffer = new byte[NTP_PACKET_SIZE];
DatagramPacket request = new DatagramPacket(buffer, buffer.length, address, NTP_PORT);


buffer[0] = NTP_MODE_CLIENT | (NTP_VERSION << 3);


writeTimeStamp(buffer, TRANSMIT_TIME_OFFSET);


socket.send(request);


// read the response
DatagramPacket response = new DatagramPacket(buffer, buffer.length);
socket.receive(response);
socket.close();


mNtpTime = readTimeStamp(buffer, RECEIVE_TIME_OFFSET);
} catch (Exception e) {
//  if (Config.LOGD) Log.d(TAG, "request time failed: " + e);
return false;
}


return true;
}




public long getNtpTime() {
return mNtpTime;
}




/**
* Reads an unsigned 32 bit big endian number from the given offset in the buffer.
*/
private long read32(byte[] buffer, int offset) {
byte b0 = buffer[offset];
byte b1 = buffer[offset+1];
byte b2 = buffer[offset+2];
byte b3 = buffer[offset+3];


// convert signed bytes to unsigned values
int i0 = ((b0 & 0x80) == 0x80 ? (b0 & 0x7F) + 0x80 : b0);
int i1 = ((b1 & 0x80) == 0x80 ? (b1 & 0x7F) + 0x80 : b1);
int i2 = ((b2 & 0x80) == 0x80 ? (b2 & 0x7F) + 0x80 : b2);
int i3 = ((b3 & 0x80) == 0x80 ? (b3 & 0x7F) + 0x80 : b3);


return ((long)i0 << 24) + ((long)i1 << 16) + ((long)i2 << 8) + (long)i3;
}


/**
* Reads the NTP time stamp at the given offset in the buffer and returns
* it as a system time (milliseconds since January 1, 1970).
*/
private long readTimeStamp(byte[] buffer, int offset) {
long seconds = read32(buffer, offset);
long fraction = read32(buffer, offset + 4);
return ((seconds - OFFSET_1900_TO_1970) * 1000) + ((fraction * 1000L) / 0x100000000L);
}


/**
* Writes 0 as NTP starttime stamp in the buffer. --> Then NTP returns Time OFFSET since 1900
*/
private void writeTimeStamp(byte[] buffer, int offset) {
int ofs =  offset++;


for (int i=ofs;i<(ofs+8);i++)
buffer[i] = (byte)(0);
}


}

并将其用于:

        long now = 0;


NTP_UTC_Time client = new NTP_UTC_Time();


if (client.requestTime("pool.ntp.org", 2000)) {
now = client.getNtpTime();
}

如果你需要UTC时间“now”作为DateTimeString,使用函数:

private String get_UTC_Datetime_from_timestamp(long timeStamp){


try{


Calendar cal = Calendar.getInstance();
TimeZone tz = cal.getTimeZone();


int tzt = tz.getOffset(System.currentTimeMillis());


timeStamp -= tzt;


// DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss",Locale.getDefault());
DateFormat sdf = new SimpleDateFormat();
Date netDate = (new Date(timeStamp));
return sdf.format(netDate);
}
catch(Exception ex){
return "";
}
}

并将其用于:

String UTC_DateTime = get_UTC_Datetime_from_timestamp(now);

转换UTC当前日期时间:

DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");


DateTimeZone dateTimeZone = DateTimeZone.getDefault(); //Default Time Zone


DateTime currDateTime = new DateTime(); //Current DateTime


long utcTime = dateTimeZone.convertLocalToUTC(currDateTime .getMillis(), false);


String currTime = formatter.print(utcTime); //UTC time converted to string from long in format of formatter


currDateTime = formatter.parseDateTime(currTime); //Converted to DateTime in UTC

这是我的实现:

public static String GetCurrentTimeStamp()
{
Calendar cal=Calendar.getInstance();
long offset = cal.getTimeZone().getOffset(System.currentTimeMillis());//if you want in UTC else remove it .
return new java.sql.Timestamp(System.currentTimeMillis()+offset).toString();
}

如果你正在使用joda time,并希望当前时间以毫秒为单位没有本地偏移,你可以使用这个:

long instant = DateTimeZone.UTC.getMillisKeepLocal(DateTimeZone.getDefault(), System.currentTimeMillis());

如果你想避免解析日期,只是想要一个GMT的时间戳,你可以使用:

final Date gmt = new Timestamp(System.currentTimeMillis()
- Calendar.getInstance().getTimeZone()
.getOffset(System.currentTimeMillis()));

这是我的toUTC的实现:

    public static Date toUTC(Date date){
long datems = date.getTime();
long timezoneoffset = TimeZone.getDefault().getOffset(datems);
datems -= timezoneoffset;
return new Date(datems);
}

可能有几种方法可以改进它,但它对我来说是有效的。

public static void main(String args[]){
LocalDate date=LocalDate.now();
System.out.println("Current date = "+date);
}
public class CurrentUtcDate
{
public static void main(String[] args) {
Date date = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println("UTC Time is: " + dateFormat.format(date));
}
}

输出:

UTC Time is: 22-01-2018 13:14:35

您可以根据需要更改日期格式。

使用java。时间包和包括以下代码-

# EYZ0

# EYZ0

这取决于您的应用程序需要。

当前UTC日期

Instant.now().toString().replaceAll("T.*", "");

当我需要输出一个Date对象时,我就是这样做的,这通常是当你需要在SQL数据库中保存一个日期,而我希望它是UTC时的情况。我只是减去当地时区的偏移时间。

    ZonedDateTime now = ZonedDateTime.now();
Date nowUTC = new Date(1000 * (now.toEpochSecond() - now.getOffset().getTotalSeconds()));
< p >——更新 Basil建议使用

来实现相同的结果
    Date nowUTC = Date.from(ZonedDateTime.now().toInstant());

但是在非utc java系统环境中测试后,我看到结果并不相同。根据巴兹尔的代码,日期仍然在本地区域

你可以使用的简单函数:

编辑:这个版本使用现代java。时间类。

private static final DateTimeFormatter FORMATTER
= DateTimeFormatter.ofPattern("dd-MM-uuuu HH:mm:ss z");


public static String getUtcDateTime() {
return ZonedDateTime.now(ZoneId.of("Etc/UTC")).format(FORMATTER);
}

方法返回值:

26-03-2022 17:38:55 UTC

最初的功能:

 public String getUTC_DateTime() {
SimpleDateFormat dateTimeFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss z");
dateTimeFormat.setTimeZone(TimeZone.getTimeZone("UTC"));//gmt
return dateTimeFormat.format(new Date());


}

以上函数返回:

26-03-2022 08:07:21 UTC