10

我是java的新手,因此很长一段时间以来一直无法解决这个问题。

我使用的是 Windows XP,机器设置为 TimeZone: Eastern Time (US & Canada)

我有一个 Java 应用程序,它获取当前系统时间和时区信息,并将如下字符串写入文件:20101012 15:56:00 EST。

上面的最后一段日期,即:时区,随着我更改系统日期而从 EST 更改为 EDT。

准确地说:从 11 月(例如:Nov2009)到 3 月(2010 年 3 月),为 EST,否则为 EDT。

EST 是我一直想要的,而不是 EDT

是否有任何特定的类/函数,我总是可以将其读取为 EST?

等待回复。


感谢您的回复。好吧,我忘了提几件事。

  1. 我希望我的机器设置为:Windows 时区设置中的东部时间(美国和加拿大)。

  2. 简单来说,我想做的是:获取我的机器时间,并将其写入文本文件

  3. 我知道从三月到十一月的夏令时。

但问题是,当我将我的机器时间写入文件时,如果夏令时 (DST) 不存在,则写入为 2010 01 12 15:56:00 EST,如果 DST 是,则写入为 20101012 15:56:00 EDT展示。我担心的是,无论是否是 DST,我都想一直写 EST。

4

7 回答 7

2

我会创建一个自定义区域:

TimeZone alwaysEst = TimeZone.getTimeZone("EST+5");

这将报告为 EST,并且总是比 UTC 早 5 小时。特别是,不要选择现有的时区,否则当时区更新更改定义时,您最终会被烧毁。

请注意,通过强制 EST,您登录的日期将仅匹配系统显示的一年中 5 个月的时间。剩下的 7 个月你会休息一个小时。它可能会简化文件的解析,但会使用户感到困惑。

于 2010-10-14T17:17:44.080 回答
2

我认为你不应该按照你的建议去做。

您是说无论您的系统时区当前是什么(东部时间不是您的时区,但 UTC+5 或 +4 是),您都希望它显示 EST。这显然是错误的。假设现在是夏天,你的电脑认为本地是 2010/6/15 15:00。您打印当前时间并获得:

我打印出来的时间:2010 06 15 15:00:00 EDT

无论出于何种原因,您认为 EDT 令人不快,因此您将其更改为 EST:

我在 2010 年 6 月 15 日 15:00:00 EST 打印出来

但是,如果您在接下来的一个小时内将该片段发送给其他人,他们将被迫认为您来自未来!由于 15:00:00 EST 是 16:00:00 EDT。

于 2010-10-14T18:00:37.067 回答
2

日期时间工作很棘手

我是java的新手,因此很长一段时间以来一直无法解决这个问题。

即使是经验丰富的程序员,日期时间处理也出奇地棘手。这些概念相当模糊。各行各业的各种人都发展了各种做法,从而使事情复杂化。

幸运的是,Java 现在已经内置了业界领先的日期时间工作框架:在 JSR 310 中定义的java.time 。

明确指定所需/预期的时区

我使用的是 Windows XP,并且机器设置为 TimeZone:

主机操作系统不应影响您在 Java 中的日期时间处理工作。

永远不要依赖主机当前的默认时区。该默认值可以随时更改,因此它超出了程序员的控制范围。相反,请在 Java 代码中指定所需/预期的时区。

ZoneId z = ZoneId.of( "America/New_York" ) ;

EDT/Eastern Time不是

… 东部时间(美国和加拿大)。

没有真正的“东部时间”这样的东西。这个不精确的术语是一个手提包集合名词,用于描述各个时区使用的当前与 UTC 的偏移量。在进行编程时,忘掉“东部时间”、“东部标准时间”和其他伪时区。

偏移与区域

了解偏移只是本初子午线之前或之后的几个小时-分钟-秒。偏移量看起来像+05:30or -05:00

时区更多。时区是特定地区的人们使用的偏移量的过去、现在和未来变化的历史。时区的规则是由政客们反复设定的,并且以惊人的频率变化。

正确的时区名称由Continent/RegionAmerica/Montreal组成America/New_York。请参阅Wikipedia 上的此区域列表(可能不是最新的)。

ISO 8601

将类似:20101012 15:56:00 EST 的字符串写入文件。

对于被序列化为文本的日期时间值的格式,我们有一个正式的国际标准:ISO 8601。不要自己发明!标准格式经过精心设计,实用、易于机器解析,并且易于跨文化的人类阅读。

例如,魁北克省 2010 年 10 月 12 日将近下午 4 点将是:

2010-10-12T15:56-04:00

java.time类在解析/生成文本时默认使用 ISO 8601 格式。所以不需要指定格式模式。用于表示通过特定时区看到的时刻。ZonedDateTime

ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = ZonedDateTime.of( 2010 , 10 , 12 , 15 , 56 , 0 , 0 , z ) ;

ZonedDateTime::toString方法明智地扩展了标准格式,将区域名称附加在方括号中。

zdt.toString(): 2010-10-12T15:56-04:00[美国/蒙特利尔]

解析这样的字符串。

ZonedDateTime zdt2 = ZonedDateTime.parse( "2010-10-12T15:56-04:00[America/Montreal]" ) ;
boolean sameZdts = zdt.equals ( zdt2 ) ;

相同的Zdts:真

查看在 IdeOne.com 上实时运行的代码

夏令时 (DST)

EST 是我一直想要的,而不是 EDT。

你的目标没有意义。

这些伪区域 ( EST& EDT) 旨在指示夏令时 (DST)何时生效以及标准时间何时生效。因此,希望始终在遵守 DST 的区域(时区)中使用标准时间是矛盾的,而且是不可能的。

因此,如果您试图通过特定地区(时区)的人们使用的挂钟时间来表示一个时刻,您应该通过 指定日期、时间和时区ZoneId,让java.time处理 DST 是否生效的问题。

LocalDate ld = LocalDate.of( 2010 , Month.OCTOBER , 12 ) ;
LocalTime lt = LocalTime.of( 15 , 56 , 0 ) ;
ZoneId z = ZoneId.of( "America/New_York" ) ;
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z ) ;

zdt.toString(): 2010-10-12T15:56-04:00[America/New_York]

要在 UTC 中查看同一时刻,请提取Instant. 同一时刻,时间线上的同一点,不同的挂钟时间。

Instant instant = zdt.toInstant() ;

即时.toString(): 2010-10-12T19:56:00Z

请参阅上面的代码在 IdeOne.com 上实时运行

预订未来的约会

正在处理我需要告诉的服务器:“在 20101015 15:30:30 xxx 执行任务”xxx 是时区。无论是哪个月份,服务器都只了解 EST 而不是 EDT。因此,EDT 令人不快。

关于 EST 与 EDT,我们已经将您的担忧视为毫无意义/无关紧要。当特定时区切入/切出 DST 时,标准时间与夏令时的这些标志会自动切换。

至于未来的预约,您无法知道夏令时(DST)是否有效。您不知道是否对您的时区规则进行了其他一些古怪的调整。

如上所述,时区定义由反复无常的政客控制。在世界各地,他们对频繁变化表现出惊人的嗜好。几十年来,美国已多次更改其夏令时转换的日期。近年来,俄罗斯多次采用和放弃夏令时。最新的时尚是全年保持 DST,最近由土耳其和摩洛哥完成,美国也即将这样做。

因此,如果您希望在一天中的某个时间完成约会或任务,您可以将其表示为 a LocalDateTime,它表示没有偏移/区域上下文的日期和时间,另外还分别表示预期时区 ( ZoneId)。

LocalDate ld = LocalDate.of( 2020 , Month.MARCH , 15 ) ;
LocalTime lt = LocalTime.of( 15 , 0 ) ;
LocalDateTime ldt = LocalDateTime.of( ld , lt ) ;
ZoneId z = ZoneId.of( "America/Thunder_Bay" ) ;

上面的代码描述了我们打算什么时候发生,但无法确定某个时刻。我们不知道 3 月 15 日下午 3 点何时会发生,因为控制America/Thunder_Bay时区的政客随时可能重新定义时区。所以我们所能做的就是偶尔动态地尝试一下。当您需要建立日历,或安排某事发生时,您必须将时区应用到LocalDateTime(不是片刻)以产生ZonedDateTime(片刻)。

ZonedDateTime zdt = ZonedDateTime.of( ldt , z ) ;
Instant instant = zdt.toInstant() ;  // Adjust from zone to UTC (an offset of zero). Same moment, same point on the timeline.

Java 中的日期时间类型表,包括现代和传统

执行者

要安排您的任务运行,请了解Java 中内置的Executors 框架。具体来说,ScheduledExecutorService类。

冷杉计算您等待运行任务的经过时间。

Duration duration = Duration.between( Instant.now() , instant );

将要运行的任务定义为Runnable. 这里我们使用现代的 lambda 语法,但这不是重点。

Runnable runnable = ( ) -> {
    System.out.println( "Running our task now: " + Instant.now() );
};

安排您的任务运行。ScheduledFuture如果要跟踪完成,可以选择捕获返回的。

final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
ScheduledFuture future = scheduler.schedule( runnable , duration.toMinutes() , TimeUnit.MINUTES );

重要提示:请务必正常关闭您的ScheduledExecutorService. 否则,线程池可能会继续运行,即使在您结束程序之后也是如此。

于 2020-02-01T21:05:38.280 回答
0

应该注意的是,在东部时区的夏季月份,几乎每个主要中心都使用夏令时,因此您可以正确地看到该时区​​的人们关心的时间。

如果您希望它是一个特定的时区,而不是默认/系统时区,那么您可以通过以下方式将TimeZone强制为 EST:

TimeZone est = TimeZone.getTimeZone("EST");

尽管正如迈克尔上面提到的,文档建议使用本地全名,例如“America/New York”,而不是通用时区缩写。

如果您想声称它确实是 EST,即使您知道它是 EDT,那么我想您可以执行以下操作:使用具有SimpleDateFormat不包含时区信息的自定义模式的实例,然后将“EST”添加到您写出的字符串的结尾。

于 2010-10-14T13:27:50.893 回答
0

你的问题还不清楚。

我不明白您是否只是想强制使用“EST”字符,即使您的机器设置为自动更改 DST,或者您想要的是获取 EST 的实际时间。

所以你有两个选择:

  1. 您的机器时间设置为下午 2:15 并且 DST 生效,并且您想写 2:15pm EST(这不是正确的实际时间),您应该使用 SimpleDateFormat。这样,您将在时间上撒谎。但是,无论如何,你知道什么最适合你。

  2. 您的机器时间设置为下午 2:15 并且 DST 生效,并且您想写 EST 下午 1:15,您应该使用: TimeZone.setDefault(TimeZone.getTimeZone("EST"))

于 2010-10-14T17:20:19.213 回答
0

解决方案取决于你写这个超时的原因以及当你读回它时你想用它做什么(它将被用来做什么,而不是“你想要什么”)。总是把它写成 EST 是对事实的歪曲。当 EDT 生效时,它实际上不是EST。如果您尝试跟踪某个“绝对”时间点,我建议您在GMT而不是任何时区工作。

于 2010-10-14T17:46:56.220 回答
-1

机器设置为时区:东部时间(美国和加拿大)。

这不是一个实时时区(EDT 和 EST 都不是)。时区(正如 Java 所理解的那样)类似于“America/Phoenix”,它是管理时区的 ID,它既有基本偏移量,也有(可选)在特定日期切换到夏令时。这两种情况都可能发生变化,在解释历史日期时有必要考虑这些变化。

因此,如果您不想切换 DST,请选择不遵守 DST 的时区。可能没有这样的时区,并且试图表现得像那样会引入不可能的日期。

于 2010-10-14T13:22:24.400 回答