当我创建一个新Date
对象时,它会初始化为当前时间但在本地时区.如何获得GMT中的当前日期和时间?
java.util.Date
没有特定的时区,尽管其值通常被认为与UTC有关.是什么让你觉得它是在当地时间?
确切地说:a中的值java.util.Date
是自1970年1月1日午夜发布的Unix纪元以来的毫秒数.同一时期也可以在其他时区描述,但传统的描述是以UTC的形式.由于它是固定时期以来的毫秒数java.util.Date
,因此无论当地时区如何,在任何特定时刻,其内部的值都是相同的.
我怀疑问题是你通过使用本地时区的日历实例显示它,或者可能使用本地时区,或者使用Date.toString()
本地时区或SimpleDateFormat
实例,默认情况下也使用本地时区.
如果这不是问题,请发布一些示例代码.
但是,我会建议您使用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()) );
Instant.now() // Capture the current moment in UTC.
生成一个String来表示该值:
Instant.now().toString()
细节2016-09-13T23:30:52.123Z
正如Jon Skeet所说的正确答案所述,java.util.Date对象没有时区†.但是,toString
在生成该日期时间值的String表示时,其实现应用JVM的默认时区.令这个天真的程序员感到困惑的是,Date 似乎有一个时区,但却没有.
的java.util.Date
,j.u.Calendar
以及java.text.SimpleDateFormat
与Java绑定类是出了名的麻烦.避免他们.相反,使用这些主管日期时间库中的任何一个:
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表示.该格式根据需要输出零,三,六或九位数字(毫秒,微秒或纳秒)来表示秒数.
如果您想要更灵活的格式化或其他附加功能,那么对于UTC本身(ZoneOffset.UTC
常量),应用UTC的偏移量为零,以获得a OffsetDateTime
.
OffsetDateTime now = OffsetDateTime.now( ZoneOffset.UTC );
转储到控制台......
System.out.println( "now: " + now );
跑的时候......
now: 2014-01-21T23:42:03.522Z
java.time类由JSR 310定义.他们的灵感来自Joda-Time,但完全是重新设计的.
乔达时间更新:现在处于维护模式的Joda-Time项目建议迁移到java.time类.
使用Joda-Time第三方开源免费库,您只需一行代码即可获得当前日期时间.
Joda-Time启发了Java 8中新的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的当前默认时区(可以随时更改!).这种依赖似乎是造成日期工作混乱和错误的常见原因.
当呼叫java.util.Date
通过要分配的期望/预期时区时.使用该Calendar
课程.
DateTimeZone zoneMontréal = DateTimeZone.forID( "America/Montreal" ); DateTime now = DateTime.now( zoneMontréal );
该类保持UTC时区的常量.
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 SimpleDateFormat
方法使用的时区; 该方法使用JVM的当前默认时区.更有理由避免这种令人困惑的类并坚持使用Joda-Time和java.time.
这肯定会返回UTC时间:作为String和Date对象!
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; }
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.
此代码打印当前时间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
这适用于在Android中获取UTC毫秒.
Calendar c = Calendar.getInstance(); int utcOffset = c.get(Calendar.ZONE_OFFSET) + c.get(Calendar.DST_OFFSET); Long utcMilliseconds = c.getTimeInMillis() + utcOffset;
Jon Skeet问道:
@Downvoter:关注评论?我的回答究竟有什么不对? - Jon Skeet 09年10月26日21:09
我不是Downvoter,但这个答案似乎是不正确的.你说:
java.util.Date
始终是UTC.是什么让你觉得它是在当地时间?我怀疑问题是你通过使用本地时区的Calendar实例显示它,或者可能使用Date.toString()
也使用本地时区的实例 .
但是,代码:
System.out.println(new java.util.Date().getHours() + " hours");
给出当地时间,而不是GMT(UTC时间),使用no Calendar
和no SimpleDateFormat
.
这就是为什么似乎有些不正确的原因.
汇总答案,代码:
System.out.println(Calendar.getInstance(TimeZone.getTimeZone("GMT")) .get(Calendar.HOUR_OF_DAY) + " Hours");
显示格林尼治标准时间而不是当地时间 - 请注意getTime.getHours()
缺少,因为这会创建一个Date()
对象,理论上将日期存储在GMT中,但会返回当地时区的小时数.
如果你想要一个Date字段的字段调整为UTC,你可以使用Joda Time这样做:
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,直到你对日期对象做一些转换为本地时区的事情.
SimpleDateFormat dateFormatGmt = new SimpleDateFormat("yyyy-MM-dd"); dateFormatGmt.setTimeZone(TimeZone.getTimeZone("GMT")); System.out.println(dateFormatGmt.format(date));
你可以直接使用它
SimpleDateFormat dateFormatGmt = new SimpleDateFormat("dd:MM:yyyy HH:mm:ss"); dateFormatGmt.setTimeZone(TimeZone.getTimeZone("GMT")); System.out.println(dateFormatGmt.format(new Date())+"");
附:
Calendar cal = Calendar.getInstance();
然后cal
有当前的日期和时间.
您还可以通过以下方式获取时区的当前日期和时间:
Calendar cal2 = Calendar.getInstance(TimeZone.getTimeZone("GMT-2"));
您可以询问cal.get(Calendar.DATE);
或其他日历常量关于其他详细信息.
Java中不推荐使用日期和时间戳.日历类不是.
这里有另一个获取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)); }
这是以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());