将utc转换为伊朗当地时间

时间:2018-06-02 04:57:06

标签: android timezone 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));

4 个答案:

答案 0 :(得分:3)

1970年在伊朗没有DST

伊朗的时区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时默认为1970年第一时间的epoch reference日期,因为你在试图解析时滥用该类没有指定日期的时间。

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.Date& java.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
)
  

4时55分

LocalTime

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

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

术语

  

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

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

所以LocalTime对象在附加到日期并置于时区(或从UTC偏移)的上下文之前没有实际意义。

时区

  

如果UTC时间是04:55,我的电话时钟是9:25

这意味着您的JVM当前默认时区使用的UTC偏离UTC的前一个半小时+04:30。根据此list of time zones 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 ) ;

伊朗时间

您在评论的后面部分解释了您的预定时区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

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

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

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

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

在1月份使用相同的代码,当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。切勿使用诸如ESTIST之类的3-4字母缩写,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

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.DateCalendar和& SimpleDateFormat

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

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

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

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore

答案 1 :(得分: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

答案 2 :(得分:1)

尝试以下方法:

  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支持的时区Android Timezone

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

答案 3 :(得分:1)

试试这个方法

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
}