我对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()));
Run Code Online (Sandbox Code Playgroud)
输出:
14/01/2014 11:12:00 EST
14/01/2014 22:12:00 EST
Run Code Online (Sandbox Code Playgroud)
我想我可以在13/01/2014 00:12:00为c2,因为UTC时间晚于我的11小时.日历不按我期望的方式工作吗?
非常感谢您的帮助.
添加了z以显示时区.这让我更加困惑,因为Mac说它的时区是(AEDT)澳大利亚东部夏令时,但Java是EST.无论如何,结果仍然不同,因为EST是UTC-5小时.
Bas*_*que 11
您应该避免使用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).
Run Code Online (Sandbox Code Playgroud)
转储到控制台......
System.out.println("dateTime: " + dateTime);
System.out.println("dateTimeUtc: " + dateTimeUtc);
Run Code Online (Sandbox Code Playgroud)
跑的时候......
dateTime: 2014-01-14T11:12:00.000+11:00
dateTime in UTC: 2014-01-14T00:12:00.000Z
Run Code Online (Sandbox Code Playgroud)
您可能打算在格式化程序上设置时区,而不是日历(或者除了日历之外,它不是100%明确您要完成的内容)!用于创建人工表示的时区来自SimpleDateFormat.当您通过调用将其转换回java.util.Date时,所有"时区"信息都会从日历中丢失getTime().
代码:
Calendar c2 = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
c2.set(year, month, date, hourOfDay, minute, second);
System.out.println(sdf.format(c2.getTime()));
Run Code Online (Sandbox Code Playgroud)
正在打印,14/01/2014 10:12:00因为在Syndey(格式化程序的时区)中显示的11AM UTC是晚上10点!(以24小时的格式使用HH)
这将打印出您打算做的事情:
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()));
Run Code Online (Sandbox Code Playgroud)
"UTC毫秒"的概念毫无意义.一定数量的毫秒只是历史中的一个固定点,它没有与之相关的时区.我们为它添加一个时区,将其转换为人类可读的表示形式.
编辑:是的,从(美国)东部时间和(澳大利亚)东部时间使用'EST'的模糊性一直是Java的陷阱.