有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java SimpleDateFormat与带时区的ZoneDateTime

我正在尝试将PST时间戳转换为历元时间

我尝试的第一种方法是使用分区datetime,将美国/洛杉矶作为输入时区

    public static void changeStringDateFormatToEpoch(String oldDate, String format) throws ParseException {
        DateTimeFormatter dtf  = DateTimeFormatter.ofPattern(format);
        LocalDateTime dt = LocalDateTime.parse(oldDate, dtf);
        ZonedDateTime zdtzone = dt.atZone(ZoneId.of("America/Los_Angeles"));
        System.out.println("When date: "+ oldDate + " is in format "+ format + " --> "  + zdtzone.toEpochSecond());
    }

在此之后,我尝试运行下面的代码,该代码使用SimpleDataFormat执行相同的操作

 public static void changeStringDateFormatToEpochSimpleDate(String oldDate, String format) throws ParseException{
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        Date dt = sdf.parse(oldDate);
        long epoch = dt. getTime();
        System.out.println("When date: "+ oldDate + " is in format "+ format + " --> "  + epoch);
    }

在第二种情况下,我甚至没有指定输入日期的时区,这两种输出是如何相似的呢

由于输入时区是PST(美国/洛杉矶),所以纪元时间不应该受到影响吗

样本输入

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;

class Scratch {
    public static void main(String[] args) {
        String date = "2019-11-27 04:32:41.000-0800"; //yyyy-MM-dd HH:mm:ss.SSSZ
        String date2 = "2019-11-27 04:32:41"; // yyyy-MM-dd HH:mm:ss


        try {
            changeStringDateFormatToEpoch(date, "yyyy-MM-dd HH:mm:ss.SSSZ");
            changeStringDateFormatToEpoch(date2, "yyyy-MM-dd HH:mm:ss");

            changeStringDateFormatToEpochSimpleDate(date, "yyyy-MM-dd HH:mm:ss.SSSZ");
            changeStringDateFormatToEpochSimpleDate(date2, "yyyy-MM-dd HH:mm:ss");


        } catch (ParseException e) {
            e.printStackTrace();
        }
    }

    public static void changeStringDateFormatToEpoch(String oldDate, String format) throws ParseException {
        DateTimeFormatter dtf  = DateTimeFormatter.ofPattern(format);
        LocalDateTime dt = LocalDateTime.parse(oldDate, dtf);
        ZonedDateTime zdtzone = dt.atZone(ZoneId.of("America/Los_Angeles"));
        System.out.println("When date: "+ oldDate + " is in format "+ format + " --> "  + zdtzone.toEpochSecond());
    }

    public static void changeStringDateFormatToEpochSimpleDate(String oldDate, String format) throws ParseException{
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        Date dt = sdf.parse(oldDate);
        long epoch = dt. getTime();
        System.out.println("SimpleDate : When date: "+ oldDate + " is in format "+ format + " --> "  + epoch);
    }
}

输出

When date: 2019-11-27 04:32:41.000-0800 is in format yyyy-MM-dd HH:mm:ss.SSSZ --> 1574857961
When date: 2019-11-27 04:32:41 is in format yyyy-MM-dd HH:mm:ss --> 1574857961
SimpleDate : When date: 2019-11-27 04:32:41.000-0800 is in format yyyy-MM-dd HH:mm:ss.SSSZ --> 1574857961000
SimpleDate : When date: 2019-11-27 04:32:41 is in format yyyy-MM-dd HH:mm:ss --> 1574857961000

共 (2) 个答案

  1. # 1 楼答案

    编辑changeStringDateFormatToEpoch()后,出现了一个新问题:它现在忽略字符串中给定的偏移量-0800。只要它恰好与您在代码中提供的硬编码时区一致,结果就可以了;但如果偏移量不同,则会得到错误的结果。即使是美国/洛杉矶时区,当夏令时(DST)结束时,您也会在重叠处得到错误的结果,时钟时间重复,偏移量是您唯一能够区分的机会

    使用SimpleDateFormat的代码可以说有相反的问题:在缺少时区或偏移量的情况下,它使用JVM的默认时区,这可能是预期的,也可能不是预期的。JVM时区设置可以随时由程序的另一部分或在同一JVM中运行的另一个程序更改,这一事实进一步损害了这种可能性

    如果您知道美国/洛杉矶时区适用于无区域或偏移量的字符串,则解决方案如下:

    /** @throws DateTimeParseException if oldDate is not in the format given */
    public static void changeStringDateFormatToEpoch(String oldDate, String format) {
        // Time zone to use if neither time zone nor UTC offset is given in the string
        ZoneId defaultZone = ZoneId.of("America/Los_Angeles");
        DateTimeFormatter dtf  = DateTimeFormatter.ofPattern(format).withZone(defaultZone);
        ZonedDateTime zdt = ZonedDateTime.parse(oldDate, dtf);
        System.out.println("When date: " + oldDate + " is in format " + format
                            + "  > "  + zdt.toEpochSecond());
    }
    

    让我们使用您自己的代码进行尝试:

        String date = "2019-11-27 04:32:41.000-0800"; //yyyy-MM-dd HH:mm:ss.SSSZ
        String date2 = "2019-11-27 04:32:41"; // yyyy-MM-dd HH:mm:ss
    
        changeStringDateFormatToEpoch(date, "yyyy-MM-dd HH:mm:ss.SSSZ");
        changeStringDateFormatToEpoch(date2, "yyyy-MM-dd HH:mm:ss");
    

    即使在我的时区欧洲/哥本哈根运行,结果也一致:

    When date: 2019-11-27 04:32:41.000-0800 is in format yyyy-MM-dd HH:mm:ss.SSSZ  > 1574857961
    When date: 2019-11-27 04:32:41 is in format yyyy-MM-dd HH:mm:ss  > 1574857961
    

    回答您的问题

    How is that both the outputs are similar, when in the 2nd case I'm not even specifying the timezone of the input date.

    在第二种情况下SimpleDateFormat使用JVM的时区设置。仅因为这是美国/洛杉矶(或另一个使用偏移量的时区,11月27日08:00),输出才一致。当在不同的时区运行时,他们不会

    Shouldn't the epoch time get affected since the input time zone is PST(America/Los Angeles)?

    输出受JVM默认时区的影响。它不使用UTC或其他默认值,除非将默认值设置为UTC或其他默认值

    不要使用SimpleDateFormat

    SimpleDateFormat类是出了名的麻烦和过时。它给你一个令人惊讶的结果并不奇怪。一定要使用java。时间,现代Java日期和时间API,它是日期和时间工作的一部分。它倾向于提供更少的惊喜和更自然的代码

  2. # 2 楼答案

    基于SimpleDateFormat的代码只能在太平洋时区的机器上运行,才能按预期工作SimpleDateFormat实例使用系统默认时区初始化,但可以更改

    要使代码健壮且可移植,请使用第一种方法。解析LocalDateTime,然后将其与显式ZoneId组合,而不是推断默认时区

    示例中解析的某些日期时间使用偏移日期时间。这是有帮助的;许多受夏令时影响的地区的开发商忽视了在存储当地时间戳时,是否需要包括一些指示夏令时当前是否有效的必要性。如果没有它,在秋季向标准时间过渡期间,解析时间就会变得模棱两可

    在任何情况下,您都应该知道,也可以将LocalDateTimeZoneOffset组合起来生成一个OffsetDateTime,并由此生成一个纪元时间