【问题标题】:How to parse UTC timestamp of format yyyy-MM-ddTHH:mm:ss.SSS+ZZZZ如何解析格式 yyyy-MM-ddTHH:mm:ss.SSS+ZZZZ 的 UTC 时间戳
【发布时间】:2021-03-15 16:41:09
【问题描述】:

我的时间戳为2020-12-03T05:35:59.398+0000,格式为String,正在流式批处理中接收。

我只想要2020-12-03 05:35:59 作为java.sql.Timestamp 实例,以便能够将它与其他Timestamp 实例进行比较。

Timestamp.valueOf() 函数出现以下错误:

Exception in thread "main" java.time.format.DateTimeParseException : Text '2020-12-03T05:35:59.398+0000' could not be parsed at index 23

我尝试了here给出的答案,确实发生了转换,但时间改为2020-12-03 11:05:59

我尝试在here 给出的格式之间进行更改,但仍然没有解决方案。

398+0000 之间是否有带有奇怪+ 的时间戳格式?

【问题讨论】:

  • 欢迎cmets对该问题投反对票
  • 编辑后请立即查看。
  • 你能避免使用Timestamp吗?该课程设计不佳且令人困惑,并且早已过时。如果您告诉我们您从哪里获得另一个 Timestamp,我们可能会提供更好的替代方案,用 java.time, the modern Java date and time API 中的类替换(或转换为)类,例如 OffsetDateTIme
  • 听起来您有两个String 类型的日期,并且您想将它们转换为日期/时间类型,以便在它们上调用比较方法。那是对的吗?如果是这样,我建议使用java.time 库并远离java.sql.Timestamp,它是旧的和过时的java.util.Date 的薄包装。
  • 但是时间改成了2020-12-03 11:05:59。不,它没有改变。它只是在您所在的时区(可能是亚洲/加尔各答)打印的。

标签: java scala timestamp utc timestamp-with-timezone


【解决方案1】:

java.time

我建议您使用现代 Java 日期和时间 API java.time 进行日期和时间工作。

    DateTimeFormatter isoFormatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSxx");
    DateTimeFormatter sqlTimestampFormatter = new DateTimeFormatterBuilder()
            .append(DateTimeFormatter.ISO_LOCAL_DATE)
            .appendLiteral(' ')
            .append(DateTimeFormatter.ISO_LOCAL_TIME)
            .toFormatter();
    
    String aTimestampString = "2020-12-03T05:35:59.398+0000";
    String anotherTimestampString = "2020-12-04 06:43:58.556385";
    
    Instant anInstant = isoFormatter.parse(aTimestampString, Instant::from);
    Instant anotherInstant = LocalDateTime.parse(anotherTimestampString, sqlTimestampFormatter)
            .atOffset(ZoneOffset.UTC)
            .toInstant();
    
    if (anInstant.isBefore(anotherInstant)) {
        System.out.println(aTimestampString + " is earlier");
    } else {
        System.out.println(anotherTimestampString + " is earlier");
    }

这个例子的输出是:

2020-12-03T05:35:59.398+0000 更早

上面前一个字符串中的+0000 是与UTC 的偏移量——00 小时00 分钟的偏移量。由于它为零,我们知道时间是 UTC。我不知道另一个字符串的时区或 UTC 偏移量。你需要知道,否则你会得到不正确的结果。在上面的代码中,我假设另一个字符串也是 UTC。

不要使用时间戳

我尝试了这里给出的答案,转换确实发生了,但是时间 改为2020-12-03 11:05:59

这就是Timestamp 类的混乱程度。您得到了正确的时间戳值。当您打印 Timestamp 对象时,会发生什么(隐式或显式)调用它的toString 方法。 Timestamp.toString() 混淆使用 JVM 的默认时区来呈现字符串。因此,如果您的时间戳等于 2020-12-03T05:35:59.398 UTC 并且您的时区是亚洲/加尔各答,那么时间将转换为亚洲/加尔各答时区并返回并打印字符串 2020-12-03 11:05:59

你没有什么好用的老式java.sql.Timestamp 类。它最初用于在 SQL 数据库之间传输带有和不带有时区的时间戳值。从 JDBC 4.2 开始,我们更喜欢 OffsetDateTimeInstantLocalDateTime。所以忘记Timestamp类吧。

链接

Oracle tutorial: Date Time 解释如何使用 java.time。

【讨论】:

    【解决方案2】:

    在 398+0000 之间是否有带有奇怪 + 的时间戳格式?

    398 部分是秒(毫秒)部分,而+0000 部分是区域偏移部分。

    您可以使用格式模式uuuu-MM-dd'T'HH:mm:ss.SSSX2020-12-03T05:35:59.398+0000 解析为OffsetDateTime

    演示:

    import java.time.OffsetDateTime;
    import java.time.format.DateTimeFormatter;
    
    public class Main {
        public static void main(String[] args) {
            String text = "2020-12-03T05:35:59.398+0000";
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSX");
            OffsetDateTime odt = OffsetDateTime.parse(text, formatter);
            System.out.println(odt);
        }
    }
    

    输出:

    2020-12-03T05:35:59.398Z
    

    查看DateTimeFormatter documentation page,了解有关用于格式化的字母的更多信息。

    您可以使用OffsetDateTimeisBeforeisAfter 函数来比较它的两个实例。

    演示:

    import java.time.OffsetDateTime;
    import java.time.format.DateTimeFormatter;
    
    public class Main {
        public static void main(String[] args) {
            String text = "2020-12-03T05:35:59.398+0000";
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSX");
            OffsetDateTime odt = OffsetDateTime.parse(text, formatter);
            OffsetDateTime odtNow = OffsetDateTime.now();
            System.out.println(odtNow.isBefore(odt));
            System.out.println(odtNow.isAfter(odt));
        }
    }
    

    输出:

    false
    true
    

    通过 Trail: Date Time 了解有关现代日期时间 API 的更多信息。如果您正在为一个 Android 项目工作并且您的 Android API 级别仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaringHow to use ThreeTenABP in Android Project

    java.util 的日期时间 API 及其格式化 API SimpleDateFormat 已过时且容易出错。建议完全停止使用它们并切换到modern date-time API。由于java.sql.Timestamp extends java.util.Date,建议也停止使用它。但是,无论出于何种原因,如果您仍想在新式和旧式日期时间 API 之间使用转换,请使用 Instant 作为桥梁。

    import java.sql.Timestamp;
    import java.time.Instant;
    import java.time.OffsetDateTime;
    import java.time.format.DateTimeFormatter;
    
    public class Main {
        public static void main(String[] args) {
            String text = "2020-12-03T05:35:59.398+0000";
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSX");
            OffsetDateTime odt = OffsetDateTime.parse(text, formatter);
            Instant instant = odt.toInstant();
            Timestamp timestamp = new Timestamp(instant.toEpochMilli());
            System.out.println(timestamp);
        }
    }
    

    输出:

    2020-12-03 05:35:59.398
    

    【讨论】:

      【解决方案3】:

      您可以将自定义DateFormatter 用于非标准格式。这是您的用例的工作示例。

      import java.time.LocalDateTime;
      import java.time.format.DateTimeFormatter;
      import java.time.format.DateTimeFormatterBuilder;
      
      import static java.time.temporal.ChronoField.*;
      
      public class Main {
      
          private static final DateTimeFormatter INPUT_NON_STANDARD_FORMAT;
      
          static {
              INPUT_NON_STANDARD_FORMAT =
                      new DateTimeFormatterBuilder()
                              .parseCaseInsensitive()
                              .append(DateTimeFormatter.ISO_LOCAL_DATE)
                              .appendLiteral('T')
                              .appendValue(HOUR_OF_DAY, 2)
                              .appendLiteral(':')
                              .appendValue(MINUTE_OF_HOUR, 2)
                              .optionalStart()
                              .appendLiteral(':')
                              .appendValue(SECOND_OF_MINUTE, 2)
                              .optionalStart()
                              .appendLiteral('.')
                              .appendValue(MILLI_OF_SECOND, 3)
                              .appendLiteral("+0000")
                              .toFormatter();
          }
      
          public static void main(String[] args) {
              String timestamp = "2020-12-03T05:35:59.398+0000";
              final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("YYYY-MM-dd HH:mm:ss");
              LocalDateTime localDateTime = LocalDateTime.parse(timestamp, INPUT_NON_STANDARD_FORMAT);
              System.out.println(localDateTime.format(dateTimeFormatter));
          }
      }
      

      输出

      2020-12-03 05:35:59
      

      【讨论】:

      • 注意格式模式字母的大小写。大写的YYYY 会给你带来新年的惊喜。
      猜你喜欢
      • 2019-11-09
      • 1970-01-01
      • 2016-10-02
      • 2022-11-16
      • 2019-07-08
      • 2020-07-09
      • 1970-01-01
      • 2017-07-09
      • 1970-01-01
      相关资源
      最近更新 更多