44

我想输出一个带有 PST 偏移量的时间戳(例如,2008-11-13T13:23:30-08:00)。java.util.SimpleDateFormat似乎没有以小时:分钟格式输出时区偏移量,它不包括冒号。有没有一种简单的方法可以在 Java 中获取该时间戳?

// I want 2008-11-13T12:23:30-08:00
String timestamp = new SimpleDateFormat("yyyy-MM-dd'T'h:m:ssZ").format(new Date());
System.out.println(timestamp); 
// prints "2008-11-13T12:23:30-0800" See the difference?

此外,SimpleDateFormat无法正确解析上面的示例。它抛出一个ParseException.

// Throws a ParseException
new SimpleDateFormat("yyyy-MM-dd'T'h:m:ssZ").parse("2008-11-13T13:23:30-08:00")
4

12 回答 12

55

从 Java 7 开始,就有X了 ISO8601 时区的模式字符串。对于您描述的格式的字符串,请使用XXX. 请参阅文档

样本:

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

结果:

2014-03-31T14:11:29+02:00
于 2014-03-31T12:12:51.853 回答
19

查看Joda Time包。它们使 RFC 3339 日期格式更容易。

乔达示例:

DateTime dt = new DateTime(2011,1,2,12,45,0,0, DateTimeZone.UTC);
DateTimeFormatter fmt = ISODateTimeFormat.dateTime();
String outRfc = fmt.print(dt);
于 2008-11-14T12:28:31.857 回答
15

从“完成部门”开始,一种解决方案是在 SimpleDateFormat 完成后使用正则表达式来修复字符串。Perl 中的类似 s/(\d{2})(\d{2})$/$1:$2/ 的东西。

如果您甚至对此感兴趣,我将使用有效的 Java 代码编辑此响应。

但是,是的。我也遇到了这个问题。RFC3339,我在看着你!

编辑:

这对我有用

// As a private class member
private SimpleDateFormat rfc3339 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");

String toRFC3339(Date d)
{
   return rfc3339.format(d).replaceAll("(\\d\\d)(\\d\\d)$", "$1:$2");
}
于 2012-07-16T19:29:47.913 回答
15

我花了很多时间寻找同一问题的答案,我在这里找到了一些东西:http: //developer.android.com/reference/java/text/SimpleDateFormat.html

建议答案:

String timestamp = new SimpleDateFormat("yyyy-MM-dd'T'h:m:ssZZZZZ").format(new Date());

如果您注意到我使用的是 5 'Z' 而不是 1。这会在偏移量中给出带有冒号的输出,如下所示:“2008-11-13T12:23:30-08:00”。希望能帮助到你。

于 2015-05-20T09:52:13.920 回答
4

问题是 Z 产生的时区偏移量没有冒号 (:) 作为分隔符。

于 2009-02-02T17:07:14.093 回答
3
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'h:m:ss.SZ");

不正是你需要的吗?

于 2008-11-14T05:39:25.553 回答
2

为此,我们可以简单地使用ZonedDateTime 类DateTimeFormatter 类

DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssxxx");
ZonedDateTime z2 = ZonedDateTime.now(ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS);
System.out.println("format =======> " + z2.format(format));

输出:格式 =======> 30-03-2020T05:57:37+00:00

于 2020-03-30T06:00:21.447 回答
1

我发现了一个帮助我解决问题的流浪 PasteBin:http: //pastebin.com/y3TCAikc

以防其内容稍后被删除:

// I want 2008-11-13T12:23:30-08:00
String timestamp = new SimpleDateFormat("yyyy-MM-dd'T'h:m:ssZ").format(new Date());
System.out.println(timestamp); 
// prints "2008-11-13T12:23:30-0800" See the difference?

// Throws a ParseException
new SimpleDateFormat("yyyy-MM-dd'T'h:m:ssZ").parse("2008-11-13T13:23:30-08:00")

SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'h:m:ss.SZ");
于 2012-08-15T02:10:59.603 回答
1

我为 RFC3339 创建了一个InternetDateFormat类。

但是源代码注释是日文的。

PS:我创建了英文版并进行了一些重构。

于 2013-05-17T00:57:55.370 回答
1

我尝试了这种格式并为我工作yyyy-MM-dd'T'HH:mm:ss'Z'

于 2021-06-10T15:11:50.233 回答
1

java.time

java.util日期时间 API 及其格式化 API已SimpleDateFormat过时且容易出错。建议完全停止使用它们并切换到现代 Date-Time API *

另外,下面引用的是来自Joda-Time主页的通知:

请注意,从 Java SE 8 开始,用户被要求迁移到 java.time (JSR-310) - JDK 的核心部分,它取代了这个项目。

使用java.time现代日期时间 API 的解决方案:太平洋时区最大的城市是洛杉矶,其时区名称为America/Los_Angeles。使用ZoneId.of("America/Los_Angeles"),您可以创建一个实例, ZonedDateTime该实例旨在在DST转换时自动调整时区偏移。

如果您需要时区偏移量但不需要时区名称,您可以将 a 转换ZonedDateTimeOffsetDateTimeusing ZonedDateTime#toOffsetDateTime。的其他一些用途OffsetDateTime是创建具有固定时区偏移量的日期时间实例(例如Instant.now().atOffset(ZoneOffset.of("+05:30")),以及解析具有时区偏移量的日期时间字符串。

演示:

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;

public class Main {
    public static void main(String[] args) {
        ZoneId zoneIdLosAngeles = ZoneId.of("America/Los_Angeles");
        ZonedDateTime zdtNowLosAngeles = ZonedDateTime.now(zoneIdLosAngeles);
        System.out.println(zdtNowLosAngeles);

        // With zone offset but without time zone name
        OffsetDateTime odtNowLosAngeles = zdtNowLosAngeles.toOffsetDateTime();
        System.out.println(odtNowLosAngeles);

        // Truncated up to seconds
        odtNowLosAngeles = odtNowLosAngeles.truncatedTo(ChronoUnit.SECONDS);
        System.out.println(odtNowLosAngeles);

        // ################ A winter date-time ################
        ZonedDateTime zdtLosAngelesWinter = ZonedDateTime
                .of(LocalDateTime.of(LocalDate.of(2021, 11, 20), LocalTime.of(10, 20)), zoneIdLosAngeles);
        System.out.println(zdtLosAngelesWinter); // 2021-11-20T10:20-08:00[America/Los_Angeles]
        System.out.println(zdtLosAngelesWinter.toOffsetDateTime()); // 2021-11-20T10:20-08:00

        // ################ Parsing a date-time string with zone offset ################
        String strDateTime = "2008-11-13T13:23:30-08:00";
        OffsetDateTime odt = OffsetDateTime.parse(strDateTime);
        System.out.println(odt); // 2008-11-13T13:23:30-08:00
    }
}

示例运行的输出:

2021-07-18T03:27:15.578028-07:00[America/Los_Angeles]
2021-07-18T03:27:15.578028-07:00
2021-07-18T03:27:15-07:00
2021-11-20T10:20-08:00[America/Los_Angeles]
2021-11-20T10:20-08:00
2008-11-13T13:23:30-08:00

ONLINE DEMO

您一定已经注意到我没有使用 aDateTimeFormatter来解析您问题的日期时间字符串。这是因为您的日期时间字符串符合 ISO-8601 标准。现代日期时间 API 基于ISO 8601DateTimeFormatter ,只要日期时间字符串符合 ISO 8601 标准,就不需要明确使用对象。

从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-07-18T10:40:50.920 回答
0

我用这个测试了很多,对我来说效果很好......特别是在解析(以及格式化)方面,它是迄今为止我发现的最接近的

DateTimeFormatter rfc3339Formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;

DateTimeFormatter rfc3339Parser = new DateTimeFormatterBuilder()
    .parseCaseInsensitive()
    .appendValue(ChronoField.YEAR, 4)
    .appendLiteral('-')
    .appendValue(ChronoField.MONTH_OF_YEAR, 2)
    .appendLiteral('-')
    .appendValue(ChronoField.DAY_OF_MONTH, 2)
    .appendLiteral('T')
    .appendValue(ChronoField.HOUR_OF_DAY, 2)
    .appendLiteral(':')
    .appendValue(ChronoField.MINUTE_OF_HOUR, 2)
    .appendLiteral(':')
    .appendValue(ChronoField.SECOND_OF_MINUTE, 2)
    .optionalStart()
    .appendFraction(ChronoField.NANO_OF_SECOND, 2, 9, true) //2nd parameter: 2 for JRE (8, 11 LTS), 1 for JRE (17 LTS)
    .optionalEnd()
    .appendOffset("+HH:MM","Z")
    .toFormatter()
    .withResolverStyle(ResolverStyle.STRICT)
    .withChronology(IsoChronology.INSTANCE);

https://github.com/guyplusplus/RFC3339-DateTimeFormatter上的测试用例

于 2021-07-13T13:46:56.120 回答