如何在Java中转换UTC和本地时区
我对Java中的时区很好奇。我想从设备获取UTC时间(以毫秒为单位),然后发送到服务器。服务器将在向用户显示时间时将其转换为本地时区。我的系统中的时区是澳大利亚/悉尼(UTC+11:00),我在测试时区时得到以下结果:如何在Java中转换UTC和本地时区,java,timezone,Java,Timezone,我对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
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
我想我可以在2014年1月13日00:12:00进行指挥与控制,因为UTC时间比我的时间晚11小时。日历不是按我预期的方式工作吗
谢谢你的帮助
编辑
添加z以显示时区。这让我更加困惑,因为Mac说它的时区是澳大利亚东部夏时制(AEDT),而爪哇是东部夏时制(EST)。无论如何,结果还是不同的,因为EST是UTC-5小时。您可能是想在格式化程序上设置时区,而不是日历(或者除了日历之外,还没有100%清楚您想要完成什么)!用于创建人类表示的时区来自SimpleDataFormat。通过调用
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()));
正在打印2014年1月14日10:12:00
,因为Syndey中显示的上午11点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()));
“UTC毫秒”的概念毫无意义。毫秒数只是历史上的一个固定点,它没有与之关联的时区。我们向它添加了一个时区,以将其转换为人类可读的表示形式
编辑:是的,对(美国)东部时间和(澳大利亚)东部时间使用“EST”的模糊性一直是Java的一个陷阱。更新:这个答案现在已经过时了。Joda时间库现在被java 8及更高版本中内置的java.Time框架所取代。看 三字母代码 您应该避免使用3个或4个字母的时区代码,例如
EST
或IST
。它们既不标准也不独特
使用,主要是大陆/城市或地区
,如美洲/蒙特利尔
或亚洲/加尔各答
乔达时间
众所周知,java.util.Date/Calendar类非常糟糕。避免使用它们。在Java8中,使用JSR310定义的、受Joda Time启发的新的或
注意下面显示的Joda时间代码是多么简单和明显。乔达时间甚至知道如何计数——一月是1,而不是0
时区
在Joda Time中,实例知道自己的时区
标准时间比UTC/GMT提前10小时,夏令时(DST)提前11小时。DST适用于问题指定的日期
小贴士:不要这样想
UTC时间比我晚11小时
像这样想
悉尼夏令时比UTC/GMT早11小时
如果您使用UTC/GMT进行思考、工作和存储,则日期-时间工作将变得更容易,更不容易出错。仅转换为本地化的日期-时间,以便在用户界面中进行演示。全球化思考,本土化展示。您的用户和服务器可以轻松移动到其他时区,因此忘记您自己的时区。始终指定时区,不要假设或依赖默认值
示例代码
下面是一些使用JodaTime2.3和Java8的示例代码
// 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
UTC日期时间:2014-01-14T00:12:00.000Z
tl;博士
使用现代java.time类
138965832000
往另一个方向走
Instant
.ofEpochMilli( 1_389_658_320_000L ) // .toString(): 2014-01-14T00:12:00Z
.atZone(
ZoneId.of( "Australia/Sydney" )
) // .toString(): 2014-01-14T11:12+11:00[Australia/Sydney]
.format(
DateTimeFormatter
.ofPattern (
"dd/MM/uuuu HH:mm:ss z" ,
new Locale( "en" , "AU" )
)
)
Instant instant = Instant.ofEpochMilli( millisecondsSinceEpoch ) ;
2014年1月14日11:12:00 AEDT
java.time
您正在使用可怕的日期时间类,这些类在几年前由于采用JSR310定义现代java.time类而过时
我对Java中的时区很好奇
仅供参考,与UTC的偏差仅为小时分秒数。当我们说“UTC”或在字符串末尾加一个Z
时,我们指的是UTC本身的零小时分秒偏移量
时区更重要。时区是特定地区人民使用的偏移量的过去、现在和未来变化的历史。世界各地的政客都有一种奇怪的倾向,那就是改变他们管辖权的偏移量
我想从设备获取UTC时间(以毫秒为单位),然后发送到服务器
对于当前时刻,请使用。Instant
内部是自1970 UTC第一时刻的历元参考开始的整秒数,加上以纳秒为单位的几分之一秒
Instant now = Instant.now() ; // Capture current moment in UTC.
long millisecondsSinceEpoch = now.toEpochMilli() ;
往另一个方向走
Instant
.ofEpochMilli( 1_389_658_320_000L ) // .toString(): 2014-01-14T00:12:00Z
.atZone(
ZoneId.of( "Australia/Sydney" )
) // .toString(): 2014-01-14T11:12+11:00[Australia/Sydney]
.format(
DateTimeFormatter
.ofPattern (
"dd/MM/uuuu HH:mm:ss z" ,
new Locale( "en" , "AU" )
)
)
Instant instant = Instant.ofEpochMilli( millisecondsSinceEpoch ) ;
服务器将把它转换为本地时区
指定用户所需/预期的时区
如果未指定时区,JVM将隐式应用其当前默认时区。该默认值可能在运行时(!)期间出现,因此您的结果可能会有所不同。最好将所需/预期时区明确指定为参数。如果关键,请与用户确认区域
以大陆/地区
的格式指定,例如美国/蒙特利尔
,非洲/卡萨布兰卡
,或太平洋/奥克兰
。切勿使用2-4个字母的缩写,如EST
或IST
,因为它们不是真正的时区,也不是标准化的,甚至不是唯一的(!)
…当它向用户显示时间时
自动本地化用户的语言和文化
要本地化,请指定:
- 确定字符串的长度或缩写
- 确定:
- 翻译日名、月名等的人类语言
- 决定缩写、大写、标点、分隔符等问题的文化规范
Locale l = Locale.CANADA_FRENCH ; // Or Locale.US, Locale.JAPAN, etc.
DateTimeFormatter f =
DateTimeFormatter
.ofLocalizedDateTime( FormatStyle.FULL )
.withLocale( l )
;
String output = zdt.format( f );
我的系统中的时区
ZoneID zAuSydney = ZoneId.of( "Australia/Sydney" ) ;
ZonedDateTime zdt = instant.atZone( zAuSydney ) ;
String output = zdt.format(
DateTimeFormatter
.localizedDateTime( FormatStyle.LONG )
.withLocale( new Locale( "en" , "AU" ) ;
) ;
LocalDate ld = LocalDate.of( 2014 , 1 , 14 ) ;
LocalTime lt = LocalTime.of( 11 , 12 ) ;
ZoneId z = ZoneId.of( "Australia/Sydney" ) ;
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z ) ;
Locale locale = new Locale ( "en" , "AU" );
ZoneId z = ZoneId.of ( "Australia/Sydney" );
ZonedDateTime zdt = ZonedDateTime.of ( 2014 , 1 , 14 , 11 , 12 , 0 , 0 , z );
DateTimeFormatter f = DateTimeFormatter.ofPattern ( "dd/MM/uuuu HH:mm:ss z" , locale );
String output = zdt.format ( f );
Instant instant = zdt.toInstant() ; // Adjust from time zone to UTC.
long millisecondsSinceEpoch = instant.toEpochMilli() ;
final String time="UTC";
int year = 2014;
int month = 0;
int date = 14;
int hourOfDay = 11;
int minute = 12;
int second = 0;
calendar.set(year, month, date, hourOfDay, minute, second);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSz");
System.out.println(sdf.format(calendar.getTime()));
Calendar calendar1=Calendar.getInstance();
Date dat= calendar.getTime();
calendar1.set(year,month,date,hourOfDay,minute,second);
sdf.setTimeZone(TimeZone.getTimeZone(time));
System.out.println(sdf.format(calendar1.getTime()));