Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/188.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android Java日历时区更改未按预期工作_Android_Calendar_Timezone_Java 7 - Fatal编程技术网

Android Java日历时区更改未按预期工作

Android Java日历时区更改未按预期工作,android,calendar,timezone,java-7,Android,Calendar,Timezone,Java 7,我使用java日历在午夜(GMT)创建一些日期,然后将时区更改为我的本地时区,以确保请求的时间为1:00(GMT+1)。 下面的代码有效,包括2个成功的断言 TimeZone TIMEZONE_GMT = TimeZone.getTimeZone("GMT"); TimeZone TIMEZONE_LOCAL = TimeZone.getDefault(); // GMT + 1 private Calendar getMidnightGmtCalendarWithLocalTimezone(

我使用java日历在午夜(GMT)创建一些日期,然后将时区更改为我的本地时区,以确保请求的时间为1:00(GMT+1)。 下面的代码有效,包括2个成功的断言

TimeZone TIMEZONE_GMT = TimeZone.getTimeZone("GMT");
TimeZone TIMEZONE_LOCAL = TimeZone.getDefault(); // GMT + 1

private Calendar getMidnightGmtCalendarWithLocalTimezone() {
    Calendar calendar = Calendar.getInstance(Locale.GERMAN);
    calendar.set(2017, Calendar.JANUARY, 1, 0, 0, 0);

    calendar.setTimeZone(TIMEZONE_GMT); // Probably not required
    assertEquals(0, calendar.get(Calendar.HOUR_OF_DAY)); // Assert 1

    // Log.i("TAG", "" + calendar.get(Calendar.HOUR_OF_DAY));

    calendar.setTimeZone(TIMEZONE_LOCAL);
    assertEquals(1, calendar.get(Calendar.HOUR_OF_DAY)); // Assert 2
    return calendar;
}
现在我删除了第一个断言,我希望不会有任何更改。现实:第二个断言现在失败了!我试图理解.get()的实现,显然它也会计算一些时间,所以它不仅仅是收集值。我仍然不明白为什么我的第二次断言失败了

当我取消注释日志行时,第二次断言再次成功(只是为了确保问题是由calendar.get()引起的,而不是断言!)

第一个问题:为什么会发生这种情况? 第二个问题:当我将时区GMT的时间设置为午夜时,如何确保我有一个带有本地时区的日历实例?(换句话说,如何正确转换时区?)

编辑:
我在Android上使用这个,所以不能使用Java8。Joda time(如下所示)是一个很好的选择,我将对此进行深入研究。但是,作为我问题的答案,我想知道这在Java7 Calendar中是如何工作的,因为我现在必须使用该代码。

因此,我运行了以下代码片段:

public static void main(String[] args) throws Exception {
    TimeZone TIMEZONE_GMT = TimeZone.getTimeZone("GMT");

    Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("Europe/Berlin"));
    calendar.set(2017, Calendar.JANUARY, 1, 0, 0, 0);

    System.out.println(calendar.get(Calendar.HOUR_OF_DAY));
    calendar.setTimeZone(TIMEZONE_GMT); // Probably not required
    System.out.println(calendar.get(Calendar.HOUR_OF_DAY));
}
在执行时,我在控制台中得到了正确的
0
23

然后我注释掉了第一个
Sysout
语句,它打印了
0
(我希望它打印
23

在进一步研究之后,我找到了这样一个答案,它正确地解释了calendar对象只存储毫秒,而不考虑时区

因此,如果我是你,我不会太担心
断言
,我会确保我得到一个带有所需时区的
日历
实例(如果默认时区设置为你需要的时区,则为默认时区),例如:


因此,我运行了以下代码段:

public static void main(String[] args) throws Exception {
    TimeZone TIMEZONE_GMT = TimeZone.getTimeZone("GMT");

    Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("Europe/Berlin"));
    calendar.set(2017, Calendar.JANUARY, 1, 0, 0, 0);

    System.out.println(calendar.get(Calendar.HOUR_OF_DAY));
    calendar.setTimeZone(TIMEZONE_GMT); // Probably not required
    System.out.println(calendar.get(Calendar.HOUR_OF_DAY));
}
在执行时,我在控制台中得到了正确的
0
23

然后我注释掉了第一个
Sysout
语句,它打印了
0
(我希望它打印
23

在进一步研究之后,我找到了这样一个答案,它正确地解释了calendar对象只存储毫秒,而不考虑时区

因此,如果我是你,我不会太担心
断言
,我会确保我得到一个带有所需时区的
日历
实例(如果默认时区设置为你需要的时区,则为默认时区),例如:

tl;博士 使用java.time,而不是
java.util.Calendar

Instant.parse( "2017-01-01T00:00:00Z" )          // UTC.
       .atZone( ZoneId.of( "Africa/Algiers" ) )  // Time zone with offset +01:00.
避免
日历
旧的日期时间类(包括)很麻烦,设计不好,容易混淆,而且有缺陷。避开它们。试图理解他们过度紧张的API毫无意义

传统的日期时间类被内置在Java8和更高版本中的一系列类所取代

Instant
该类以纳秒的分辨率表示时间线上的一个时刻

Instant instant = Instant.parse( "2017-01-01T00:00:00Z" );
instant.toString():2017-01-01T00:00:00Z

ZoneDateTime
您要求在UTC提前一小时的时区中查看。所以,让我们尝试应用时区来获得一个

zdt.toString():2017-01-01T01:00+01:00[非洲/阿尔及尔]

OffsetDateTime
如果希望通过参数而不是解析字符串来构造日期时间(如上所示),请将参数传递给的工厂方法。指定方便的常数。月份的编号是合理的,1-12月份为1-12,与
日历相比

OffsetDateTime odt = OffsetDateTime.of( 2017 , 1 , 1 , 0 , 0 , 0 , 0 , ZoneOffset.UTC ) ;
odt.toString():2017-01-01T00:00Z

与上面类似,我们可以调整到一个时区。针对异常情况进行调整,例如:

zdt.toString():2017-01-01T01:00+01:00[非洲/阿尔及尔]

看这个

Locale
关于问题代码中
Locale
的使用…
Locale
与时区完全正交,相互独立。
Locale
对象只影响生成的表示日期时间值的字符串的格式


关于java.time 该框架内置于Java8及更高版本中。这些类取代了麻烦的旧日期时间类,例如,&

该项目现已启动,建议迁移到类

要了解更多信息,请参阅。并搜索堆栈溢出以获得许多示例和解释。规格是

从哪里获得java.time类

  • 后来
    • 内置的
    • 标准JavaAPI的一部分,带有捆绑实现
    • Java9添加了一些次要功能和修复
    • 大部分java.time功能都在中向后移植到Java6和Java7
    • 该项目专门为Android采用了ThreeTen Backport(如上所述)
该项目使用其他类扩展了java.time。这个项目是java.time将来可能添加的一个试验场。您可以在这里找到一些有用的类,如、、和。

tl;博士 使用java.time,而不是
java.util.Calendar

Instant.parse( "2017-01-01T00:00:00Z" )          // UTC.
       .atZone( ZoneId.of( "Africa/Algiers" ) )  // Time zone with offset +01:00.
避免
日历
旧的日期时间类(包括)很麻烦,设计不好,容易混淆,而且有缺陷。避开它们。试图理解他们过度紧张的API毫无意义

传统的日期时间类被内置在Java8和更高版本中的一系列类所取代

Instant
该类以纳秒的分辨率表示时间线上的一个时刻

Instant instant = Instant.parse( "2017-01-01T00:00:00Z" );
instant.toString():2017-01-01T00:00:00Z

ZoneDateTime
您要求在UTC提前一小时的时区中查看。所以,让我们尝试应用时区来获得一个

zdt.toString():2017-01-01T01:00+01:00[非洲/阿尔及尔]

OffsetDateTime<