【问题标题】:ISO 8601 datetime nowISO 8601 日期时间现在
【发布时间】:2016-03-10 07:30:05
【问题描述】:

我在 java 中需要的正是 C# 中的那种格式 DateTime.Now.ToString("o")DateTime.Now.ToString("o") 的样本返回日期为

2016-03-10T11:24:59.7862749+04:00

然后在 sql 中插入为

2016-03-10 11:24:59.786

我正在尝试从 java 插入相同的日期格式。我用那个:

TimeZone tz = TimeZone.getTimeZone("UTC");
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mmZ");
df.setTimeZone(tz);
String nowAsISO = df.format(new Date());

它会返回这个

2016-03-10T07:29+0000

由于这种格式,它会出错。如何将格式更改为我想要的格式?

【问题讨论】:

  • 为什么将 DateTime 作为字符串插入?只需将其插入并在需要表示时对其进行格式化?如果使用 Sql Server,datetimedatetime2 类型不保留偏移部分。您可能想改用 datetimeoffset 类型。而且您甚至都没有展示如何将此值插入数据库以及如何从中获取值。
  • @SonerGönül 这种格式在网络服务中。我不能改变它..我只是打电话给它,需要通过。没有它,服务会出现 500 错误
  • @GediminasMasaitis 因为我想在 java 中使用这种格式。我提到的代码是在java中!

标签: java c# date datetime


【解决方案1】:

Answer by Meno Hochschild 是正确的。我将添加更多的 cmets 和一些特定于 SQL 的代码。

避免使用旧的日期时间类

旧的日期时间类 java.util.Date/.Calendar 和 java.text.SimpleDateFormat 设计不佳、混乱且麻烦。避开他们。

旧的类已被 Java 8 及更高版本中内置的 java.time 框架所取代。

要在 Java 8 之前使用,请查看 ThreeTen-Backport 项目。

纳秒

java.time 类具有纳秒级分辨率。因此,您不会遇到由于旧类使用毫秒分辨率而导致2016-03-10T11:24:59.7862749+04:00 被截断为2016-03-10 11:24:59.786 的数据丢失问题。

由于遗留问题,在 Java 8 中获取当前时刻被限制为毫秒,即秒的小数部分的三位数字。 Java 9 将以纳秒为单位获取当前时刻,最多九位小数(假设您的计算机的硬件时钟可以提供如此精细的分辨率)。

ISO 8601

ISO 8601 标准为日期时间值定义了合理的文本格式。例如,2016-03-09T23:24:33Z2016-03-09T22:24:33-01:00。 java.time 类默认使用这些,因此无需定义解析模式。

即时

Instant 是 UTC 时间线上的一个时刻。

Instant instant = Instant.now();

调用Instant::toString 以生成标准格式的字符串。

String output = instant.toString();

2016-03-09T23:24:33.123Z

OffsetDateTime

申请ZoneOffset 以获得OffsetDateTime

ZoneOffset zoneOffset = ZoneOffset.ofHoursMinutes( -5 , 30 );
OffsetDateTime odt = OffsetDateTime.ofInstant( instant , zoneOffset );

ZonedDateTime

如果您知道完整时区而不仅仅是offset-from-UTC,请应用ZoneId 以获得ZonedDateTime

使用proper time zone names

ZoneId zoneId = ZoneId.of( "Asia/Kolkata" ); // "Europe/Paris", "America/Montreal", etc.
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );

java.sql.Timestamp

希望 JDBC 驱动程序将更新为直接使用 java.time 类型。在此之前,我们将转换为 java.sql 类型以将数据传入/传出数据库。

如上所述,java.time 可以处理纳秒。 java.sql.Timestamp 也是如此。但是您的数据库可能不会。某些数据库仅限于整秒、毫秒或微秒。当数据通过 JDBC 传递到数据库时,数据库可能会被截断。

java.sql.Timestamp ts = java.sql.Timestamp.from( instant );

……然后朝着另一个方向……

Instant instant = ts.toInstant();

请注意,根据定义,Instant 始终采用 UTC。所以不需要执行问题末尾尝试的那种代码。

工作流程

在处理日期时间时应尽量减少字符串的使用。最大限度地使用有用的日期时间类/对象,即 java.time 类。不要将字符串视为日期时间值——它们是日期时间值的文本表示

不要将日期时间值作为字符串插入/检索数据库。使用 java.sql 对象,例如 java.sql.Timestampjava.sql.Date。使用PreparedStatement 和“设置/获取”方法,例如setTimestamp/getTimestamp。并且在数据库中几乎 always define your columnsTIMESTAMP WITH TIME ZONE 而不是“没有时区”。

从数据库获取数据时,使用 java.sql 类型。但尽快转换为 java.time 类型。 java.sql 类型很乱,很脏,应该只用于数据传输而不是业务逻辑。

一般最好在您的业务逻辑、数据存储、数据交换、API 调用等中使用UTC。仅在用户期望或数据接收器需要时调整到时区。

【讨论】:

    【解决方案2】:

    对于 Java 7,您可以使用:

    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
    System.out.println(df.format(new Date()));
    

    这使用了模式符号 XXX,它也会在偏移量内打印冒号。但是,对于 Java-6,不提供此功能。而且精度总是被限制在毫秒以内。

    对于 Java-8,您还可以使用:

    DateTimeFormatter dtf = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
    System.out.println(OffsetDateTime.now().format(dtf)); // 2016-03-10T08:46:44.849+01:00
    

    如果这样的时钟可用(从 Java-9 开始),这将启用纳秒精度。

    对于 Java-6 应用基于 SimpleDateFormat 的 hack 或使用外部库:

    // Java-6 (SimpleDateFormat)
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
    String text = sdf.format(new Date());
    text = text.substring(0, text.length() - 2) + ":" + text.substring(text.length() - 2);
    System.out.println(text);
    
    // Joda-Time
    DateTime now = DateTime.now();
    System.out.println(DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZZ").print(now));
    
    // Time4J
    Moment now = SystemClock.currentMoment();
    System.out.println(Iso8601Format.EXTENDED_DATE_TIME_OFFSET.withStdTimezone().format(now));
    

    【讨论】:

    • @George 我不确定你为什么要省略偏移量(“没有 XXX”)。在这种情况下,您只是发送一个没有偏移信息的普通时间戳,指示您的本地时间。但即使 web 服务接受这种格式,它也可能有害,因为 web 服务在数据库层转换为 UTC 时可能会误解它。
    【解决方案3】:

    使用这种格式“yyyy-MM-dd'T'HH:mm:ss.SSSZ”

    示例:

    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
    
    System.out.println(df.format(new Date()));
    

    【讨论】:

    • 谢谢,但现在返回了2016-03-10T07:40:09.0619+0000,但它还是出错了..
    • http 500。它是关于日期格式的。当我以我提到的格式对其进行硬编码时,它工作得很好
    • 注意:四次使用“S”表示秒的分数肯定是错误的。
    猜你喜欢
    • 2010-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-18
    • 1970-01-01
    相关资源
    最近更新 更多