我必须在我的 Java 应用程序中打印 EST 时间。我已使用以下方法将时区设置为 EST:
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("EST"));
但是当在这个时区遵循夏令时时,我的代码不会打印正确的时间(它打印的时间少 1 小时)。
无论是否遵守夏令时,如何使代码始终读取正确的时间?
PS:我尝试将时区设置为 EDT,但并没有解决问题。
PS: I tried setting the timezone to EDT, but it solve the problem
这是开始的问题:
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()));
其他答案是正确的,尤其是 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 时间不同。例如,后者可以有闰秒。
Instant
被视为日期和时间时,闰秒变得无关紧要。这就是闰秒的全部意义,让我们的时钟停顿片刻,让我们的日历与地球普遍放缓的天文位置同步。虽然 Instant
的内部表示确实短于迄今为止已声明的闰秒数(每两年左右一次),但在讨论日期和时间时,这种区别是没有实际意义的。这些细节在课堂文档中为那些关心的人进行了讨论。结果:实际上,Instant
是 UTC。
Instant
表示的 Java 时间也不会停止时钟 - 它在当天具有相同的毫秒数,但它们都稍长一些。即使您不想那样想,它仍然是这样实现的,这就是为什么您不能使用 ISO_DATE_TIME
格式化 Instant
。
Instant.now().atZone(ZoneOffset.UTC)
您可以输入“EST5EDT”,而不是输入“EST”作为时区。正如您所指出的,仅“EDT”不起作用。这将解决夏令时问题。代码行如下所示:
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("EST5EDT"));
根据此 answer:
TimeZone tz = TimeZone.getTimeZone("EST");
boolean inDs = tz.inDaylightTime(new Date());
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;
}
Date
、Calendar
、SimpleDateFormat
。
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中,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
}
实现 TimeZone 类以将时区设置为 Calendar 负责夏令时。
java.util.TimeZone 表示时区偏移量,还计算夏令时。
示例代码:
TimeZone est_timeZone = TimeZoneIDProvider.getTimeZoneID(TimeZoneID.US_EASTERN).getTimeZone();
Calendar enteredCalendar = Calendar.getInstance();
enteredCalendar.setTimeZone(est_timeZone);
TimeZoneIDProvider
是自定义类吗?在这种情况下,您需要提供其实现。
DateFormat format = new SimpleDateFormat("HH:mm:ss:ms MM/dd/yyyy").getDateTimeInstance()
之类的内容更改格式?我的示例生成警告“应以静态方式访问 DateFormat 类型的静态方法 getDateTimeInstance()”。DateFormat format = DateFormat.getDateTimeInstance()
。它是一个静态方法,因此它与现有实例无关。真的不清楚你要做什么,但你可能应该问一个新问题。HH:mm:ss:ms MM/dd/yyyy
”。SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss:ms MM/dd/yyyy");
System.out.println(format.format(new Date()));
...替换答案中的最后一行代码以获得所需的输出。感谢您的帮助。new Date()
的结果不依赖于系统时区。如果您的意思是将SimpleDateFormat
与系统时区一起使用,那么是的,调用sdf.format(new Date());
然后在几毫秒后立即调用sdf.format(new Date());
可能会导致字符串表示形式相隔一个小时。