Calendar.getInstance().getTime() 返回 "GMT" 中的日期而不是默认时区
Calendar.getInstance().getTime() returning date in "GMT" instead of Default TimeZone
Calendar c = Calendar.getInstance();
System.out.println(c.getTime());
c.set(2007, 0, 1);
System.out.println(c.getTime());
输出:
Tue Sep 12 12:36:24 IST 2017
Mon Jan 01 12:36:24 IST 2007
但是,当我在不同的环境中使用相同的代码时,输出变为如下:
输出:
Tue Sep 12 12:36:24 IST 2017
Mon Jan 01 12:36:24 GMT 2007
仅供参考,我尝试在设置值之前和之后打印日历实例的时区,两者都在 "IST".
中
我想知道这的根本原因。
您需要设置时区,您会得到想要的结果。
TimeZone.setDefault(TimeZone.getTimeZone("IST"));
这是一个工作代码。
import java.util.Calendar;
import java.util.TimeZone;
public class Cal {
public static void main(String[] args) {
// TODO Auto-generated method stub
TimeZone.setDefault(TimeZone.getTimeZone("IST")); // Add this before print
Calendar c = Calendar.getInstance();
System.out.println(c.getTime());
c.set(2007, 0, 1);
System.out.println(c.getTime());
}
}
根据Doc "Typically, you get a TimeZone using getDefault which creates a TimeZone based on the time zone where the program is running. For example, for a program running in Japan, getDefault creates a TimeZone object based on Japanese Standard Time."
所以当您 运行 在不同的时区时,它被用作默认时区。希望你现在清楚。我附上文件。请阅读。
谈谈这个有趣的行为:
来自日历的源代码class:
public final void set(int year, int month, int date)
{
set(YEAR, year);
set(MONTH, month);
set(DATE, date);
}
这导致设置方法:
public void set(int field, int value)
{
// If the fields are partially normalized, calculate all the
// fields before changing any fields.
if (areFieldsSet && !areAllFieldsSet) {
computeFields();
}
internalSet(field, value);
isTimeSet = false;
areFieldsSet = false;
isSet[field] = true;
stamp[field] = nextStamp++;
if (nextStamp == Integer.MAX_VALUE) {
adjustStamp();
}
}
这里有趣的部分是 computeFields() 方法,它有两个实现(一个用于公历,一个用于日本日历)。这些方法非常复杂,但据我所知,这是您的 Calendar 实例可能会在您的用例中更改时区的唯一地方。
您问题中的第二个输出是 JVM 运行 爱尔兰时间 (Europe/Dublin) 上的正确和预期行为。 2017 年 9 月 12 日,爱尔兰正处于夏令时 (DST)。虽然没有明确记录,但 Date.toString()
(在打印从 c.getTime()
获得的 Date
时隐式调用)打印 JVM 时区中的日期和时间,该时区在 9 月呈现作为爱尔兰夏令时的 IST。
当您在 Calendar
对象上设置日期时也使用爱尔兰时间,一天中的小时将被保留;在你的情况下,你得到 Jan 01 2007 12:36:24 爱尔兰标准时间。现在想象一下,如果爱尔兰夏令时和爱尔兰标准时间都呈现为 IST,会造成怎样的混乱。你将无法区分。相反,由于爱尔兰标准时间与格林威治标准时间一致,因此当日期为 not 时 Date.toString()
在一年中的夏令时部分(一月不是)打印出来。
我的猜测是您的第一个输出来自 JVM 运行 印度时间。它也被呈现为 IST,并且由于印度不使用夏令时,所以同样的缩写被赋予了夏季和冬季。
java.time
在了解您观察到的行为的解释之前,我发布了一条关于过时和现代 Java 日期和时间 classes 的评论。不过,我仍然认为评论还没有结束。这是您的代码的现代版本:
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Europe/Dublin"));
System.out.println(zdt);
zdt = zdt.with(LocalDate.of(2007, Month.JANUARY, 1));
System.out.println(zdt);
它打印
2017-09-12T11:45:33.921+01:00[Europe/Dublin]
2007-01-01T11:45:33.921Z[Europe/Dublin]
如果要使用 JVM 的时区设置,请使用 ZoneId.systemDefault()
而不是 ZoneId.of("Europe/Dublin")
。顾名思义,与 Date
相反,ZonedDateTime
确实包含时区。它更符合旧的Calendar
class。如您所见,它的 toString
方法打印出 UTC 的偏移量(Z
表示零偏移量)和明确的 region/city 中的时区名称格式。我相信这会减少混淆的空间。如果要以特定格式打印日期,请使用 DateTimeFormatter
.
附录:代码的示例输出
为了完整起见,以下是当 运行 可能呈现为 IST 的不同时区时代码的输出:
Europe/Dublin(同意你的第二个输出)
Tue Sep 12 11:19:28 IST 2017
Mon Jan 01 11:19:28 GMT 2007
Asia/Tel_Aviv
Tue Sep 12 13:19:28 IDT 2017
Mon Jan 01 13:19:28 IST 2007
Asia/Kolkata(同意你的第一个输出)
Tue Sep 12 15:49:28 IST 2017
Mon Jan 01 15:49:28 IST 2007
Calendar c = Calendar.getInstance();
System.out.println(c.getTime());
c.set(2007, 0, 1);
System.out.println(c.getTime());
输出:
Tue Sep 12 12:36:24 IST 2017
Mon Jan 01 12:36:24 IST 2007
但是,当我在不同的环境中使用相同的代码时,输出变为如下:
输出:
Tue Sep 12 12:36:24 IST 2017
Mon Jan 01 12:36:24 GMT 2007
仅供参考,我尝试在设置值之前和之后打印日历实例的时区,两者都在 "IST".
中我想知道这的根本原因。
您需要设置时区,您会得到想要的结果。
TimeZone.setDefault(TimeZone.getTimeZone("IST"));
这是一个工作代码。
import java.util.Calendar;
import java.util.TimeZone;
public class Cal {
public static void main(String[] args) {
// TODO Auto-generated method stub
TimeZone.setDefault(TimeZone.getTimeZone("IST")); // Add this before print
Calendar c = Calendar.getInstance();
System.out.println(c.getTime());
c.set(2007, 0, 1);
System.out.println(c.getTime());
}
}
根据Doc "Typically, you get a TimeZone using getDefault which creates a TimeZone based on the time zone where the program is running. For example, for a program running in Japan, getDefault creates a TimeZone object based on Japanese Standard Time."
所以当您 运行 在不同的时区时,它被用作默认时区。希望你现在清楚。我附上文件。请阅读。
谈谈这个有趣的行为:
来自日历的源代码class:
public final void set(int year, int month, int date)
{
set(YEAR, year);
set(MONTH, month);
set(DATE, date);
}
这导致设置方法:
public void set(int field, int value)
{
// If the fields are partially normalized, calculate all the
// fields before changing any fields.
if (areFieldsSet && !areAllFieldsSet) {
computeFields();
}
internalSet(field, value);
isTimeSet = false;
areFieldsSet = false;
isSet[field] = true;
stamp[field] = nextStamp++;
if (nextStamp == Integer.MAX_VALUE) {
adjustStamp();
}
}
这里有趣的部分是 computeFields() 方法,它有两个实现(一个用于公历,一个用于日本日历)。这些方法非常复杂,但据我所知,这是您的 Calendar 实例可能会在您的用例中更改时区的唯一地方。
您问题中的第二个输出是 JVM 运行 爱尔兰时间 (Europe/Dublin) 上的正确和预期行为。 2017 年 9 月 12 日,爱尔兰正处于夏令时 (DST)。虽然没有明确记录,但 Date.toString()
(在打印从 c.getTime()
获得的 Date
时隐式调用)打印 JVM 时区中的日期和时间,该时区在 9 月呈现作为爱尔兰夏令时的 IST。
当您在 Calendar
对象上设置日期时也使用爱尔兰时间,一天中的小时将被保留;在你的情况下,你得到 Jan 01 2007 12:36:24 爱尔兰标准时间。现在想象一下,如果爱尔兰夏令时和爱尔兰标准时间都呈现为 IST,会造成怎样的混乱。你将无法区分。相反,由于爱尔兰标准时间与格林威治标准时间一致,因此当日期为 not 时 Date.toString()
在一年中的夏令时部分(一月不是)打印出来。
我的猜测是您的第一个输出来自 JVM 运行 印度时间。它也被呈现为 IST,并且由于印度不使用夏令时,所以同样的缩写被赋予了夏季和冬季。
java.time
在了解您观察到的行为的解释之前,我发布了一条关于过时和现代 Java 日期和时间 classes 的评论。不过,我仍然认为评论还没有结束。这是您的代码的现代版本:
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Europe/Dublin"));
System.out.println(zdt);
zdt = zdt.with(LocalDate.of(2007, Month.JANUARY, 1));
System.out.println(zdt);
它打印
2017-09-12T11:45:33.921+01:00[Europe/Dublin]
2007-01-01T11:45:33.921Z[Europe/Dublin]
如果要使用 JVM 的时区设置,请使用 ZoneId.systemDefault()
而不是 ZoneId.of("Europe/Dublin")
。顾名思义,与 Date
相反,ZonedDateTime
确实包含时区。它更符合旧的Calendar
class。如您所见,它的 toString
方法打印出 UTC 的偏移量(Z
表示零偏移量)和明确的 region/city 中的时区名称格式。我相信这会减少混淆的空间。如果要以特定格式打印日期,请使用 DateTimeFormatter
.
附录:代码的示例输出
为了完整起见,以下是当 运行 可能呈现为 IST 的不同时区时代码的输出:
Europe/Dublin(同意你的第二个输出)
Tue Sep 12 11:19:28 IST 2017 Mon Jan 01 11:19:28 GMT 2007
Asia/Tel_Aviv
Tue Sep 12 13:19:28 IDT 2017 Mon Jan 01 13:19:28 IST 2007
Asia/Kolkata(同意你的第一个输出)
Tue Sep 12 15:49:28 IST 2017 Mon Jan 01 15:49:28 IST 2007