繁体   English   中英

SimpleDateFormat 与 ZonedDateTime 与时区

[英]SimpleDateFormat vs ZonedDateTime with timezone

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

我尝试的第一种方法是通过将美国/洛杉矶作为输入时区来使用分区日期时间。

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

在此之后我尝试运行下面的代码,它使用 SimpleDateFormat 来做同样的事情

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

output

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

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

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

您的示例中解析的某些日期时间使用偏移日期时间。 这很有帮助; 受夏令时影响的区域中的许多开发人员忽略了在存储本地时间戳时包含一些指示当前夏令时是否有效的必要性。 没有它,在秋季过渡到标准时间的过程中,解析时间会存在歧义。

在任何情况下,您都应该知道,也可以将LocalDateTimeZoneOffset以产生OffsetDateTime ,并由此产生纪元时间。

编辑您的changeStringDateFormatToEpoch()出现了一个新问题:它现在忽略了字符串中给出的偏移量-0800 只要恰好符合你在代码中硬编码提供的时区,结果就OK; 但如果偏移量不同,您将获得不正确的结果。 即使对于 America/Los_Angeles 时区,当夏令时 (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");

即使在我的时区 Europe/Copenhagen 运行时,结果也一致:

 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

回答您的问题

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

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

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

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

不要使用SimpleDateFormat

SimpleDateFormat类是出了名的麻烦且早已过时。 它给你一个令人惊讶的结果并不奇怪。 请使用 java.time, ZonedDateTime是您的日期和时间工作的一部分的现代 Java 日期和时间 API。 它往往提供更少的惊喜和更自然的代码。

    ZonedDateTime zonedDateTime = LocalDateTime.now().atZone(ZoneId.of("Asia/Hong_Kong"));
    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("MM/dd/yyyy - hh:mm:ss zzz");
    String formattedString = zonedDateTime.format(dateTimeFormatter);
    System.out.println(String.format("ZonedDateTime [%s], Formatted ZonedDateTime [%s]", zonedDateTime, formattedString));

output 是 - ZonedDateTime [2022-03-17T17:09:27.471+08:00[Asia/Hong_Kong]],格式化 ZonedDateTime [03/17/2022 - 05:09:27 HKT]

但是当我这样做的时候

SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd/mm/yyyy - hh:mm:ss zzz");
    String format = simpleDateFormat.format(zonedDateTime);
    System.out.println(format);

抛出错误

无法将 Object 格式化为日期

这意味着 SimpleDateFormat 不支持 ZonedDateTime?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM