将UTC转换为伊朗当地时间

erf*_*fan 3 timezone android simpledateformat

我尝试将 UTC 时间转换为本地时间,分钟工作正常,但小时总是晚 1 小时,例如,如果 UTC 时间是 04:55,我的手机时钟是 9:25,但我的代码生成 8:25

   String dateStr = "04:55";
        SimpleDateFormat df = new SimpleDateFormat("HH:mm");
        df.setTimeZone(TimeZone.getTimeZone("UTC"));
        Date date = null;
        try {
            date = df.parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        df.setTimeZone(TimeZone.getDefault());
        String formattedDate = df.format(date);

        time.setText(String.valueOf(formattedDate));
Run Code Online (Sandbox Code Playgroud)

Bas*_*que 6

1970 年伊朗没有夏令时

伊朗的时区在 2018 年夏天Asia/Tehran遵守夏令时 (DST),但在 1970 年没有这样做。

2018 年夏天,伊朗比 UTC 时间早四个半小时,而不是三个半小时。因此,从 UTC 的 4:55 开始调整应该是夏季的 9:25,而不是 8:25。

System.out.println(
        OffsetDateTime.of(
                LocalDate.of( 2018 , Month.JUNE , 1 ) ,
                LocalTime.parse( "04:55" ) ,
                ZoneOffset.UTC
        )
       .atZoneSameInstant(
           ZoneId.of( "Asia/Tehran" )
       )
);
Run Code Online (Sandbox Code Playgroud)

2018-06-01T09:25+04:30[亚洲/德黑兰]

但是我怀疑您的代码在解析字符串时默认为UTC 中 1970 年第一时刻的纪元参考日期 1970-01-01T00:00:00Z,因为您在尝试解析时间时滥用该类不指定日期。

1970 年,伊朗没有遵守夏令时 (DST)。因此,在 1970 年夏天,偏移量比 UTC 早了三个半小时,而在 2018 年夏天比 UTC 早了四个半小时。

System.out.println(
    OffsetDateTime.of(
        LocalDate.EPOCH ,
        LocalTime.parse( "04:55" ) ,
        ZoneOffset.UTC
    )
        .atZoneSameInstant(
            ZoneId.of( "Asia/Tehran" )
        )
);
Run Code Online (Sandbox Code Playgroud)

1970-01-01T08:25+03:30[亚洲/德黑兰]

错误的课程

您使用了错误的类。

您想要表示一天中的时间值。所以你应该使用时间课程。但是您正在使用 date-with-time-of-day 类,java.util.Date.

您正在使用麻烦的糟糕设计的日期时间类,java.util.Date& java.text.SimpleDateFormat。这些在几年前被java.time类取代。完全避免遗留类。仅使用java.time包中的类。

时间

解析时间字符串。

LocalTime.parse( "04:55" )
Run Code Online (Sandbox Code Playgroud)

获取当前时间。

LocalTime.now()                  // Capture the current time of day per the JVM’s current default time zone.
Run Code Online (Sandbox Code Playgroud)

最好明确表明您打算使用 JVM 的当前默认时区。

LocalTime.now(
    ZoneId.systemDefault()       // Capture the current time of day by explicitly asking for the JVM’s current default time zone.
)
Run Code Online (Sandbox Code Playgroud)

或者指定一个特定的时区。

LocalTime.now( 
    ZoneId.of( "Asia/Kabul" )  // Capture the current time-of-day as seen in the wall-clock time used by the people of a particular region (a time zone).
)
Run Code Online (Sandbox Code Playgroud)

9:25

获取 UTC 中的当前时间。

LocalTime.now( 
    ZoneOffset.UTC
)
Run Code Online (Sandbox Code Playgroud)

04:55

LocalTime

如果您有一个输入字符串,例如“04:55”,则解析为一个LocalTime对象。此类表示没有日期和时区的时间。

String input = "04:55" ;
LocalTime lt = LocalTime.parse( input ) ;
Run Code Online (Sandbox Code Playgroud)

术语

我尝试将 UTC 时间转换为本地时间

您的短语“本地时间”在日期时间处理中具有特定含义。不幸的是,该含义您的意图相反。在 *java.time.Local..." 类中看到的“本地”一词表示任何地点或所有地点,而不是任何一个特定地点。

因此,LocalTime对象在附加到日期并放置在时区的上下文中(或从 UTC 偏移)之前没有真正的意义。

时区

如果 UTC 时间是 04:55 ,我的手机时钟是 9:25

这意味着您的 JVM 当前默认时区使用的是 UTC 的偏移量,比 UTC 早四个半小时+04:30。根据这个时区的名单作为由IANA管理,目前使用偏移只有一个时区:Asia/Kabul

要完全表示当前时刻,您需要一个日期和时间以及区域/偏移量。要捕捉当前时刻,请使用Instant。该Instant级表示时间轴上的时刻UTC,分辨率为纳秒(最多小数的9个位数)。

Instant instant = Instant.now() ;  // Capture the current moment in UTC.
Run Code Online (Sandbox Code Playgroud)

要查看您所在时区的同一时刻,请应用 aZoneId以获取ZonedDateTime.

ZoneId zKabul = ZoneId.of( "Asia/Kabul" ) ;
ZonedDateTime zdt = instant.atZone( zKabul ) ;
Run Code Online (Sandbox Code Playgroud)

如果您真的只想要该值的时间部分,请提取LocalTime. 这对于在用户界面中呈现可能很有用,但在您的业务逻辑中可能没有用。

LocalTime lt = zdt.toLocalTime() ;  // Extract just the time-of-day as seen in the wall-clock time used by the people of this region (this time zone).
Run Code Online (Sandbox Code Playgroud)

作为快捷方式,您可以调用LocalTime.now

LocalTime lt = LocalTime.now( zKabul ) ;
Run Code Online (Sandbox Code Playgroud)

伊朗时间

后来在你的意见,你解释你的意图时区Asia/Tehran在伊朗的时间。目前,伊朗遵守夏令时 (DST),这可能是您困惑的根源。虽然标准偏移量是 +03:30(比 UTC 早三个半小时),但在 3 月 22 日和 9 月 22 日之间,偏移量是 +04:30,比 UTC 多一个小时。

这正是您应该指定所需/预期时区的原因。对于临时使用,您可以使用 JVM 的当前默认时区。但是要知道默认值可以在运行时随时更改。默认值可能不是您想要的。对于关键用途,请始终与用户确认他们的预期时区。

让我们以 UTC 中的示例时间 4:55 为 6 月 1 日建立一个日期时间。我们可以使用常数ZoneOffset.UTC。当仅使用 UTC 偏移量(在这种情况下为零偏移量)时,请使用OffsetDateTime. UTC偏移量只是一些小时和分钟,仅此而已。相比之下,时区是特定地区人民使用的偏移量的过去、现在和未来变化的历史。

LocalTime lt = LocalTime.parse( "04:55" ) ;
LocalDate ld = LocalDate.of( 2018 , Month.JUNE , 1 ) ;
OffsetDateTime odt = OffsetDateTime.of( ld , lt , ZoneOffset.UTC ) ;
Run Code Online (Sandbox Code Playgroud)

odt.toString(): 2018-06-01T04:55Z

Asia/Tehran通过应用 aZoneId获得 a 来调整到该区域ZonedDateTime。同一时刻,时间线上的同一点,但挂钟时间不同。

ZoneId zTehran = ZoneId.of( "Asia/Tehran" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( zTehran );
Run Code Online (Sandbox Code Playgroud)

zdt.toString(): 2018-06-01T09:25+04:30[亚洲/德黑兰]

请注意,夏季的时间显示为 9 小时,而不是 8 小时。

尝试用月月相同的代码,当DST是不是有效。

LocalTime lt = LocalTime.parse( "04:55" );
LocalDate ld = LocalDate.of( 2018 , Month.JANUARY , 1 );
OffsetDateTime odt = OffsetDateTime.of( ld , lt , ZoneOffset.UTC );
ZoneId zTehran = ZoneId.of( "Asia/Tehran" );
ZonedDateTime zdt = odt.atZoneSameInstant( zTehran );
Run Code Online (Sandbox Code Playgroud)

zdt.toString(): 2018-01-01T08:25+03:30[亚洲/德黑兰]

现在我们看到 8 小时。

区域名称

以、、 或等格式指定正确的时区名称。永远不要使用 3-4 个字母的缩写,例如或因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。continent/regionAmerica/MontrealAfrica/CasablancaPacific/AucklandESTIST

ZoneId z = ZoneId.of( "America/Montreal" ) ;  
Run Code Online (Sandbox Code Playgroud)

如果您想使用 JVM 的当前默认时区,请询问它并作为参数传递。如果省略,则隐式应用 JVM 的当前默认值。最好是明确的,因为JVM 中任何应用程序的任何线程中的任何代码都可能在运行时随时更改默认值。

ZoneId z = ZoneId.systemDefault() ;  // Get JVM’s current default time zone.
Run Code Online (Sandbox Code Playgroud)

关于java.time

java.time框架是建立在Java 8和更高版本。这些类取代了麻烦的旧的遗留日期时间类,例如java.util.Date, Calendar, & SimpleDateFormat

现在处于维护模式Joda-Time项目建议迁移到java.time类。

要了解更多信息,请参阅Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规范是JSR 310

您可以直接与您的数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC 驱动程序。不需要字符串,不需要类。java.sql.*

从哪里获得 java.time 类?

ThreeTen-额外项目与其他类扩展java.time。该项目是未来可能添加到 java.time 的试验场。你可能在这里找到一些有用的类,比如IntervalYearWeekYearQuarter,和更多


Ven*_*WAR 4

 df.setTimeZone(TimeZone.getDefault());
Run Code Online (Sandbox Code Playgroud)

 df.setTimeZone(TimeZone.getTimeZone("GMT+4:30"));
Run Code Online (Sandbox Code Playgroud)

工作代码

String dateStr = "04:55";
                SimpleDateFormat df = new SimpleDateFormat("HH:mm");
                df.setTimeZone(TimeZone.getTimeZone("UTC"));
                Date date = null;
                try {
                    date = df.parse(dateStr);
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                df.setTimeZone(TimeZone.getTimeZone("GMT+4:30"));
                String formattedDate = df.format(date);


                System.out.println(formattedDate);
                //time.setText(String.valueOf(formattedDate));

        }
Run Code Online (Sandbox Code Playgroud)

我得到的输出 9:25