Java时区转换

时间:2010-09-12 12:01:00

标签: java timezone

我有一个字符串,用UTC表示时间。 考虑到夏令时,我需要将其转换为自美国东部时间午夜以来的毫秒数。 例如,在1月份,偏移量为5小时,但在6月4小时。

但是,下面的代码显示6月和1月的相同偏差为5小时。 变量tzOffset = -18000000(= -5小时),无论日期月份。

请指教,

谢谢!

package TimeConversion;

import java.text.SimpleDateFormat;

import java.util.*;

public class TimeConversion {

    public static void main(String[] args) throws Exception {

        String utcTime = "20100101120000000";
        SimpleDateFormat sdfIn = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        sdfIn.setTimeZone(TimeZone.getTimeZone("UTC"));        
        long utcMillis = sdfIn.parse(utcTime).getTime();
        long tzOffset = TimeZone.getTimeZone("EST").getOffset(utcMillis);
        long estMillis = utcMillis + tzOffset;
        long estMillisSinceMidnight = estMillis % 86400000;
        System.out.println("utcTime = " + utcTime + "\nestMillisSinceMidnight = " + estMillisSinceMidnight + "(" + 24.0 * estMillisSinceMidnight / 86.4e6 + ")");
    }

}

2 个答案:

答案 0 :(得分:0)

您可以从this calendar conversion utility窃取一些代码。你可能需要的是getLocalTime。免责声明:我写了它。

答案 1 :(得分:0)

tl; dr

Duration                                                     // Represent a span-of-time not attached to the timeline, on a scale of hours-minutes-seconds.
.between(                                                    // Instantiate a `Duration` by calculating time elapsed between a pair of moments.
    LocalDateTime.parse(                                     // Represent a date with time-of-day but lacking the context of a time zone or offset-from-UTC.
        "20100101120000000" ,                                // Tip: Use standard ISO 8601 formats instead of inventing your own.
        DateTimeFormatter.ofPattern( "uuuuMMddHHmmssSSS" ) 
    )                                                        // Returns a `LocalDateTime` object.
    .atZone(                                                 // Place this date-with-time in the context of a particular time zone to determine a moment, a specific point on the timeline.
        ZoneId.of( "America/Montreal" )                      // Never use 2-4 character pseudo-zones such as `EST` or `EDT`. Real time zone names are in `Continent/Region` format.
    )                                                        // Returns a `ZonedDateTime` object.
    .toLocalDate()                                           // Extracts the date-only portion from a `ZonedDateTime` object.
    .atStartOfDay(                                           // Determine the first moment of the day on that date as seen in a particular time zone.
        ZoneId.of( "America/Montreal" )
    )                                                        // Returns a `ZonedDateTime` object, rather than altering original. (immutable objects)                     
    ,
    LocalDateTime.parse( 
        "20100101120000000" , 
        DateTimeFormatter.ofPattern( "uuuuMMddHHmmssSSS" ) 
    )
    .atZone(
        ZoneId.of( "America/Montreal" )
    )
)                                                             // Returns a `Duration`.
.toMillis()                                                   // Returs a `long` integer. 

请注意可能的数据丢失,因为任何毫秒或纳秒都不会以较粗的毫秒数来解释。

ISO 8601

字符串utcTime =“ 20100101120000000”;

顺便说一句,而不是发明自己的格式,请使用标准的ISO 8601格式来交换日期时间值作为文本。该标准就是为此目的而发明的。

java.time

定义一种格式设置以匹配您的输入。

String input = "20100101120000000";
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuuMMddHHmmssSSS" ) ;

解析为LocalDateTime对象,因为您的输入缺少时区或自UTC偏移的上下文。

LocalDateTime ldt = LocalDateTime.parse( input , f ) ;

如果您可以确定该日期和日期的预期时区,请应用ZoneId以获得ZonedDateTime

我猜测EDT是指北美或加勒比海地区的东海岸时间。那可以是任意数量的各种时区,例如America/New_YorkAmerica/Louisville等。我在这里任意猜测我的代码示例为America/Montreal

请勿使用2-4个字母的缩写,例如EDTESTIST,因为它们不是真正的时区,不是标准化的,也不是甚至唯一的(!)。以Continent/Region的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland

ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ;

您希望获得从该时区中第一天的第一刻开始经过的时间,直到我们刚刚确定的ZonedDateTime对象。

java.time 确定一天的第一时刻。在某些日期的某些区域中,日期可能不会从00:00开始。

LocalDate ld = zdt.toLocalDate() ;
ZonedDateTime zdtStartOfDay = ld.atStartOfDay( z ) ;

将经过时间计算为Duration。提要输入为Instant对象,它们表示与我们的ZonedDateTime对象相同的时刻,但已调整为UTC(零小时-分钟-秒的偏移量)。

Duration d = Duration.between(
    zdtStartOfDay.toInstant() ,
    zdt.toInstant() 
);

显然,您希望将时间跨度表示为毫秒数。小心可能的数据丢失,因为ZonedDateTimeInstant类解析为更精细的纳秒。

long millis = d.toMillis() ;  // Report entire span-of-time as a count of milliseconds. Beware: possible data loss as any microseconds and nanoseconds are ignored. 

请参见此code run live at IdeOne.com。我们得到了12个小时的结果。

d.toString():PT12H

毫里斯:43200000