我已经从 String 解析了 java.util.Date ,但它将本地时区设置为 date 对象的时区 .
时间区域未在 String 中指定,从中解析 Date . 我想设置 date 对象的特定时区 .
我怎样才能做到这一点?
8 回答
144
使用DateFormat . 例如,
SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
isoFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = isoFormat.parse("2010-05-23T09:01:02");
0
请注意 java.util.Date 对象本身不包含任何时区信息 - 您无法在 Date 对象上设置时区 . Date 对象包含的唯一内容是自"epoch" - 1970年1月1日00:00:00 UTC以来的毫秒数 .
LocalDateTime.parse( "2018-01-23T01:23:45.123456789" ) // Parse string, lacking an offset-from-UTC and lacking a time zone, as a `LocalDateTime`.
.atZone( ZoneId.of( "Africa/Tunis" ) ) // Assign the time zone for which you are certain this date-time was intended. Instantiates a `ZonedDateTime` object.
Date date1 = new Date();
System.out.println(date1);
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
// or pass in a command line arg: -Duser.timezone="UTC"
Date date2 = new Date();
System.out.println(date2);
/**
* Converts the given <code>date</code> from the <code>fromTimeZone</code> to the
* <code>toTimeZone</code>. Since java.util.Date has does not really store time zome
* information, this actually converts the date to the date that it would be in the
* other time zone.
* @param date
* @param fromTimeZone
* @param toTimeZone
* @return
*/
public static Date convertTimeZone(Date date, TimeZone fromTimeZone, TimeZone toTimeZone)
{
long fromTimeZoneOffset = getTimeZoneUTCAndDSTOffset(date, fromTimeZone);
long toTimeZoneOffset = getTimeZoneUTCAndDSTOffset(date, toTimeZone);
return new Date(date.getTime() + (toTimeZoneOffset - fromTimeZoneOffset));
}
/**
* Calculates the offset of the <code>timeZone</code> from UTC, factoring in any
* additional offset due to the time zone being in daylight savings time as of
* the given <code>date</code>.
* @param date
* @param timeZone
* @return
*/
private static long getTimeZoneUTCAndDSTOffset(Date date, TimeZone timeZone)
{
long timeZoneDSTOffset = 0;
if(timeZone.inDaylightTime(date))
{
timeZoneDSTOffset = timeZone.getDSTSavings();
}
return timeZone.getRawOffset() + timeZoneDSTOffset;
}
8 回答
使用DateFormat . 例如,
请注意
java.util.Date
对象本身不包含任何时区信息 - 您无法在Date
对象上设置时区 .Date
对象包含的唯一内容是自"epoch" - 1970年1月1日00:00:00 UTC以来的毫秒数 .正如ZZ Coder所示,您可以在
DateFormat
对象上设置时区,告诉它您要在哪个时区显示日期和时间 .tl;博士
j.u.Date中没有时区
正如其他正确答案所述,java.util.Date没有时区† . 它代表UTC / GMT(没有时区偏移) . 非常混乱,因为它的
toString
方法在生成String表示时应用JVM的默认时区 .避免j.u.Date
出于这个原因和其他许多原因,您应该避免使用内置的java.util.Date和.Calendar&java.text.SimpleDateFormat . 众所周知,它们很麻烦 .
而是使用与Java 8捆绑在一起的java.time package .
java.time
java.time类可以通过三种方式表示时间轴上的时刻:
UTC(
Instant
)带偏移量(
OffsetDateTime
,带ZoneOffset
)带时区(
ZonedDateTime
,带ZoneId
)瞬发
在java.time中,基本构建块是Instant,是UTC时间线上的一个时刻 . 将
Instant
对象用于大部分业务逻辑 .OffsetDateTime
应用offset-from-UTC调整到某个地区的wall-clock time .
应用ZoneOffset获取OffsetDateTime .
ZonedDateTime
更好的是应用time zone,偏移加上处理异常的规则,例如Daylight Saving Time (DST) .
将ZoneId应用于
Instant
以获得ZonedDateTime . 始终指定proper time zone name . 切勿使用EST
或IST
等3-4个缩写,既不是唯一的也不是标准化的 .LocalDateTime
如果输入字符串缺少偏移量或区域的任何指示符,则解析为LocalDateTime .
如果您确定预期的时区,请指定
ZoneId
以生成ZonedDateTime
. 请参阅顶部的tl; dr部分中的上面的代码示例 .格式化字符串
在这三个类中的任何一个上调用
toString
方法,以生成一个表示标准ISO 8601格式的日期时间值的String .ZonedDateTime
类通过在括号中附加时区名称来扩展标准格式 .对于其他格式,请使用DateTimeFormatter类 . 通常最好让该类使用用户期望的人类语言和文化规范生成本地化格式 . 或者您可以指定特定格式 .
关于java.time
java.time框架内置于Java 8及更高版本中 . 这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date,Calendar和SimpleDateFormat .
Joda-Time项目,现在在maintenance mode,建议迁移到java.time类 .
要了解更多信息,请参阅Oracle Tutorial . 并搜索Stack Overflow以获取许多示例和解释 . 规格是JSR 310 .
您可以直接与数据库交换java.time对象 . 使用JDBC driver符合JDBC 4.2或更高版本 . 不需要字符串,不需要
java.sql.*
类 .从哪里获取java.time类?
Java SE 8,_ 120020017,Java SE 10,Java SE 11和更高版本 - 带有捆绑实现的标准Java API的一部分 .
Java 9增加了一些小功能和修复 .
Java SE 6和Java SE 7
大多数java.time功能在ThreeTen-Backport中被反向移植到Java 6和7 .
Android
更新版本的Android捆绑java.time类的实现 .
对于早期的Android(<26),ThreeTenABP项目适应ThreeTen-Backport(如上所述) . 见How to use ThreeTenABP… .
ThreeTen-Extra项目使用其他类扩展了java.time . 该项目是未来可能添加到java.time的试验场 . 你可能会在这里找到一些有用的类,如Interval,YearWeek,YearQuarter,和more .
Joda-Time
虽然Joda-Time仍在积极维护,但其制造商告诉我们尽快迁移到java.time . 我保留此部分作为参考,但我建议使用上面的
java.time
部分 .在Joda-Time中,日期时间对象(DateTime)确实知道其指定的时区 . 这意味着与UTC的偏移以及该时区的夏令时(DST)和其他此类异常的规则和历史记录 .
调用
toString
方法以ISO 8601格式生成字符串 .Joda-Time还提供丰富的功能来生成各种其他String格式 .
如果需要,您可以从Joda-Time DateTime转换为java.util.Date .
在“joda date”中搜索StackOverflow以查找更多示例,其中一些非常详细 .
†实际上java.util.Date中嵌入了一个时区,用于某些内部函数(请参阅本答案中的注释) . 但是此内部时区不作为属性公开,并且无法设置 . 此内部时区不是toString方法在生成日期时间值的字符串表示形式时使用的时区;相反,JVM的当前默认时区是即时应用的 . 所以,作为简写,我们经常说“j.u.Date没有时区” . 混乱?是 . 避免这些疲惫的旧课程的另一个原因 .
您还可以在JVM级别设置时区
输出:
java.util.Calendar是使用JDK类处理时区的常用方法 . Apache Commons还有一些可能有用的替代品/实用工具 . Edit Spong 's note reminded me that I'听说Joda-Time真的很好吃(虽然我自己没有用过它) .
如果必须只使用标准JDK类,则可以使用:
归功于post .
如果有人需要这个,如果你需要将
XMLGregorianCalendar
时区从UTC转换为当前时区,那么你需要做的就是将时区设置为0
,然后调用toGregorianCalendar()
- 它将保持相同的时区,但Date
知道如何将它转换为你的,所以你可以从那里获取数据 .结果:
将Date转换为String并使用SimpleDateFormat执行此操作 .