我怎样才能得到在UTC UTC或格林尼治标准时间的当前date和时间?

当我创build一个新的Date对象时,它被初始化为当前时间,但在本地时区。 我怎样才能得到格林尼治标准时间的当前date和时间?

java.util.Date没有特定的时区,尽pipe它的值通常被认为是与UTC相关的。 是什么让你觉得这是当地时间?

准确地说: java.util.Date的值是Unix时代以来的毫秒数,UTC时间为1970年1月1日午夜(UTC)。 在其他时区也可以描述同一个时代,但是传统的描述是以UTC为单位的。 因为它是一个固定时期以来的毫秒数,所以在任何特定时刻, java.util.Date的值都是相同的,而不pipe本地时区如何。

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

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

不过,我会build议你使用Joda-Time ,它提供了一个更清晰的API。

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

TL;博士

 Instant.now() 

生成一个string来表示该值:

 Instant.now().toString() 

2016-09-13T23:30:52.123Z

细节

由Jon Skeet的正确答案指出,java.util.Date对象没有时区 。 但是它的toString实现在生成该date时间值的string表示时应用JVM的默认时区。 对于天真的程序员来说,date似乎有一个时区,但没有。

与Java捆绑在一起的java.util.DatejuCalendarjava.text.SimpleDateFormat类是非常麻烦的。 避免他们。 相反,使用这些有效的date时间库:

  • Java 8中的java.time。*包
  • 乔达时间

java.time(Java 8)

Java 8带来了一个优秀的新的java.time。*包来取代旧的java.util.Date/Calendar类。

在UTC / GMT获取当前时间是一个简单的单线…

 Instant instant = Instant.now(); 

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

在Java 8中,当前时刻仅以毫秒的分辨率捕获。 Java 9带来了全新的Clock 实现 ,捕捉当前时刻,达到该类的全纳秒能力,具体取决于主计算机时钟硬件的能力。

这是toString方法使用一个特定的ISO 8601格式生成其值的string表示。 该格式根据需要输出零,三,六或九位数字( 毫秒 , 微秒或纳秒 )以表示秒的分数。

如果您想要更灵活的格式,在各种时区或其他附加function中进行调整,请使用时区( ZoneId对象)来获取ZonedDateTime 。 时区可以是UTC或任何其他时区。 ZoneId的子类ZoneId 为UTC保存一个常量 。

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

转储到控制台…

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

当运行…

 now: 2014-01-21T23:42:03.522Z 

java.time类由JSR 310定义。 他们受到Joda-Time的启发,但完全重新devise。

乔达时间

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

使用Joda-Time第三方开放源代码免费库,您可以在一行代码中获取当前的date时间。

Joda-Time启发了Java 8中新的java.time。*类,但具有不同的体系结构。 您可以在旧版本的Java中使用Joda-Time。 Joda-Time继续在Java 8中工作,并继续积极维护(截至2014年)。 但是,Joda-Time团队build议迁移到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 

有关做时区工作的更多示例代码,请参阅我对类似问题的回答。

时区

我build议你总是指定一个时区,而不是隐式地依赖于JVM当前的默认时区(可以随时更改!)。 这种依赖似乎是日常工作中混乱和错误的常见原因。

now()呼叫now()通过期望/预期的时区分配。 使用DateTimeZone类。

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

该类在UTC时区保持不变 。

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

如果您真的想要使用JVM的当前默认时区,请进行明确的调用,以便您的代码可以自行logging。

 DateTimeZone zoneDefault = DateTimeZone.getDefault(); 

ISO 8601

阅读ISO 8601格式。 java.time和Joda-Time都使用该标准的合理格式作为parsing和生成string的默认值。


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

这肯定会返回UTC时间:作为string和date对象!

 static final String DATEFORMAT = "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(DATEFORMAT); 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; } 
  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 f = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss"); f.setTimeZone(TimeZone.getTimeZone("UTC")); System.out.println(f.format(new Date())); 

地球上任何一点的时间都是一样的,但是我们对时间的看法可能因地点而异。

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

这适用于在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 

Jon Skeet问道:

@Downvoter:关心评论? 我的回答究竟是不正确的? – 乔恩Skeet 09年10月26日在21:09

我不是Downvoter,但是这个答案似乎是不正确的。 你说:

java.util.Date始终使用UTC。 是什么让你觉得这是当地时间? 我怀疑问题是你通过使用本地时区的日历的实例,或者可能使用也使用本地时区的Date.toString()来显示它。

但是,代码:

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

给出当地时间,而不是GMT(UTC小时),不使用Calendar ,也不使用SimpleDateFormat

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

综合答复,代码:

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

显示格林尼治标准时间,而不是当地时间 – 请注意getTime.getHours()丢失,因为这将创build一个Date()对象,理论上存储在格林尼治标准时间的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)); 

您可以使用:

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

然后,使用aGMTCalendar对象执行的所有操作将使用GMT时区完成,并且不会有夏季时间或固定偏移应用。 我认为之前的海报是正确的,Date()对象总是返回一个GMT,它不是直到你去做一些与它被转换为本地时区的date对象。

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

附:

 Calendar cal = Calendar.getInstance(); 

然后cal有当前的date和时间。
您还可以通过以下方式获取当前的date和时间:

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

你可以问cal.get(Calendar.DATE); 或其他日历常数关于其他细节。
date和时间戳在Java中已被弃用。 日历课程不是。

这里有一个获取GMT时间戳对象的其他build议:

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

这是另一种以string格式获取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()); 

你可以直接使用这个

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

只是为了使这个更简单,要创build一个UTCDate ,你可以使用Calendar

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

这将使用“UTC” TimeZone构造Calendar的新实例。

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

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

 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 az 'on' MM/dd/yyyy")); System.out.println("---------------------------------------------"); // Alternate format System.out.println(my_time_in("America/Los_Angeles", "'at' HH:mm az 'on' MM/dd/yyyy") ); System.out.println(my_time_in("America/Buenos_Aires", "'at' HH:mm az '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 

在UTC中转换当前date时间:

 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 

这工作对我来说,返回格林尼治标准时间戳!

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

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

使用此类可以从在线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); 

这是我的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 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时间,并且需要毫秒数而没有你本地的偏移量,你可以使用这个:

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

如果你想避免分析date,只想在格林尼治标准时间戳,你可以使用:

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