Java 如何将时间戳字符串转换为历元时间?

Java 如何将时间戳字符串转换为历元时间?,java,timestamp,epoch,java-time,datetime-parsing,Java,Timestamp,Epoch,Java Time,Datetime Parsing,我的时间戳格式为2017-18-08 11:45:30.345 我想将其转换为大纪元时间,因此我将执行以下操作: String timeDateStr = "2017-18-08 11:45:30.345"; DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-dd-MM HH:mm:ss.SSS"); ZonedDateTime zdt = ZonedDateTime.parse(timeDateStr, dtf);

我的时间戳格式为
2017-18-08 11:45:30.345

我想将其转换为大纪元时间,因此我将执行以下操作:

String timeDateStr = "2017-18-08 11:45:30.345"; 
DateTimeFormatter dtf  = DateTimeFormatter.ofPattern("yyyy-dd-MM HH:mm:ss.SSS");
ZonedDateTime     zdt  = ZonedDateTime.parse(timeDateStr, dtf);        
System.out.println(zdt.toInstant().toEpochMilli());
我得到以下错误:

java.time.format.DateTimeParseException:无法分析文本“2017-18-08 11:45:30.345”:无法从TemporalAccessor获取ZonedDateTime


我也尝试了不同的格式,但仍然有错误

更正了有关yyyy dd MM的代码。此外,分钟值可能为1-59,而不是60。你提供了60英镑。这是解决这个问题的另一个简单方法。只需使用DateFormat类

String timeDateStr = "2017-18-08 12:59:30.345";
DateFormat df = new SimpleDateFormat("yyyy-dd-MM hh:mm:ss.SSS", Locale.ENGLISH);
try {
    Date d = df.parse(timeDateStr);
    System.out.println(d.toInstant().toEpochMilli());
} catch (ParseException e) {
    e.printStackTrace();
}
注意:问题输入了
2017-18-08 12:60:30.345
(分钟字段中有
60
),然后(时间从
12:60
更改为
11:45
),但我决定继续讨论原始输入(
12:60
),因为它也适用于编辑的版本(
11:45


ZonedDateTime
需要时区或偏移量,但输入的
字符串中没有它(它只有日期和时间)

输入中还有其他详细信息:

  • 分钟值是
    60
    ,这是不被接受的:有效值是从0到59(实际上有一种方法可以接受,请参阅下面的“宽松解析”)
  • hh
    是唯一的,因此它还需要完全解析AM/PM指示符。因为没有,所以应该使用
    HH
    模式
因此模式必须是
yyyy-dd-MM HH:MM:ss.SSS
,输入不能将
60
作为分钟值(除非使用宽松解析,我将在下面解释),并且不能直接解析为
ZoneDateTime
,因为它没有时区/偏移指示器

另一种方法是将其解析为
LocalDateTime
,然后定义此日期所在的时区/偏移量。在下面的示例中,我假设它位于:

这将输出:

1503061170345

这相当于中的
2017-18-08 12:59:30.345

如果希望日期位于其他时区,可以使用
ZoneId
类:

// get the LocalDateTime in some timezone
ZonedDateTime z = dt.atZone(ZoneId.of("Europe/London"));
System.out.println(z.toInstant().toEpochMilli());
String timeDateStr = "2017-18-08 12:60:30.345";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-dd-MM HH:mm:ss.SSS")
    // use lenient parsing
    .withResolverStyle(ResolverStyle.LENIENT);
// parse to LocalDateTime
LocalDateTime dt = LocalDateTime.parse(timeDateStr, dtf);
输出为:

150305757345

请注意,结果是不同的,因为相同的本地日期/时间在每个时区代表不同的
瞬间
(在世界各地,本地日期/时间
2017-18-08 12:59:30.345发生在不同的瞬间)

还要注意,API使用的格式(始终为
地区/城市
,如
美国/圣保罗
欧洲/柏林
)。 避免使用三个字母的缩写(如
CST
PST
),因为它们是

通过调用
ZoneId.getAvailableZoneIds()
,可以获得可用时区的列表(并选择最适合您的系统的时区)

您也可以将系统的默认时区
ZoneId.systemDefault()
一起使用,但即使在运行时,也可以在不事先通知的情况下更改,因此最好明确使用特定的时区


还可以选择将
LocalDateTime
转换为(如
-05:00
+03:00
):

输出将相当于偏移量
+03:00
(UTC前3小时)中的本地日期/时间:

1503050370345


宽松解析 同样,您可以在分钟字段中使用宽松解析来接受
60
(使用
java.time.format.ResolverStyle
类):

在这种情况下,将60分钟调整到下一个小时,
LocalDateTime
将为:

2017-08-18T13:00:30.345


夏时制 如果您决定使用UTC或固定偏移量(使用
ZoneOffset
class),则可以忽略此部分

但是,如果您决定使用时区(使用
ZoneId
class),您还必须注意这些问题。我将以我居住的时区为例(
美国/圣保罗

在圣保罗,DST从2017年10月15日开始:午夜,时钟从午夜向前移动1小时至凌晨1点。所以00:00到00:59之间的所有本地时间都不存在于这个时区中。如果在此时间间隔内创建本地日期,则会将其调整到下一个有效时刻:

ZoneId zone = ZoneId.of("America/Sao_Paulo");

// October 15th 2017 at midnight, DST starts in Sao Paulo
LocalDateTime d = LocalDateTime.of(2017, 10, 15, 0, 0, 0, 0);
ZonedDateTime z = d.atZone(zone);
System.out.println(z);// adjusted to 2017-10-15T01:00-02:00[America/Sao_Paulo]
DST结束时:2018年2月18日午夜,时钟倒转1小时,从午夜到17日晚23点。因此,从23:00到23:59的所有本地时间都存在两次(在DST和非DST中),您必须决定您想要哪一次:

// February 18th 2018 at midnight, DST ends in Sao Paulo
// local times from 23:00 to 23:59 at 17th exist twice
LocalDateTime d = LocalDateTime.of(2018, 2, 17, 23, 0, 0, 0);
// by default, it gets the offset before DST ends
ZonedDateTime beforeDST = d.atZone(zone);
System.out.println(beforeDST); // before DST end: 2018-02-17T23:00-02:00[America/Sao_Paulo]

// get the offset after DST ends
ZonedDateTime afterDST = beforeDST.withLaterOffsetAtOverlap();
System.out.println(afterDST); // after DST end: 2018-02-17T23:00-03:00[America/Sao_Paulo]
请注意,DST结束前后的日期具有不同的偏移量(
-02:00
-03:00
)。这会影响Epochmili的值


您必须检查DST何时在您选择的时区开始和结束,并相应地检查调整。

刚才我在nagendra547的答案中做了一点更改

请参考以下代码:-

String timeDateStr = "2017-18-08 12:59:30.345";
DateFormat df = new SimpleDateFormat("yyyy-dd-mm hh:mm:ss.SSS", Locale.ENGLISH);
try {
    Date d = df.parse(timeDateStr);
    System.out.println(d.toInstant().toEpochMilli());
} catch (ParseException e) {
    e.printStackTrace();
}

您的代码将因以下3个原因失败

  • 您的日期字符串(
    2017-18-08 12:60:30.345
    )与您使用的格式设置程序不匹配。它应该是yyyy-MM-dd HH:MM:ss.SSS而不是yyy-dd-MM HH:MM:ss.SSS
  • 分钟的范围是(0-59),60不在此范围内
  • 即使您已基于上述点更正了代码,它也不会在
    ZoneDateTime
    中运行。因此,您需要在之前创建一个
    LocalDateTime
    ,然后将一个
    ZoneId
    传递给它
  • 代码应如下所示:

    String timeDateStr = "2017-18-08 12:59:30.345"; 
    DateTimeFormatter dtf  = DateTimeFormatter.ofPattern("yyyy-dd-MM HH:mm:ss.SSS");
    LocalDateTime date = LocalDateTime.parse(timeDateStr, dtf);
    ZonedDateTime     zdt  = date.atZone(ZoneId.of("Europe/London"));
    System.out.println(zdt.toInstant().toEpochMilli());
    

    这是打字错误,请检查更新的问题。谢谢你的指点。@Assafs不,不是唯一的错误。也请看一看模式符号“h”。@User7723337分钟是60?您解决了这个问题吗?ZonedDateTime在这个模式没有时区信息时有效吗?您是唯一一个看到h对h错误的回答者(因此向上投票)。关于mi
    String timeDateStr = "2017-18-08 12:59:30.345";
    DateFormat df = new SimpleDateFormat("yyyy-dd-mm hh:mm:ss.SSS", Locale.ENGLISH);
    try {
        Date d = df.parse(timeDateStr);
        System.out.println(d.toInstant().toEpochMilli());
    } catch (ParseException e) {
        e.printStackTrace();
    }
    
    String timeDateStr = "2017-18-08 12:59:30.345"; 
    DateTimeFormatter dtf  = DateTimeFormatter.ofPattern("yyyy-dd-MM HH:mm:ss.SSS");
    LocalDateTime date = LocalDateTime.parse(timeDateStr, dtf);
    ZonedDateTime     zdt  = date.atZone(ZoneId.of("Europe/London"));
    System.out.println(zdt.toInstant().toEpochMilli());