如何在Java中转换UTC和本地时区
我对Java中的时区感到好奇。 我希望从设备获得UTC时间(以毫秒为单位)并发送到服务器。 当服务器向用户显示时间时,服务器会将其转换为本地时区。 我的系统中的时区是澳大利亚/悉尼(UTC + 11:00),当我测试时区时,我得到了以下结果:
int year = 2014; int month = 0; int date = 14; int hourOfDay = 11; int minute = 12; int second = 0; Calendar c1 = Calendar.getInstance(); c1.set(year, month, date, hourOfDay, minute, second); SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss z"); System.out.println(sdf.format(c1.getTime())); Calendar c2 = Calendar.getInstance(TimeZone.getTimeZone("UTC")); c2.set(year, month, date, hourOfDay, minute, second); System.out.println(sdf.format(c2.getTime()));
输出:
14/01/2014 11:12:00 EST 14/01/2014 22:12:00 EST
我以为我可以在13/01/2014 00:12:00为c2,因为UTC时间晚于我的11小时。 日历不按我期望的方式工作吗?
非常感谢您的帮助。
编辑
添加了z以显示时区。 这让我更加困惑,因为Mac说它的时区是(AEDT)澳大利亚东部夏令时,但Java是EST。 无论如何,结果仍然不同,因为EST是UTC-5小时。
您可能打算在格式化程序上设置时区,而不是日历(或者除了日历之外,它不是100%明确您要完成的内容)! 用于创建人工表示的时区来自SimpleDateFormat。 当您通过调用getTime()
将其转换回java.util.Date时,所有“时区”信息都会从日历中丢失。
代码:
Calendar c2 = Calendar.getInstance(TimeZone.getTimeZone("UTC")); c2.set(year, month, date, hourOfDay, minute, second); System.out.println(sdf.format(c2.getTime()));
正在打印14/01/2014 10:12:00
因为在Syndey(格式化程序的时区)显示的上午11点UTC是晚上10点! (在格式中使用HH 24小时)
这将打印出您打算做的事情:
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss z"); System.out.println(sdf.format(c1.getTime())); sdf.setTimeZone(TimeZone.getTimeZone("UTC")); System.out.println(sdf.format(c1.getTime()));
“UTC毫秒”的概念毫无意义。 毫秒数量只是历史中的一个固定点,它没有与之相关的时区。 我们为它添加一个时区,将其转换为人类可读的表示forms。
编辑:是的,从(美国)东部时间和(澳大利亚)东部时间使用’EST’的模糊性一直是Java的陷阱。
三字母代码
您应该避免使用3或4个字母的时区代码,例如EST
或IST
。 它们既不标准也不独特。
使用适当的时区名称 ,主要是Continent/CityOrRegion
例如America/Montreal
或Asia/Kolkata
。
乔达时间
众所周知,java.util.Date / Calendar类很糟糕。 避免使用它们。 使用Joda-Time或Java 8中由JSR 310定义并受Joda-Time启发的新java.time。*类 。
请注意下面显示的Joda-Time代码更简单,更明显。 Joda-Time甚至知道如何计算 – 一月是1,而不是0!
时区
在Joda-Time中, DateTime实例知道自己的时区。
悉尼澳大利亚的标准时间比UTC / GMT提前10小时,夏令时(DST)提前11小时。 DST适用于问题指定的日期。
提示:不要这样想……
UTC时间比我的晚11个小时
想这样……
悉尼DST比UTC / GMT早11个小时。
如果您以UTC / GMT思考,工作和存储,日期时间工作变得更容易,并且更不容易出错。 仅转换为本地化的日期时间,以便在用户界面中进行演示。 全球思考,在本地展示。 您的用户和服务器可以轻松移动到其他时区,因此请忘记您自己的时区。 始终指定时区,永远不要假设或依赖默认值。
示例代码
下面是一些使用Joda-Time 2.3和Java 8的示例代码。
// Better to specify a time zone explicitly than rely on default. // Use time zone names, not 3-letter codes. // This list is not quite up-to-date (read page for details): http://joda-time.sourceforge.net/timezones.html DateTimeZone timeZone = DateTimeZone.forID("Australia/Sydney"); DateTime dateTime = new DateTime(2014, 1, 14, 11, 12, 0, timeZone); DateTime dateTimeUtc = dateTime.toDateTime(DateTimeZone.UTC); // Built-in constant for UTC (no time zone offset).
转储到控制台……
System.out.println("dateTime: " + dateTime); System.out.println("dateTimeUtc: " + dateTimeUtc);
跑的时候……
dateTime: 2014-01-14T11:12:00.000+11:00 dateTime in UTC: 2014-01-14T00:12:00.000Z