如何将日期时间字符串转换为Instant? - Kotlin/Java

5

我正在尝试从日期和时间字符串创建一个Instant实例。日期格式为yyyy-MM-dd。因此,值可能是这样的:

val date = "2021-11-25"
val time = "15:20"

我正在尝试从这两个字符串中创建有效的时间戳,如下所示:

val dateTime = "${date}T${time}:00"
val instantDateTime = ZonedDateTime.parse(dateTime, 
                                          DateTimeFormatter.ISO_OFFSET_DATE_TIME.withZone(defaultTimeZone)
                                         ).toInstant()

我也尝试使用它:

val instantDateTime = Instant.from(DateTimeFormatter .ISO_OFFSET_DATE_TIME.withZone(defaultTimeZone).parse(dateTime))

但是,那不起作用,我收到了:

Exception in thread "main" java.time.format.DateTimeParseException: Text '2021-11-25T15:20:00' could not be parsed at index 19
2个回答

7
你可以将日期和时间字符串组合成ISO 8601格式的日期时间字符串,然后可以将其解析为LocalDateTime,再使用适当的ZoneId转换为Instant。请注意,现代日期时间API基于ISO 8601,只要日期时间字符串符合ISO 8601标准,就不需要显式使用DateTimeFormatter对象。
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;

public class Main {
    public static void main(String[] args) {
        String strDate = "2021-11-25";
        String strTime = "15:20";
        String strDateTime = strDate + "T" + strTime;
        LocalDateTime ldt = LocalDateTime.parse(strDateTime);
        Instant instant = ldt.atZone(ZoneId.systemDefault()).toInstant();
        System.out.println(instant);
    }
}

输出:

2021-11-25T15:20:00Z

在线演示

一些替代方法:

  1. 可以像daniu建议的那样,单独解析日期和时间字符串,并使用它们创建LocalDateTime实例。

演示:

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;

public class Main {
    public static void main(String[] args) {
        String strDate = "2021-11-25";
        String strTime = "15:20";
        LocalDateTime ldt = LocalDateTime.of(LocalDate.parse(strDate), LocalTime.parse(strTime));
        Instant instant = ldt.atZone(ZoneId.systemDefault()).toInstant();
        System.out.println(instant);
    }
}

在线演示

  1. 按照Ole V.V.的建议,使用ZonedDateTime#of(LocalDate, LocalTime, ZoneId)创建ZonedDateTime实例。你也可以尝试使用ZonedDateTime#of(LocalDateTime, ZoneId)这种方法的另一种变体。

演示:

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class Main {
    public static void main(String[] args) {
        String strDate = "2021-11-25";
        String strTime = "15:20";
        ZonedDateTime zdt = ZonedDateTime.of(LocalDate.parse(strDate), LocalTime.parse(strTime),
                                                ZoneId.systemDefault());
        // Alternatively
        // ZonedDateTime zdt = ZonedDateTime.of(LocalDateTime.of(LocalDate.parse(strDate), LocalTime.parse(strTime)),
        //                                          ZoneId.systemDefault());
        
        Instant instant = zdt.toInstant();
        System.out.println(instant);
    }
}

在线演示

  1. 将日期和时间字符串合并为 ISO 8601 格式的日期时间字符串,并使用 DateTimeFormatter.ISO_LOCAL_DATE_TIME.withZone(ZoneId.systemDefault()) 解析为 ZonedDateTime

演示:

import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

public class Main {
    public static void main(String[] args) {
        String strDate = "2021-11-25";
        String strTime = "15:20";
        DateTimeFormatter dtf = DateTimeFormatter.ISO_LOCAL_DATE_TIME.withZone(ZoneId.systemDefault());
        ZonedDateTime zdt = ZonedDateTime.parse(strDate + "T" + strTime, dtf);
        Instant instant = zdt.toInstant();
        System.out.println(instant);
    }
}

在线演示

  1. 通过解析日期和时间字符串创建LocalDateTime实例,并使用LocalDateTime#toInstant获取所需的Instant

演示:

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;

public class Main {
    public static void main(String[] args) {
        String strDate = "2021-11-25";
        String strTime = "15:20";
        LocalDateTime ldt = LocalDateTime.of(LocalDate.parse(strDate), LocalTime.parse(strTime));
        Instant instant = ldt.toInstant(ZoneId.systemDefault().getRules().getOffset(ldt));
        System.out.println(instant);
    }
}

在线演示

教程:日期时间了解更多关于现代日期时间API*的内容。查看这个答案这个答案,学习如何在JDBC中使用java.time API。


* 如果您正在开发 Android 项目,而您的 Android API 级别仍未符合 Java-8,请查看 通过去糖化可用的 Java 8+ APIs。请注意,Android 8.0 Oreo 已经提供了对java.time的支持


1
个人观点而已,但我发现将每个项目分别解析为 LocalDateLocalTime 更加清晰,然后再通过 LocalDateTime.of() 组合它们。这样你就可以避免与中间字符串搭配使用。 - daniu
1
@daniu - 这确实是一个很好的建议!现在,我已经将它纳入了答案。谢谢。 - Arvind Kumar Avinash
我在这里和@daniu一样。我们甚至可以使用三个参数的ZonedDateTime.of(LocalDate, LocalTime, ZoneId)直接组合成一个ZonedDateTime - Ole V.V.
1
没错,@OleV.V. 我已经用这些方法写了很多答案。只是我写下了脑海中浮现的第一个解决方案。我仍然可以想到至少三种更好的解决方案,但目前我没有时间去写它们。我会在有时间的时候添加它们。 - Arvind Kumar Avinash

0

你的日期字符串中不包含时区信息,因此无法直接解析为 ZonedDateTime(请参见 ZonedDateTime#parse 的 javadoc)。

尝试将字符串解析为 LocalDateTime(使用 LocalDate#parse )。

然后,您可以使用 LocalDateTime#toInstantLocalDateTime 转换为 Instant,或者使用 LocalDateTime#atZone 将其转换为 ZonedDateTime


@Abra 我认为我的回答确实提供了足够清晰的信息来解决问题。当然,它不是一份即可复制粘贴的答案,但这个平台的主要目的是帮助人们学习和理解,而不是提供现成的复制粘贴解决方案,对吧? - marthursson
@marthursson 实际上我的问题有误导性,我只需要将字符串转换为Instant,有什么简单的方法吗? - Leff
@Leff 更新了答案,提供了如何生成即时的信息。 - marthursson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接