【问题标题】:convert utc to local time in iran将UTC转换为伊朗当地时间
【发布时间】:2018-11-12 04:46:17
【问题描述】:

我尝试将 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));

【问题讨论】:

标签: android timezone simpledateformat


【解决方案1】:

1970 年伊朗没有夏令时

伊朗的时区 Asia/Tehran 在 2018 年夏天观察到 Daylight Saving Time (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" )
       )
);

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

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

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

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

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

错误的类

您使用了错误的类。

您想表示一个时间值。所以你应该使用一天中的时间课程。但是您正在使用日期与时间类java.util.Date

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

时间

解析时间字符串。

LocalTime.parse( "04:55" )

获取当前时间。

LocalTime.now()                  // Capture the current time of day per the JVM’s current default time zone.

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

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

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

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).
)

9:25

以 UTC 格式获取当前时间。

LocalTime.now( 
    ZoneOffset.UTC
)

04:55

LocalTime

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

String input = "04:55" ;
LocalTime lt = LocalTime.parse( input ) ;

术语

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

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

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

时区

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

这意味着您的 JVM 当前的默认时区使用比 UTC 提前四个半小时的 UTC 偏移量,+04:30。根据list of time zones as managed by the IANA,当前只有一个时区使用该偏移量:Asia/Kabul

要完全表示当前时刻,您需要日期和时间以及区域/偏移量。要捕捉当前时刻,请使用InstantInstant 类代表UTC 时间线上的时刻,分辨率为nanoseconds(最多九 (9) 位小数)。

Instant instant = Instant.now() ;  // Capture the current moment in UTC.

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

ZoneId zKabul = ZoneId.of( "Asia/Kabul" ) ;
ZonedDateTime zdt = instant.atZone( zKabul ) ;

如果您真的只想要该值的时间部分,请提取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).

作为快捷方式,您可以拨打LocalTime.now

LocalTime lt = LocalTime.now( zKabul ) ;

伊朗时间

稍后在您的 cmets 中,您解释您的预期时区是 Asia/Tehrantime in Iran。目前,伊朗遵守夏令时 (DST),这可能是您困惑的根源。虽然标准偏移量是 +03:30(比 UTC 提前三个半小时),但在 3 月 22 日和 9 月 22 日之间,偏移量是 +04:30,比 UTC 提前一个小时。

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

让我们建立一个 6 月 1 日的日期时间,您的示例时间是 UTC 时间 4:55。我们可以使用常量ZoneOffset.UTC。如果仅使用与 UTC 的偏移量(在这种情况下偏移量为零),请使用 OffsetDateTimeoffset-from-UTC 只是几个小时和分钟,不多也不少。相比之下,time zone 是过去、现在和未来对特定区域的人们使用的偏移量变化的历史。

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

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

通过应用ZoneId 调整到区域Asia/Tehran 以获得ZonedDateTime。同一时刻,时间轴上的同一点,但挂钟时间不同。

ZoneId zTehran = ZoneId.of( "Asia/Tehran" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( zTehran );

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 );

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

现在我们看到一个 8 小时。

区域名称

continent/region 的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用 3-4 个字母的缩写,例如 ESTIST,因为它们不是真正的时区,没有标准化,甚至不是唯一的 (!)。

ZoneId z = ZoneId.of( "America/Montreal" ) ;  

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

ZoneId z = ZoneId.systemDefault() ;  // Get JVM’s current default time zone.

关于java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

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

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

从哪里获得 java.time 类?

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

【讨论】:

    【解决方案2】:
     df.setTimeZone(TimeZone.getDefault());
    

     df.setTimeZone(TimeZone.getTimeZone("GMT+4:30"));
    

    工作代码

    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));
    
            }
    

    我得到了 9:25 的输出

    【讨论】:

    • 哦..它在我的 IDE 中工作。请验证您导入的类
    • 我正在使用这个类 import java.text.ParseException;导入 java.text.SimpleDateFormat;导入 java.util.Date;导入 java.util.TimeZone;
    • 是的,先生,我正确导入了这些类,但没有启动
    • 在普通的java代码中执行这段代码(使用main())
    • 我将“GMT+4:30”更改为“GMT+2:30”并开始工作,但是当我的国家一年两次的时间发生变化时,我对这个 +2:30 感到紧张,所以还有很多
    【解决方案3】:

    试试这个方法

    public static String convertUTCtoLocalTimeZone(String date, String date_formate) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(date_formate,Locale.getDefault());
        Date myDate = null;
        try {
            simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
            myDate = simpleDateFormat.parse(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }
    
        return new SimpleDateFormat(date_formate, Locale.getDefault()).format(myDate); // Note: Use new DateFormat
    }
    

    【讨论】:

    • UTC 时间是 07:53,我的手机时钟是 10:22,你的代码生成 11:22
    • 我已经更新了我的答案,请再试一次让我知道
    【解决方案4】:

    试试下面的方法:

      private String convertDateToUserTimeZone(String serverDate) {
        String ourdate;
    
        try {
            SimpleDateFormat serverFormatter = new SimpleDateFormat(
                    "yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.UK);
            serverFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
            Date value = serverFormatter.parse(serverDate);
            TimeZone timeZone = TimeZone.getTimeZone("Asia/Kolkata");
    //            SimpleDateFormat dateFormatter = new SimpleDateFormat(serverdateFormat, Locale.UK); //this format changeable
                serverFormatter.setTimeZone(timeZone);
                ourdate = serverFormatter.format(value);
    
            //Log.d("OurDate", OurDate);
        } catch (Exception e) {
            ourdate = "00-00-0000 00:00";
        }
        return ourdate;
    }
    

    所有安卓支持的时区Android Timezone

    日期时间我建议JodaTime Lib。它有丰富的有用功能。

    【讨论】:

    • 方法不工作
    • 您正在使用多年前被 java.time 类取代的麻烦的旧类。同样,Joda-Time 项目处于维护模式,其团队建议迁移到 java.time 类。
    猜你喜欢
    • 2021-03-20
    • 2015-09-26
    • 1970-01-01
    • 2011-03-25
    • 2013-07-14
    • 2023-04-09
    • 2013-03-12
    • 1970-01-01
    • 2018-07-27
    相关资源
    最近更新 更多