ChatGPT解决这个技术问题 Extra ChatGPT

如何在 Java 中使用 TimeZone 处理夏令时

我必须在我的 Java 应用程序中打印 EST 时间。我已使用以下方法将时区设置为 EST:

Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("EST"));

但是当在这个时区遵循夏令时时,我的代码不会打印正确的时间(它打印的时间少 1 小时)。

无论是否遵守夏令时,如何使代码始终读取正确的时间?

PS:我尝试将时区设置为 EDT,但并没有解决问题。

您能否扩展您的示例代码,准确显示您正在尝试做什么?
除了打印日期外,我没有什么太多的事情要做。但是当我在输出中看到小时时,在 EST 中遵循夏令时时,它显示错误(少 1 小时)。如何照顾夏令时是我的问题
请使用该信息编辑您的问题。它可能会在评论中被遗漏,但可能不会在您的问题中。另外,请编辑并澄清此声明PS: I tried setting the timezone to EDT, but it solve the problem
夏令时在夏令时开始时将时钟提前一小时,并在其结束时将时钟延迟相同的量。在我看来,你看到的行为是完全正常的。请通过en.wikipedia.org/wiki/Daylight_saving_time
“当美国东部时间遵循夏令时时” - 你的意思是“当东部时间遵循夏令时时”。 EST 是东部标准时间 - 标准时间与日光相反。

J
Jon Skeet

这是开始的问题:

Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("EST"));

应完全避免使用 3 个字母的缩写,以支持 TZDB 区域 ID。 EST 是东部标准时间 - 标准时间从不遵守 DST;这不是一个完整的时区名称。它是用于部分时区的名称。 (不幸的是,我还没有找到一个关于“半时区”概念的好词。)

您需要一个完整时区名称。例如,America/New_York 位于东部时区:

TimeZone zone = TimeZone.getTimeZone("America/New_York");
DateFormat format = DateFormat.getDateTimeInstance();
format.setTimeZone(zone);

System.out.println(format.format(new Date()));

谢谢@Jon,是否可以使用 DateFormat format = new SimpleDateFormat("HH:mm:ss:ms MM/dd/yyyy").getDateTimeInstance() 之类的内容更改格式?我的示例生成警告“应以静态方式访问 DateFormat 类型的静态方法 getDateTimeInstance()”。
@IanCampbell:完全不清楚你期望它做什么——它是一个静态方法,所以你通常只使用 DateFormat format = DateFormat.getDateTimeInstance()。它是一个静态方法,因此它与现有实例无关。真的不清楚你要做什么,但你可能应该问一个新问题。
好的,谢谢@Jon,我只是想知道如何将输出格式更改为“HH:mm:ss:ms MM/dd/yyyy”。
对不起@Jon 的困惑,我只是按照你的建议做了:SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss:ms MM/dd/yyyy"); System.out.println(format.format(new Date())); ...替换答案中的最后一行代码以获得所需的输出。感谢您的帮助。
@maximus:我不确定你的意思。 new Date() 的结果不依赖于系统时区。如果您的意思是将 SimpleDateFormat 与系统时区一起使用,那么是的,调用 sdf.format(new Date()); 然后在几毫秒后立即调用 sdf.format(new Date()); 可能会导致字符串表示形式相隔一个小时。
B
Basil Bourque

其他答案是正确的,尤其是 the one by Jon Skeet,但已过时。

java.time

这些旧的日期时间类已被 Java 8 及更高版本中内置的 java.time 框架所取代。

如果您只想要 UTC 中的当前时间,请使用 Instant 类。

Instant now = Instant.now();

EST 不是时区,如 correct Answer by Jon Skeet 中所述。这样的 3-4 个字母代码既不标准化也不唯一,进一步混淆了夏令时 (DST)。使用“大陆/地区”格式的正确时区名称。

也许您的意思是北美东海岸的东部标准时间?还是埃及标准时间?还是欧洲标准时间?

ZoneId zoneId = ZoneId.of( "America/New_York" );
ZoneId zoneId = ZoneId.of( "Africa/Cairo" );
ZoneId zoneId = ZoneId.of( "Europe/Lisbon" );

使用任何此类 ZoneId 对象将当前时刻调整到特定时区以生成 ZonedDateTime 对象。

ZonedDateTime zdt = ZonedDateTime.now( zoneId ) ;

通过从第一个对象生成另一个 ZonedDateTime 对象,将该 ZonedDateTime 调整到不同的时区。 java.time 框架使用 immutable objects 而不是更改(变异)现有对象。

ZonedDateTime zdtGuam = zdt.withZoneSameInstant( ZoneId.of( "Pacific/Guam" ) ) ;

https://i.stack.imgur.com/V7t6V.png


Instant 与 UTC 时间不同。例如,后者可以有闰秒。
@OrangeDog 当 Instant 被视为日期和时间时,闰秒变得无关紧要。这就是闰秒的全部意义,让我们的时钟停顿片刻,让我们的日历与地球普遍放缓的天文位置同步。虽然 Instant 的内部表示确实短于迄今为止已声明的闰秒数(每两年左右一次),但在讨论日期和时间时,这种区别是没有实际意义的。这些细节在课堂文档中为那些关心的人进行了讨论。结果:实际上,Instant 是 UTC。
呃,没有。 UTC 闰秒不会“停止时钟”,它会增加一秒(2016-12-24T23:23:60Z 是最近的)。 Instant 表示的 Java 时间也不会停止时钟 - 它在当天具有相同的毫秒数,但它们都稍长一些。即使您不想那样想,它仍然是这样实现的,这就是为什么您不能使用 ISO_DATE_TIME 格式化 Instant
幸运的是,转换很容易 - Instant.now().atZone(ZoneOffset.UTC)
就日期和时间而言,添加一秒确实会停止时钟。在进入日历中的下一个日期之前,我们需要额外的时间。所以闰秒被我们的日历吸收了。正如我所说,这就是闰秒的全部意义:放慢我们的时钟以减慢我们的日历跟踪。虽然您关于忽略闰秒的观点在 java.time 类的内部表示方面在技术上是正确的,但实际上,您的观点与许多努力学习如何表示日期和时间的程序员无关、迂腐和不必要的混淆。
V
Vadim Kotov

您可以输入“EST5EDT”,而不是输入“EST”作为时区。正如您所指出的,仅“EDT”不起作用。这将解决夏令时问题。代码行如下所示:

Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("EST5EDT"));

C
Community

根据此 answer

TimeZone tz = TimeZone.getTimeZone("EST");
boolean inDs = tz.inDaylightTime(new Date());

f
fartwhif
private static Long DateTimeNowTicks(){
    long TICKS_AT_EPOCH = 621355968000000000L;
    TimeZone timeZone = Calendar.getInstance().getTimeZone();
    int offs = timeZone.getRawOffset();
    if (timeZone.inDaylightTime(new Date()))
        offs += 60 * 60 * 1000;
    return (System.currentTimeMillis() + offs) * 10000 + TICKS_AT_EPOCH;
}

几年前,随着 JSR 310 的采用,这些可怕的旧日期时间类被 java.time 类所取代。这些遗留类根本不应该再使用。
有时开发人员被迫陷入可怕的旧遗留问题,但很高兴知道,谢谢。
对于 Java 6 和在 Java 7 中,大部分 java.time 功能都在 ThreeTen-Backport 项目中使用几乎相同的 API 进行了反向移植。所以真的没有必要使用糟糕的遗留日期时间类,例如 DateCalendarSimpleDateFormat
有时,开发人员在没有向后移植的情况下被迫陷入可怕的旧遗留情况,因此别无选择,只能使用糟糕的遗留日期时间类,但很高兴知道,谢谢!
J
Jayesh Kalkani
public static float calculateTimeZone(String deviceTimeZone) {
    float ONE_HOUR_MILLIS = 60 * 60 * 1000;

    // Current timezone and date
    TimeZone timeZone = TimeZone.getTimeZone(deviceTimeZone);
    Date nowDate = new Date();
    float offsetFromUtc = timeZone.getOffset(nowDate.getTime()) / ONE_HOUR_MILLIS;

    // Daylight Saving time
    if (timeZone.useDaylightTime()) {
        // DST is used
        // I'm saving this is preferences for later use

        // save the offset value to use it later
        float dstOffset = timeZone.getDSTSavings() / ONE_HOUR_MILLIS;
        // DstOffsetValue = dstOffset
        // I'm saving this is preferences for later use
        // save that now we are in DST mode
        if (timeZone.inDaylightTime(nowDate)) {
            Log.e(Utility.class.getName(), "in Daylight Time");
            return -(ONE_HOUR_MILLIS * dstOffset);
        } else {
            Log.e(Utility.class.getName(), "not in Daylight Time");
            return 0;
        }
    } else
        return 0;
}

仅供参考,这些非常麻烦的旧类在几年前被现代 java.time 类所取代。
S
Sunil Garg

在java中,DateFormatter默认使用DST,为了避免夏令时(DST)你需要手动做一个技巧,首先你必须得到DST偏移量,即应用了多少毫秒的DST,例如某处DST也是45分钟对于某些地方,它是 30 分钟,但在大多数情况下,DST 是 1 小时,您必须使用 Timezone 对象并检查日期是否属于 DST,然后您必须手动将 DST 的偏移量添加到其中。例如:

 TimeZone tz = TimeZone.getTimeZone("EST");
 boolean isDST = tz.inDaylightTime(yourDateObj);
 if(isDST){
 int sec= tz.getDSTSavings()/1000;// for no. of seconds
 Calendar cal= Calendar.getInstance();
 cal.setTime(yourDateObj);
 cal.add(Calendar.Seconds,sec);
 System.out.println(cal.getTime());// your Date with DST neglected
  }

这实际上很有帮助 - 我需要“取消夏令时”日期,但我不知道“inDayLightTime”功能。谢谢!
R
Radnerus

实现 TimeZone 类以将时区设置为 Calendar 负责夏令时。

java.util.TimeZone 表示时区偏移量,还计算夏令时。

示例代码:

TimeZone est_timeZone = TimeZoneIDProvider.getTimeZoneID(TimeZoneID.US_EASTERN).getTimeZone();
Calendar enteredCalendar = Calendar.getInstance();
enteredCalendar.setTimeZone(est_timeZone);

TimeZoneIDProvider 是自定义类吗?在这种情况下,您需要提供其实现。