我怎样才能得到在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.Date
, juCalendar
和java.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一个UTC
的Date
,你可以使用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()));