How can I get the current date and time in UTC or GMT in Java?
当我创建一个新的
准确地说:
我怀疑问题是您通过使用本地时区的日历实例来显示它,或者可能使用也使用本地时区的
如果这不是问题,请发布一些示例代码。
不过,我还是建议您使用joda-time,它提供了更清晰的API。
1 2 3 4 5 6 7 8 | 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()) ); |
DR
1 | Instant.now() // Capture the current moment in UTC. |
生成表示该值的字符串:
1 | Instant.now().toString() |
2016-09-13T23:30:52.123Z
细节
正如jon skeet所说的正确答案,java.util.date对象没有时区?.但是它的
EDCOX1,1,EDCOX1,2,和EDCOX1,3个与Java捆绑的类是众所周知的麻烦。避开它们。相反,请使用以下任一有效的日期时间库:
- Java 8中的Java.Time.*包
- 乔达时间
JavaTime:(Java 8)
Java 8带来了一个优秀的新Java .Time.*包来取代旧的JavaUTL.DATE/日历类。
用UTC/GMT计算当前时间是一个简单的一行程序…
1 | Instant instant = Instant.now(); |
在Java 8中,当前时刻仅以毫秒分辨率捕获。Java 9带来了一个新的
它的
如果您想要更灵活的格式或其他附加功能,那么对UTC本身(
1 | OffsetDateTime now = OffsetDateTime.now( ZoneOffset.UTC ); |
转储到控制台…
1 |
跑步时…
1 | now: 2014-01-21T23:42:03.522Z |
java.time类由jsr 310定义。他们的灵感来自于乔达时代,但完全是重新设计的。
乔达时间更新:现在处于维护模式的joda time项目建议迁移到java.time类。
使用Joda Time第三方免费开放源码库,您只需一行代码就可以获得当前日期时间。
JoDA时间启发了Java 8中的新Java.Time.*类,但具有不同的体系结构。您可以在JAVA的旧版本中使用JoDA时间。JoDA时间继续在Java 8中工作,并继续积极维护(如2014)。然而,Joda Time团队建议迁移到java.time。
1 | System.out.println("UTC/GMT date-time in ISO 8601 format:" + new org.joda.time.DateTime( org.joda.time.DateTimeZone.UTC ) ); |
更详细的示例代码(Joda时间2.3)
1 2 | 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 ); |
转储到控制台…
1 2 |
跑步时…
1 2 | 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的当前默认时区(随时都可以更改!)这种依赖似乎是日期时间工作中混乱和错误的常见原因。
调用
1 2 | DateTimeZone zoneMontréal = DateTimeZone.forID("America/Montreal" ); DateTime now = DateTime.now( zoneMontréal ); |
该类保存UTC时区的常量。
1 | DateTime now = DateTime.now( DateTimeZone.UTC ); |
如果您真的想要使用JVM的当前默认时区,那么就进行一个显式调用,这样您的代码就可以自我记录了。
1 | DateTimeZone zoneDefault = DateTimeZone.getDefault(); |
国际标准化组织8601
阅读ISO 8601格式。java.time和joda-time都使用该标准的合理格式作为解析和生成字符串的默认格式。
?实际上,java.util.date确实有一个时区,深深地隐藏在源代码层之下。对于大多数实际用途,该时区将被忽略。所以,简而言之,我们说java.util.date没有时区。此外,隐藏的时区不是date的
这肯定会返回UTC时间:作为字符串和日期对象!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 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; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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()); |
实际上不是时间,但它的表示可以改变。
1 2 3 | SimpleDateFormat f = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss"); f.setTimeZone(TimeZone.getTimeZone("UTC")); System.out.println(f.format(new Date())); |
地球上任何一点的时间都是一样的,但我们对时间的感知可能会因地点的不同而有所不同。
此代码打印当前时间UTC。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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())); } } |
结果
1 | 2013-10-26 14:37:48 UTC |
Calendar aGMTCalendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
Then all operations performed using the aGMTCalendar object will be done with the GMT time zone and will not have the daylight savings time or fixed offsets applied
错了!
1 2 |
和
1 |
将同时返回。Idem
1 |
这适用于在Android中获取UTC毫秒。
1 2 3 |
这是乔恩·斯基特的回答中似乎不正确的地方。他说:
java.util.Date is always in UTC. What makes you think it's in local
time? I suspect the problem is that you're displaying it via an
instance of Calendar which uses the local timezone, or possibly using
Date.toString() which also uses the local timezone.
但是,代码:
给出本地时间,而不是格林威治时间(UTC时间),完全不使用
这就是为什么看起来有些不正确。
把这些答案放在一起,代码:
1 2 |
显示的是格林尼治标准时间而不是当地时间--请注意,缺少
如果您想要一个日期对象,其字段根据UTC进行调整,您可以使用Joda时间这样做:
1 2 3 4 5 6 7 8 9 10 |
1 2 3 | SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MM-dd"); dateFormatGmt.setTimeZone(TimeZone.getTimeZone("GMT")); System.out.println(dateFormatGmt.format(date)); |
你可以使用:
然后,使用agmtcalendar对象执行的所有操作都将使用GMT时区完成,并且不会应用夏令时或固定偏移量。我认为前面的海报是正确的,日期()对象总是返回一个格林威治标准时间,直到你对日期对象做一些事情,它才被转换到本地时区。
你可以直接用这个
1 2 3 | SimpleDateFormat dateFormatGmt = new SimpleDateFormat("dd:MM:yyyy HH:mm:ss"); dateFormatGmt.setTimeZone(TimeZone.getTimeZone("GMT")); System.out.println(dateFormatGmt.format(new Date())+""); |
用:
那么,
您可以向
下面是获取GMT时间戳对象的其他建议:
1 2 3 4 5 6 7 8 9 10 11 |
这是另一种获取字符串格式的GMT时间的方法
1 2 3 4 | 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()); |
为了简单起见,要在
它将使用"UTC"
如果您需要日历中的
以特定时区和特定格式呈现系统时间的示例代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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); } } |
产量
1 2 3 4 | 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格式转换当前日期时间:
1 2 3 4 5 6 7 8 9 10 11 | 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 |
以下是我对TOUTC的实现:
1 2 3 4 5 6 |
可能有几种方法可以改进它,但它对我有用。
这对我有效,返回格林威治时间戳!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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(); } |
1 2 3 4 |
使用此类从联机NTP服务器获取正确的UTC时间:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | 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); } } |
并将其用于:
1 2 3 4 5 6 7 | long now = 0; NTP_UTC_Time client = new NTP_UTC_Time(); if (client.requestTime("pool.ntp.org", 2000)) { now = client.getNtpTime(); } |
如果需要将UTC时间"now"作为日期时间字符串,请使用函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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""; } } |
并将其用于:
1 |
使用java.time包并包含以下代码-
或
取决于您的应用程序需要。