5

我将SimpleDateFormat对象与对象一起使用Date,如下所示。问题在于Date对象显示了错误的日期,与原始字符串相差几分钟。该Date对象似乎以总毫秒数存储调试器中的时间。

关于这个问题的任何想法?

import java.text.SimpleDateFormat;

import java.util.Date;

Date played_at_local; 

dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSSSSSZ");

played_at_local = dateFormat.parse("2011-04-11T22:27:18.491726-05:00"); 

//played_at_local shows "Mon Apr 11 22:35:29 America/Chicago 2011" in debugger
4

7 回答 7

15

尝试从格式字符串中删除小数秒。我刚刚遇到了同样的问题,但格式略有不同。我的输入格式不是 ISO 格式(没有“T”,也没有“Z”),但症状是一样的——时间相差了一些随机的分钟和秒数,但其他一切都很好。这是我的日志结果的样子:

使用小数秒格式时:

SimpleDateFormat dateFormater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS");

# Parsed date: 2011-05-27 17:11:15.271816 => Fri May 27 17:15:46 EDT 2011
# Parsed date: 2011-05-27 17:09:37.750343 => Fri May 27 17:22:07 EDT 2011
# Parsed date: 2011-05-27 17:05:55.182921 => Fri May 27 17:08:57 EDT 2011
# Parsed date: 2011-05-27 16:55:05.69092 => Fri May 27 16:56:14 EDT 2011
# Parsed date: 2011-05-27 16:38:35.50348 => Fri May 27 16:39:25 EDT 2011

我通过从格式中删除小数秒来修复它。

SimpleDateFormat dateFormater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

# Parsed date: 2011-05-27 17:11:15.271816 => Fri May 27 17:11:15 EDT 2011
# Parsed date: 2011-05-27 17:09:37.750343 => Fri May 27 17:09:37 EDT 2011
# Parsed date: 2011-05-27 17:05:55.182921 => Fri May 27 17:05:55 EDT 2011
# Parsed date: 2011-05-27 16:55:05.69092 => Fri May 27 16:55:05 EDT 2011
# Parsed date: 2011-05-27 16:38:35.50348 => Fri May 27 16:38:35 EDT 2011

我认为正在发生的是输入字符串的“小数秒”部分太长(在 OP 示例中也是如此)。它似乎只期望小数点后三位。如果您进行数学运算(以第一个示例为例):

  • 小数秒 = 0.271816 秒
  • DateFormat 看到的是271816 / 1000一秒钟
  • 271816 / 1000 == 271 秒
  • 271 / 60 = 4 分钟
  • 271 % 60 = 31 秒
  • 17:11:15 到 17:15:46 正好是 4 分 31 秒
于 2011-05-27T21:25:54.873 回答
1

试试这个,为我工作Z应该在日期中使用,或者从格式字符串中删除

SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSSSSS'Z'");

played_at_local = dateFormat.parse("2011-04-11T22:27:18.491726Z-05:00");
于 2011-04-12T14:19:33.610 回答
1

您的代码中存在三个主要问题:

  1. 您已经使用.SSSSSS了几分之一秒,而SimpleDateFormat不支持超过毫秒 ( .SSS) 的精度。这也意味着您需要将几分之一秒的数字限制为三个。
  2. 您已经习惯于Z解析时区偏移量,-05:00正确的模式XXX.
  3. 您已经使用hh了 24 小时格式的时间,而正确的模式是HH. 该符号hh用于 12 小时制(即上午/下午)格式的时间。

除此之外,我建议您始终使用Locale日期解析/格式化 API,因为日期时间字符串的某些部分在不同Locale的 s 中以不同的方式表示。

演示:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

public class Main {
    public static void main(String[] args) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ENGLISH);
        Date date = sdf.parse("2011-04-11T22:27:18.491-05:00");

        // Print the default string i.e. Date#toString
        System.out.println(date);

        // Print the date-time in a custom format
        sdf.setTimeZone(TimeZone.getTimeZone("GMT-05:00"));
        System.out.println(sdf.format(date));
    }
}

输出:

Tue Apr 12 04:27:18 BST 2011
2011-04-11T22:27:18.491-05:00

关于遗留日期时间 API 的一些事实:

  1. java.util.Date对象不是像现代日期时间类型那样的真实日期时间对象;相反,它表示自称为“纪元” January 1, 1970, 00:00:00 GMT(或 UTC)的标准基准时间以来的毫秒数。当您打印 的对象时java.util.Date,其toString方法会返回 JVM 时区中的日期时间,根据此毫秒值计算得出。如果您需要在不同的时区打印日期时间,则需要将时区设置为SimpleDateFormat并从中获取格式化字符串。
  2. java.util日期时间 API 及其格式化 API已SimpleDateFormat过时且容易出错。建议完全停止使用它们并切换到现代日期时间 API *

使用现代日期时间 API:

import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;

public class Main {
    public static void main(String[] args) {
        OffsetDateTime odt = OffsetDateTime.parse("2011-04-11T22:27:18.491726-05:00");

        // Print the default string i.e. OffsetDateTime#toString
        System.out.println(odt);

        // Print the date-time in a custom format. Note: OffsetDateTime#toString drops
        // seconds if it is zero
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSSSSXXX");
        System.out.println(dtf.format(odt));
    }
}

输出:

2011-04-11T22:27:18.491726-05:00
2011-04-11T22:27:18.491726-05:00

注意:对于DateTimeFormatter,符号,u表示年份,而符号,y表示年代。在 [AD][2] 时代,这一年没有任何区别,但在 BC 时代,这一年很重要。检查此答案以了解更多信息。

从Trail: Date Time了解有关现代日期时间 API 的更多信息。


* 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,则可以使用ThreeTen-Backport,它将大部分java.time功能向后移植到 Java 6 和 7。如果您正在为 Android 项目和 Android API 工作level 仍然不符合 Java-8,请检查Java 8+ APIs available through desugaringHow to use ThreeTenABP in Android Project

于 2021-03-27T10:43:40.093 回答
0

你可以试试这个方法: http://docs.oracle.com/javase/6/docs/api/java/sql/Timestamp.html#valueOf(java.lang.String)

关键是小数位是可选的,您可以使用可变数量的小数位。但是,这似乎没有考虑时区。

从文档:

valueOf

public static Timestamp valueOf(String s)
Converts a String object in JDBC timestamp escape format to a Timestamp value.
Parameters:
s - timestamp in format yyyy-mm-dd hh:mm:ss[.f...]. The fractional seconds may be omitted.
Returns:
corresponding Timestamp value
Throws:
IllegalArgumentException - if the given argument does not have the format yyyy-mm-dd hh:mm:ss[.f...]
于 2013-02-28T07:04:26.630 回答
0

05:00 -->> 0500

hh --> HH // error not because of this ,but date is in 24hr format.

played_at_local = dateFormat.parse("2011-04-11T22:27:18.491726-05:00"); 

应该

played_at_local = dateFormat.parse("2011-04-11T22:27:18.491726-0500"); 
于 2011-04-12T14:12:45.757 回答
0

尝试这个 :

dTime  =  new  SimpleDateFormat("HH:mm:ss:SS");
String  sTime =  (dTime.format(new java.util.Date())).toString();

希望这有帮助

于 2014-11-28T10:48:31.450 回答
0

java.time 和 ThreeTenABP

无法SimpleDateFormat正确解析您的日期时间字符串。另一方面,现代 Java 日期和时间 API java.time 支持开箱即用的格式。

import org.threeten.bp.OffsetDateTime;

    String dateTimeString = "2011-04-11T22:27:18.491726-05:00";
    OffsetDateTime playedAtLocal = OffsetDateTime.parse(dateTimeString);
    System.out.println("Parsed into " + playedAtLocal);

输出是:

解析为 2011-04-11T22:27:18.491726-05:00

SimpleDateFormat仅支持毫秒,精确到秒的三位小数,不是两位,不是四位,不是六位(诚然,我不确定某些 Android 版本是否有SimpleDateFormat可以做得更好的版本,但您的问题表明您的版本不能)。SimpleDateFormat也是出了名的麻烦和过时,所以无论如何你都不想使用它。

java.time 使用起来要好得多。您注意到我们甚至不需要显式格式化程序,因此不需要编写格式模式字符串,这总是一个容易出错的任务。您的日期时间字符串采用 ISO 8601 格式,java.time 类将 ISO 8601 解析为其默认值。

问题:我可以在 Android 上使用 java.time 吗?

是的,java.time 在较旧和较新的 Android 设备上运行良好。它只需要至少Java 6

  • 在 Java 8 及更高版本以及更新的 Android 设备(从 API 级别 26 开始)中,现代 API 是内置的。
  • 在 Java 6 和 7 中获得 ThreeTen Backport,现代类的后向端口(ThreeTen 用于 JSR 310;请参阅底部的链接)。
  • 在(较旧的)Android 上使用 ThreeTen Backport 的 Android 版本。它被称为 ThreeTenABP。并确保从org.threeten.bp子包中导入日期和时间类。

链接

于 2019-09-05T07:11:20.683 回答