我过去几个小时一直在网上搜索,以便在我的系统时区获得日期时间。
当我使用calendar.getTimezone.getDefaultName时,它总是返回GMT。 (理想情况下它应该返回我当前的时区,即IST) 我正在尝试将此字符串“2014-02-14T06:04:00:00”转换为我的时区日期时间。 它总是在格林尼治标准时间回归我。
我只看到每个人都建议使用Timezone。即,
dateFormatter.setTimezone("any_arbitary_timezone");
点是我的应用程序将用于不同的地理位置。我无法将其设置为特定时区。它应该设置为系统时区,以便它可以显示在用户当前所在的任何时区
答案 0 :(得分:47)
使用现代 java.time 类。
ZonedDateTime.now( // Capture the current moment in the wall-clock time used by the people of a certain region (a time zone).
ZoneId.systemDefault() // Get the JVM’s current default time zone. Can change at any moment during runtime. If important, confirm with the user.
) // Renders a `ZonedDateTime` object. To see the same moment in UTC, extract a `Instant` object by calling `ZonedDateTime::getInstant`.
您可以省略对ZoneId.systemDefault
的显式调用。
ZonedDateTime.now() // Capture the current moment in the JVM’s current default time zone.
将您的字符串解析为LocalDateTime
,并调整到所需的时区。
LocalDateTime.parse( "2014-02-14T06:04:00:00" ) // Parse a string lacking any indicator of time zone or offset-from-UTC. *Not* a specific point on the timeline.
.atOffset( ZoneOffset.UTC ) // Apply UTC as we are certain that offset-from-UTC of zero was intended by the supplier of that input string. Returns a `OffsetDateTime` object.
.atZoneSameInstant( // Adjust into another time zone. The `sameInstant` part means the same moment, different wall-clock time.
ZoneId.of( "Africa/Tunis" ) // Specify the particular zone of interest to you.
) // Returns a `ZonedDateTime` object.
java.util.Date
& .Calendar
这些遗留类是众所周知的麻烦。 Sun / Oracle在Java 8中添加了java.time包来取代它们。该套餐的灵感来自Joda-Time。
遗留类中的问题包括这种令人困惑的行为:虽然java.util.Date没有时区信息,但它的toString
实现在生成String时应用JVM的当前默认时区。因此,当它没有时区时,它会误导你。
我正在尝试转换此字符串" 2014-02-14T06:04:00:00",...
您的输入字符串缺少任何时区指示符或与UTC的偏移量。所以我们解析为LocalDateTime
,它没有任何区域/偏移的概念。
LocalDateTime
不表示片刻,不时间轴上的某个点。这里的“本地”一词不表示特定的地点。这意味着“根本没有特定的地方”。没有区域/偏移的上下文,它没有实际意义。
LocalDateTime ldt = LocalDateTime.parse( "2014-02-14T06:04:00:00" ) ;
......这是格林尼治标准时间......
您说您确定该输入字符串的供应商将UTC作为上下文。我们可以应用从零开始的UTC偏移量或UTC本身来获取OffsetDateTime
对象。 OffsetDateTime
是片刻,时间轴上的一个点。我们可以使用UTC的常量ZoneOffset.UTC
指定ZoneOffset
。
OffsetDateTime odt = ldt.atOffset( ZoneOffset.UTC ) ;
...到我的时区日期时间
显然,您希望将该时刻调整到另一个时区,以查看特定地区人员使用的挂钟时间。我们需要应用时区(ZoneId
)才能获得ZonedDateTime
。
ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = odt.atZone( z ) ;
您可以向JVM询问其当前的默认时区,而不是指定时区。注意:JVM当前的默认时区可以随时由该JVM中任何应用程序的任何线程中的任何代码更改。
ZoneId z = ZoneId.systemDefault() ;
ZonedDateTime zdt = odt.atZone( z ) ;
点是我的应用程序将在不同的地理位置使用。
只需明确指定所需/预期的时区。在我看来,这是总是的良好做法。作为程序员,默认时区位于您的控制之外,这使得它不可靠。
以continent/region
的格式指定proper time zone name,例如America/Montreal
,Africa/Casablanca
或Pacific/Auckland
。切勿使用诸如EST
或IST
之类的3-4字母缩写,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。
另一个提示:以UTC工作,思考,存储和交换。忘记你自己的狭隘时区,因为来回翻译到你的家乡区域会让你感到沮丧。将UTC视为 One True Time ,其他区域/偏移仅仅是变化。
Instant instant = Instant.now() ; // Capture current moment in UTC.
ZoneId zAuckland = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime zdtAuckland = instant.atZone( zAuckland ) ;
ZoneId zKolkata = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdtKolkata = instant.atZone( zKolkata ) ;
ZoneId zCasablanca = ZoneId.of( "Africa/Casablanca" ) ;
ZonedDateTime zdtCasablanca = instant.atZone( zCasablanca ) ;
我们有四种方式(instant
,zdtAuckland
,zdtKolkata
,zdtCasablanca
)查看同一时刻,即时间轴上的相同点。
instant.toString():2018-05-08T20:55:14.761721Z
zdtAuckland.toString():2018-05-09T08:55:14.761721 + 12:00 [太平洋/奥克兰]
zdtKolkata.toString():2018-05-09T02:25:14.761721 + 05:30 [亚洲/加尔各答]
zdtCasablanca.toString():2018-05-08T21:55:14.761721 + 01:00 [非洲/卡萨布兰卡]
来自UTC的偏移量只是小时数,分钟数和秒数。没有更多,没有更少。任何数量的时区都可能在特定时刻共享特定的偏移量。
时区是特定地区人民使用的偏移的过去,现在和将来变化的历史记录。例如,夏令时(DST)是一个地区的人(莫名其妙地)决定每年两次更改其偏移量的做法。
因此,时区总是优于仅仅偏移。拥有区域允许我们以有意义的方式添加或减去时间,以考虑该区域历史中偏移的变化。
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类?
ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如Interval
,YearWeek
,YearQuarter
和more。
更新:Joda-Time项目现在处于维护模式。该团队建议迁移到java.time类。跳到本答案中下面的java.time部分。
Joda-Time软件包对时区有明确的支持。与java.util.Date不同,Joda-Time DateTime确实知道自己指定的时区。如果您未指定时区,则会隐式分配JVM的当前默认时区。
DateTime dateTime = DateTime.now(); // Applies JVM’s default time zone implicitly.
我建议不要隐含地依赖默认时区。这样做会导致日期工作时出现混淆和错误。
DateTime dateTime = DateTime.now( DateTimeZone.getDefault() ); // Explicitly using default time zone.
如果需要,您可以指定时区。
DateTime dateTimeKolkata = DateTime.now( DateTimeZone.forID( "Asia/Kolkata" ) ); // Specify a time zone.
对于服务器端工作,最佳做法是在UTC中进行业务逻辑和数据库存储。
DateTime dateTimeUtc = DateTime.now( DateTimeZone.UTC ); // Assign UTC (GMT) time zone.
您可以从指定的时区转换为另一个时区,包括JVM当前的默认时区。
DateTime dateTime = dateTimeUtc.withZone( DateTimeZone.getDefault() );
对于线程安全,Joda-Time使用immutable objects。 withZone
等方法不是修改对象,而是根据原始方法创建新实例。
要将String解析为DateTime,您必须注意String是否包含与UTC和/或时区的偏移量。你的没有。因此,您必须指定用于解释该String的时区。如果未指定,则在解析期间将使用JVM的当前默认时区。
DateTime dateTimeUtc = new DateTime( "2014-02-14T06:04:00:00", DateTimeZone.UTC );
解析后,您可以根据需要指定另一个时区。宇宙时间线上的相同时刻,但显示不同的Wall-Clock time。
DateTime dateTimeDefaultZone = dateTimeUtc.withZone( DateTimeZone.getDefault() );
请注意,这是一个两步的过程。首先,我们使用我们对该String的预期时区的外部知识来解析您的String,因为它缺少该时区或偏移的内部表示。其次,我们将时区调整为另一个(JVM默认区域)。
如果您的字符串包含+00:00
或习惯Z
的偏移量,我们可以将这两个步骤合并为一个。
DateTime dateTimeDefaultZone = new DateTime( "2014-02-14T06:04:00:00Z", DateTimeZone.getDefault() ); // Apply time zone adjustment *after* parsing.
请注意,此DateTime构造函数与上面的构造函数类似,但实际上却完全不同。这个时区参数在解析后应用,而不是在解析期间应用。这里时区参数用于调整已解析的DateTime。最后Z
会让世界变得不同。
JVM最初从主机操作系统获取其默认时区。但请注意,程序员可以通过以下方式覆盖它:
java.util.TimeZone.setDefault
。执行此覆盖会影响该JVM中运行的所有应用程序的所有线程。所以你应该知道JVM的默认时区通常与主机操作系统相同,但不一定相同。
答案 1 :(得分:10)
以下是获取与您的本地系统时钟偏移相匹配的TimeZone
的ID的方法,
Calendar cal = Calendar.getInstance();
long milliDiff = cal.get(Calendar.ZONE_OFFSET);
// Got local offset, now loop through available timezone id(s).
String [] ids = TimeZone.getAvailableIDs();
String name = null;
for (String id : ids) {
TimeZone tz = TimeZone.getTimeZone(id);
if (tz.getRawOffset() == milliDiff) {
// Found a match.
name = id;
break;
}
}
System.out.println(name);
答案 2 :(得分:1)
output = model(inp)
答案 3 :(得分:0)
我相信你要找的是Joda库。它的功能比答案here中指定的Calendar或Date类更好。
This function应该特别有用。