Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/365.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
Java8时区转换_Java_Datetime_Timezone_Java Time_Datetime Conversion - Fatal编程技术网

Java8时区转换

Java8时区转换,java,datetime,timezone,java-time,datetime-conversion,Java,Datetime,Timezone,Java Time,Datetime Conversion,我知道也有类似的问题,但我没有找到与我类似的例子。我学习了LocalDateTime和ZonedDateTime,但我不知道如何告诉我的ZonedDateTime解析日期的假定时区 我正在从Java7迁移到Java8。在我的代码中,我有这样一个方法: public String changeTZ(String tzFrom, String tzTo, String dateToChange) { ZoneId zoneFrom = ZoneId.of(tzFrom); DateT

我知道也有类似的问题,但我没有找到与我类似的例子。我学习了
LocalDateTime
ZonedDateTime
,但我不知道如何告诉我的
ZonedDateTime
解析日期的假定时区

我正在从Java7迁移到Java8。在我的代码中,我有这样一个方法:

public String changeTZ(String tzFrom, String tzTo, String dateToChange) {
    ZoneId zoneFrom = ZoneId.of(tzFrom);
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat.toPattern());
    LocalDateTime localtDateAndTime = LocalDateTime.parse(dateToChange, formatter);
    ZonedDateTime dateAndTimeINeed = ZonedDateTime.of(localtDateAndTime, zoneFrom );

    ZonedDateTime rezDate = dateAndTimeINeed.withZoneSameInstant(ZoneId.of(tzTo));

    return formatter.format(rezDate);
}
示例用法是:

String rez = changeTZ("CEST", "UTC", "2017-08-10 14:23:58");
正如您所看到的,它以字符串的形式接收日期时间,时区日期位于
tzFrom
变量和我需要的TZ(
toTo
变量)

在Java7中实现这一点的代码既荒谬又复杂,所以我不会在这里引用它。您能告诉我如何在不改变方法接口(参数和返回类型)的情况下在Java8中实现同样的功能吗?DST呢?在Java8中它是自动处理的吗


请注意,该方法还支持“CEST”、“CET”、“UTC”以及“Europe/London”等标准时区。

此解决方案使用Hugo在注释中提到的IANA时区名称来获取
区域ID
(更多详细信息)。如果与CEST一起使用,将引发异常

使用类似于:

String rez = changeTZ("US/Alaska", "Europe/Berlin", "2017-08-10 14:23:58");
Java8使用的格式(总是
地区/城市
,如
美国/圣保罗
欧洲/柏林
)。 避免使用短缩写(如
CEST
PST
),因为它们是

实际上,这些名称不适用于ZoneId,主要是因为这种模糊性(例如,CST可以是“中央标准时间”、“古巴标准时间”或“中国标准时间”)。实际上,由于复古兼容性的原因,它们中的一些可能会起作用,但不能保证它们都能起作用

我假设塞斯特是第一个。有很多不同的国家(和时区)目前都在CEST中,因此如果您只是将“CEST”传递给API,API无法决定选择哪个时区

这是因为一个时区包含了一个地区在其历史上所有不同的偏移量。今天可能有很多国家使用CEST,但它们的历史在过去有所不同(一些国家可能在不同的年份使用DST,或者使用不同的偏移量,然后进行更改,等等),这就是为什么它们每个都有一个时区

不过,要使用这样的短名称(如
CEST
),您可以为每个名称定义一些默认值(这是一个任意选择),并将这些选择放在地图中:

// map of custom zone names
Map<String, String> map = new HashMap<>();
// setting my arbitrary choices for each name
map.put("CEST", "Europe/Berlin"); // Berlin during DST period
map.put("CET", "Europe/Berlin"); // Berlin during non-DST period
// ... and so on
我选择了
欧洲/柏林
,但您当然可以根据需要将其更改为任何时区。通过调用
ZoneId.getAvailableZoneIds()
,可以获得可用时区的列表(并选择最适合您的系统的时区)


使用上面的地图:

System.out.println(changeTZ("CEST", "UTC", "2017-08-10 14:23:58"));
此代码输出:

2017-08-10 12:23:58

请注意,
CEST
(我选择了
Europe/Berlin
)中的14:23是UTC中的12:23,这是正确的,因为8月份柏林是DST(偏移量是
+02:00

ZoneId
zoneDateTime
类自动处理DST效果。您可以通过选择1月份的日期(DST在柏林不生效)来检查这一点:

输出为:

2017-01-10 13:23:58

一月柏林不在DST,因此偏移量为
+01:00
,然后柏林的14:23变成UTC的13:23


当然,理想的做法是始终使用全名(如
Europe/Berlin
),但如果您无法控制输入,则可以使用自定义映射


Java8也有一个类,但与任何其他预定义的东西一样,选择是任意的,不一定是您需要的

public class TimeZoneConverter {

    private static String datePattern = "yyyy-MM-dd HH:mm:ss";

    public static void main(String[] args) throws ParseException {
        String sourceDate = "2017-02-27 16:00:00";
        String resultDate = convertTimeZone("EET", "UTC", sourceDate);

        System.out.println("EET: "+ sourceDate);
        System.out.println("UTC: "+ resultDate);
    }

    public static String convertTimeZone(String timeZoneFrom, String timeZoneTo, String date) throws ParseException {
        long timestamp = stringToTimestamp(date, timeZoneFrom);
        String result = timestampToString(timestamp, timeZoneTo);
        return result;
    }

    public static long stringToTimestamp(String time, String timeZone) throws ParseException {
        DateFormat format = getDateFormat(timeZone);
        return format.parse(time).getTime();
    }

    public static String timestampToString(long timestamp, String timeZone) {
        DateFormat format = getDateFormat(timeZone);
        return format.format(new Date(timestamp));
    }

    private static DateFormat getDateFormat(String timeZone) {
        DateFormat format = new SimpleDateFormat(datePattern);
        format.setTimeZone(TimeZone.getTimeZone(timeZone));
        return format;
    }

}

请看下面的答案:Java8使用的格式(总是
地区/城市
,如
美国/圣保罗
欧洲/柏林
)。它不直接支持三个字母的缩写(如
CST
PST
),因为它们是,尽管你可以使用一些。@Robin我编辑了我的问题。“看起来还可以”-你确定
ZoneId.of(“CEST”)
不会引发异常吗?对我来说,“DST呢?”-
ZoneId
zoneDateTime
类自动处理DST效果。可能在原始界面中输入CEST、CET等。。。映射偏移而不是分区的步骤。如果这是真的,那么他能做的最好的映射应该是
map.put(“CEST”,“+2”)
map.put(“CET”、“+1”)
etc.@Phoenix这是一个选项,但我更喜欢使用时区,因为当涉及历史信息时(DST开始和结束时),偏移量“不太准确”。对于这种特殊情况,它可能会起作用,但我认为理想的做法是使用时区。我接受这个答案,因为它确实详细地解释了事情。“CET”/“CEST”映射的额外积分:)@guest86另一个细节:特别是“UTC”,您可以使用常量
ZoneOffset.UTC
,而不是
ZoneId.of
(尽管最终结果相同)谢谢,这真的很好,很简短谢谢!很好的解决方案。
System.out.println(changeTZ("CEST", "UTC", "2017-08-10 14:23:58"));
// January is not DST, so use CET
System.out.println(changeTZ("CET", "UTC", "2017-01-10 14:23:58"));
public class TimeZoneConverter {

    private static String datePattern = "yyyy-MM-dd HH:mm:ss";

    public static void main(String[] args) throws ParseException {
        String sourceDate = "2017-02-27 16:00:00";
        String resultDate = convertTimeZone("EET", "UTC", sourceDate);

        System.out.println("EET: "+ sourceDate);
        System.out.println("UTC: "+ resultDate);
    }

    public static String convertTimeZone(String timeZoneFrom, String timeZoneTo, String date) throws ParseException {
        long timestamp = stringToTimestamp(date, timeZoneFrom);
        String result = timestampToString(timestamp, timeZoneTo);
        return result;
    }

    public static long stringToTimestamp(String time, String timeZone) throws ParseException {
        DateFormat format = getDateFormat(timeZone);
        return format.parse(time).getTime();
    }

    public static String timestampToString(long timestamp, String timeZone) {
        DateFormat format = getDateFormat(timeZone);
        return format.format(new Date(timestamp));
    }

    private static DateFormat getDateFormat(String timeZone) {
        DateFormat format = new SimpleDateFormat(datePattern);
        format.setTimeZone(TimeZone.getTimeZone(timeZone));
        return format;
    }

}