获得UTC当前时刻的ISO 8601格式表示的最优雅方法是什么?它应该看起来像:2010-10-12T08:50Z

示例:

String iso8601 = DateFormat.getDateTimeInstance(DateFormat.ISO_8601).format(date);


评论

svn.apache.org/repos/asf/commons/dormant/feedparser/trunk/src / ...

@marcolopes当心,使用私有静态SimpleDateFormat并不是线程安全的。

将符合ISO 8601的字符串转换为java.util.Date的可能重复项

与此其他问题类似,但一个问题将截短至整秒,而该问题将截断至整分钟。

#1 楼

使用SimpleDateFormat格式化所需的任何Date对象:

TimeZone tz = TimeZone.getTimeZone("UTC");
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'"); // Quoted "Z" to indicate UTC, no timezone offset
df.setTimeZone(tz);
String nowAsISO = df.format(new Date());


如上所示使用new Date()将格式化当前时间。

评论


@Joachim这种“标准”方法的缺点是,每次我需要ISO-8601格式的日期时,我的应用程序中都必须有许多“ yyyy-MM-dd'T'HH:mmZ”实例。如我所见,借助JodaTime,我可以使用预定义的格式化程序ISODateTimeFormat,它可以为我完成此工作。

–yegor256
2010-10-12 12:18

@ Joachim,Z是SimpleDateFormat中的有效模式,请执行以下操作:yyyy-MM-dd'T'HH:mm'Z'。

– Buhake Sindi
10-10-12在12:43

-1这将为您提供当前时区中的日期/时间,而不是UTC。卡洛斯的答案包括必要的UTC代码。

–斯科特·里皮(Scott Rippey)
2012年3月30日16:15

我只是解决了时区错误-因为这是公认的答案,所以我认为这是正确的做法。

– BoD
13年8月16日在22:22

Z的引用必须像“ yyyy-MM-dd'T'HH:mm'Z'”

–Kimball Robinson
15年10月13日在22:26

#2 楼

对于默认时区不是UTC的系统:如果经常需要,可以将SimpleDateFormat实例声明为全局常量,但请注意,此类不是线程-安全。如果由多个线程同时访问,则必须同步。

编辑:如果要进行许多不同的“时间/日期”操作,我希望使用乔达时间...
编辑2:已更正:setTimeZone不接受字符串(由保罗更正)

评论


在某些内置库中,这种格式不是恒定的吗?

–丹尼尔·卡普兰(Daniel Kaplan)
2014年6月10日22:44

“ DateFormat”有两个不同的包,请记住使用“ import java.text.DateFormat”

–oabarca
2014年6月24日19:12

如果要当前时区,请使用TimeZone tz = TimeZone.getDefault();。代替

–oabarca
2014年6月24日19:15

您不应该在格式中引用“ Z”,因为这在逻辑上不重要。如果如上例中的TimeZone为UTC,则未加引号的Z将仅在输出中导致Z ...但是,如果TimeZone不是UTC,则当时间可能不为Z时,Z仍将输出为字面值表示UTC是。如果使用方系统将Z读取为UTC,但时间不是,则时间将转移。相反,如果解析器使用带引号的Z而不设置TimeZone,它将解析UTC时间为本地时间(再次移位)。如果设置了TZ,则不需要此引号,但如果未设置,则很危险。

–马特·惠普尔
16年6月13日在18:50

@MattWhipple-但是,如果使用不带引号的Z,则结果将类似于2016-06-14T13:56 + 0000-问题是询问诸如2016-06-14T13:56Z

–user85421
16年6月14日14:00

#3 楼

Java 8 Native

java.time自Java 8起变得简单,而且线程安全。

br />
您可能会喜欢使用较轻的2015-04-14T11:07:36.639Z,例如TemporalInstant
,但是它们缺乏格式器支持或时区数据。
只有LocalDateTime可以直接使用。 >

通过调整或链接ZonedDateTime和DateTimeFormatter的选项/操作,可以在一定程度上轻松地控制时区和精度:

ZonedDateTime.now( ZoneOffset.UTC ).format( DateTimeFormatter.ISO_INSTANT )


结果:ZonedDateTime

仍必须通过自定义格式或自定义后期处理来满足已删除的要求,例如删除秒部分。 br />
对于Java 6和7,您可以考虑java.time的反向端口,例如ThreeTen-Backport,它也具有Android端口。乔达的经历-特别是。考虑到java.time是由Joda的作者设计的。


评论


好答案。请注意,明确指定时区而不是隐式依赖JVM当前的默认时区是一个好习惯。如果需要,可以指定一个特定的时区,例如ZoneId.of(“ America / Montreal”)。

–罗勒·布尔克
16-2-17在21:51



Instant只需调用.toString()方法即可将其格式化为ISO 8601格式:return DateTimeFormatter.ISO_INSTANT.format(this);

–VadymVL
17年7月7日14:39



这是最好的,因为您避免使用默认值。

–克里斯托弗·鲁西(Christophe Roussy)
18年4月3日在12:18

警告:使用ISO_INSTANT的Java 8解决方案有一个令人讨厌的怪癖。当毫秒恰好为0时,它们不包含在输出中。根据ISO 8601标准,这是允许的,但是许多其他语言的库和解析器并不那么宽容。如果有必要始终包含零,请改用它:DateTimeFormatter ISO_8601 = ofPattern(“ yyyy-MM-dd'T'HH:mm:ss.SSSX”)。withZone(UTC);

–于尔根
18年7月24日在20:57



从Java 8切换到11之后,我看到DateTimeFormatter.ISO_INSTANT和DateTimeFormatter.ISO_DATE_TIME在秒后使用6位数字,而不是3,Spring的@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)不再使用3位数字。

–DanielM
20-1-23在11:29

#4 楼

Java 8:

thisMoment = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mmX")
                              .withZone(ZoneOffset.UTC)
                              .format(Instant.now());



Java 8之前的版本:

thisMoment = String.format("%tFT%<tRZ",
                           Calendar.getInstance(TimeZone.getTimeZone("Z")));


来自文档:


'R' 24小时制的时间格式为“%tH:%tM” 'F' ISO 8601完整日期格式为“%tY-%tm-%td”。


评论


好吧,要么您包括一个额外的第三方库作为您项目的依赖项(您可能希望保持最新状态,并随您的应用程序一起交付,嘿,它只是一个额外的3.2 MB),然后执行DateTime dt = new DateTime (); DateTimeFormatter fmt = ISODateTimeFormat.dateTime();字符串str = fmt.print(dt);,或者您封装返回String.format(“%tFT%
–aioobe
10-10-12在12:36



%tFT%
–帕特里克·林斯基(Patrick Linskey)
2012年8月5日,下午1:21

一个非常简洁的解决方案,应该是现在已经被接受的答案:)

–阿卜杜勒·哈迪(AbdelHady)
14年8月21日在16:28

@PatrickLinskey有一个有用的注释,用于将秒和毫秒添加到输出中,但是毫秒模式的错误很小。 Z应该在毫秒后出现,例如%tFT%
– sho222
2014年10月3日20:55

DateTimeFormatter具有常数ISO_DATE_TIME以获取ISO-8601日期格式器,而不是自己显式编写模式。

–nickb
17年1月2日在20:45

#5 楼

从Java 8开始,您只需执行以下操作即可:

Instant.now().toString();


java.time.Instant文档: />
public static Instant now()

从系统时钟获取当前时刻。

这将查询系统UTC时钟以获取当前时刻。





toString


public String toString()

使用ISO-表示此瞬时的字符串8601表示形式。

使用的格式与DateTimeFormatter.ISO_INSTANT相同。


评论


这是正确的答案,而且在所有这些炮制的SimpleDateFormats上,它都没有得到更高的评价,这是一个丑闻。

– David Moles
18年5月7日在15:27

很高兴我阅读了更多答案。我同意,这应该是现在的答案。

– Xan-Kun Clark-Davis
20年1月27日在16:01

而且因为它是toString,所以在很多情况下,您甚至不需要显式调用它。

–kaya3
20-2-25在22:49

警告:在前面的答案中,警告也适用于此:“警告:使用ISO_INSTANT的Java 8解决方案有一个令人讨厌的怪癖。当毫秒为0时,它们不包含在输出中。根据ISO 8601,这是允许的标准,但许多其他语言的库和解析器并不那么宽容。”

–戴夫L。
20-2-26在20:09

#6 楼

使用JodaTime


ISO 8601日历系统是Joda-Time中的默认实现


这里是JodaTime Formatter的文档

编辑:

如果不想添加或看不到添加上述库的价值,则可以在内置的SimpleDateFormat类中使用,以将Date格式化为所需的ISO格式

@Joachim Sauer建议

DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mmZ");
String nowAsString = df.format(new Date());


评论


您将如何生成问题所示格式的String?

–约阿希姆·绍尔(Joachim Sauer)
10-10-12在12:12

我想说的是,不要为这样简单的事情添加库依赖(可以通过两行Java代码来实现)。 (当然,如果需求增加,那就另当别论了。)

– aioobe
2010-10-12 12:14



@aioobe,如果它只是在应用程序的多个部分中使用,则可以默认使用,在其他情况下,jodatime更好。

– jmj
10-10-12在12:15

@aioobe jodatime在任何情况下都更好,因为它具有ISODateTimeFormat-ISO-8601的预定义格式化程序。

–yegor256
10-10-12在12:19

@ org.life.java:仅当您可以正确切换到Jode时间时才有意义。仅使用Joda time的此功能时,您将没有它们。

– Joachim Sauer
2010-10-12 13:29

#7 楼

Apache commons-lang3的DateFormatUtils具有有用的常量,例如:DateFormatUtils.ISO_DATETIME_FORMAT

评论


更准确地说,当前时间是UTC:DateFormatUtils.format(new Date(),“ yyyy-MM-dd'T'HH:mm'Z'”,TimeZone.getTimeZone(“ UTC”)));默认时区中的当前时刻:DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.format(new Date()); @ yegor256感谢您提到DateFormatUtils,在apache commons-lang上有必要使用日期格式。

– babinik
2013年9月18日13:40

#8 楼

如果您不想包括Jodatime(非常好)

javax.xml.bind.DatatypeConverter.printDateTime(
    Calendar.getInstance(TimeZone.getTimeZone("UTC"))
);


它返回以下字符串: />
,它与原始请求略有不同,但仍为ISO-8601。

#9 楼

ISO 8601可能包含秒数
请参见http://en.wikipedia.org/wiki/ISO_8601#Times

,因此代码应为

DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");


#10 楼

Joda-Time

更新:Joda-Time项目现在处于维护模式,团队建议迁移到java.time类。对于Java 6和7,请参见ThreeTen-Backport项目,该项目在ThreeTenABP项目中进一步适用于Android。

使用Joda-Time库…

String output = new DateTime( DateTimeZone.UTC ).toString() ;


这是线程安全的。 Joda-Time会创建新的不可变对象,而不是更改现有对象。

如果您真正想要的是不带秒数的格式,可以解析为分钟,那么请使用Joda中许多其他内置的格式器之一-Time。

DateTime now = new DateTime( DateTimeZone.UTC ) ;
String output = ISODateTimeFormat.dateHourMinute.print( now ) ;


java.time

对于Java 8和更高版本,Joda-Time继续工作。但是内置的java.time框架取代了Joda-Time。因此,您可以方便地将代码从Joda-Time迁移到java.time。

关于现代解决方案,请参见我的其他答案。 time


java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧的旧式日期时间类,例如java.util.DateCalendarSimpleDateFormat。 />
要了解更多信息,请参见Oracle教程。并在Stack Overflow中搜索许多示例和说明。规范是JSR310。

您可以直接与数据库交换java.time对象。使用与JDBC 4.2或更高版本兼容的JDBC驱动程序。不需要字符串,不需要java.sql.*类。

从哪里获取java.time类?



Java SE 8,Java SE 9,Java SE 10及更高版本


内置。
具有捆绑实现的标准Java API的一部分。
Java 9增加了一些次要功能和修复。



Java SE 6和Java SE 7


java.time的许多功能在ThreeTen-Backport中都反向移植到Java 6和7。 Android


较新版本的java.time类的Android捆绑实现。
对于较早的Android(<26),ThreeTenABP项目改编了ThreeTen-Backport(如上所述)。请参见如何使用ThreeTenABP…。



ThreeTen-Extra项目使用其他类扩展了java.time。该项目是将来可能向java.time添加内容的试验场。您可能会在这里找到一些有用的类,例如IntervalYearWeekYearQuarter等。

#11 楼

对于Java版本7

,您可以遵循Oracle文档:
http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html

X-用于ISO 8601时区

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

System.out.println(nowAsISO);

DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
//nowAsISO = "2013-05-31T00:00:00Z";
Date finalResult = df1.parse(nowAsISO);

System.out.println(finalResult);


#12 楼

tl; dr

其他一些答案在推荐java.time类时是正确的,但是为了满足您的特定需求而使用不必要的长度。

/>
2018-01-23T12:34Z


Instant::toString

jav.time.Instant类表示UTC中的时刻,始终表示UTC。

Instant.now()                               // Capture the current moment in UTC with a resolution as fines nanoseconds but usually in microseconds or milliseconds.
       .truncatedTo( ChronoUnit.MINUTES )   // Lop off any seconds or fractional second, to get a value in whole minutes.
       .toString()                          // Generate a String in standard ISO 8601 format where a `T` separates the year-month-day from the hour-minute-second, and the `Z` on the end for “Zulu” means UTC.



Instant.toString():2018-01-23T12:34:56.123456Z


示例字符串Z末尾的2010-10-12T08:50Z发音为“ Zulu”,表示UTC。

您所需的格式恰好符​​合ISO 8601标准。解析/生成字符串时,java.time类默认使用这些标准格式。因此,无需指定格式化模式。只需如上所述拨打Instant::toString

如果您特别希望整分钟都没有秒或小数秒,则将其截断。通过ChronoUnit类指定时间单位。

Instant instant = Instant.now() ;



关于java.time



java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧的旧式日期时间类,例如java.util.DateCalendarSimpleDateFormat。 />
要了解更多信息,请参见Oracle教程。并在Stack Overflow中搜索许多示例和说明。规范是JSR310。

您可以直接与数据库交换java.time对象。使用与JDBC 4.2或更高版本兼容的JDBC驱动程序。不需要字符串,不需要java.sql.*类。

从哪里获取java.time类?



Java SE 8,Java SE 9,Java SE 10及更高版本


内置。
具有捆绑实现的标准Java API的一部分。
Java 9增加了一些次要功能和修复。



Java SE 6和Java SE 7


很多Java.time功能在ThreeTen-Backport中都已反向移植到Java 6和7。较新版本的java.time类的Android捆绑实现。
对于较早的Android(<26),ThreeTenABP项目改编了ThreeTen-Backport(如上所述)。请参见如何使用ThreeTenABP…。



ThreeTen-Extra项目使用其他类扩展了java.time。该项目是将来可能向java.time添加内容的试验场。您可能会在这里找到一些有用的类,例如IntervalYearWeekYearQuarter等。

#13 楼

您可以将Java的SimpleDateFormat与ISO 8601的以下模式yyyy-MM-dd'T'HH:mm:ssXXX一起使用。


示例代码:(列出所有可用时区)


for (String timeZone : TimeZone.getAvailableIDs())
{
    DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
    dateFormat.setTimeZone(TimeZone.getTimeZone(timeZone));
    String formatted = dateFormat.format(new Date());
    System.out.print(formatted);

    if (formatted.endsWith("Z"))
    {
        // These time zone's have offset of '0' from GMT.
        System.out.print("\t(" + timeZone + ")");
    }

    System.out.println();
}


您可以使用:


TimeZone.getDefault()



作为默认的vm时区。在此处更多信息

您可能会注意到几个以'Z'结尾的时区的日期时间。这些时区与格林尼治标准时间的偏差为'0'

更多信息可在此处找到。

#14 楼

我确实认为最简单的方法是先进入即时模式,然后再输入类似字符串:
br />

评论


如果您需要当前时间,则无需遍历老式的Date对象。只需执行Instant.now()。toString()。如果您是从旧版API获取日期,则您的方法是最好的方法。

– Ole V.V.
17年11月15日在11:45

作为Ole V.V.注释说,麻烦的旧日期时间类(例如java.util.Date,java.util.Calendar和java.text.SimpleDateFormat)现在已成为旧版,由Java 8和更高版本中内置的java.time类取代。请参见Oracle教程。

–罗勒·布尔克
18年4月10日在20:29

#15 楼

这是一个经过优化的整个类,因此,调用“ now()”不会做它必须做的其他事情。


评论


将其设置为静态可能会引起麻烦,因为SimpleDateFormat并非线程安全的:“日期格式不同步。建议为每个线程创建单独的格式实例。如果多个线程同时访问一种格式,则必须在外部进行同步。” docs.oracle.com/javase/7/docs/api/java/text / ...

– JuhaPalomäki
13年2月7日在21:10

正如@JuhaPalomäki所说,这不是线程安全的。如果您使用的是Java 8或更高版本,则ThreadLocal.withInitial可以解决此问题。如果您使用的是Java 7或更低版​​本,请创建一个新的ThreadLocal并通过覆盖ThreadLocal.initialValue提供一个初始值

–马特·斯加拉塔(Matt Sgarlata)
2014-10-16 15:43



@ user393274-如果您使用的是Java 8,则应使用Instant,DateTimeFormat和其他现代线程安全替代品

–user177800
17年9月5日在18:08

我对SimpleDateFormat的问题是不是线程安全的感到困惑。如果两个线程同时执行静态初始化程序,那么我看不到发生什么比SimpleDateFormat构造函数被调用两次,但只有其中一个瞬间(最后一个完成)记录为“ df”的情况更糟了。

– gilbertpilz
18年2月7日在3:09

#16 楼

private static String getCurrentDateIso()
{
    // Returns the current date with the same format as Javascript's new Date().toJSON(), ISO 8601
    DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
    dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
    return dateFormat.format(new Date());
}


#17 楼

如果您关心性能,则可以创建一个在处理ISO8601格式日期方面优于标准Java解析器和格式化程序的库。 DatetimeProcessor实现是线程安全的,可以缓存在并发映射或静态字段中。

 <dependency>
  <groupId>com.axibase</groupId>
  <artifactId>date-processor</artifactId>
  <version>1.0.3</version>
</dependency>
 


 import com.axibase.date.DatetimeProcessor;
import com.axibase.date.PatternResolver;
import org.junit.Before;
import org.junit.Test;

import java.time.Clock;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;

public class DateFormatTest {
    private Clock clock;

    @Before
    public void prepare() {
        clock = Clock.fixed(Instant.ofEpochMilli(1571285405300L), ZoneId.of("Europe/Berlin"));
    }

    @Test
    public void testIsoMillis(){
        final DatetimeProcessor formatter = PatternResolver.createNewFormatter("iso");
        assertThat(formatter.print(clock.millis(), ZoneOffset.UTC), is("2019-10-17T04:10:05.300Z"));
    }

    @Test
    public void testIsoMillisLocalZone(){
        final DatetimeProcessor formatter = PatternResolver.createNewFormatter("iso");
        assertThat(formatter.print(clock.millis(), clock.getZone()), is("2019-10-17T06:10:05.300+02:00"));
    }

    @Test
    public void testIsoMinutes(){
        final DatetimeProcessor formatter = PatternResolver.createNewFormatter("yyyy-MM-ddTHH:mmXXX");
        assertThat(formatter.print(clock.millis(), ZoneOffset.UTC), is("2019-10-17T04:10Z"));
    }
}

 


#18 楼

尽管如此,joda-time仅支持扩展格式:
“ 2015-12-09T00:22:42.930Z”
不支持基本格式:
“ 20151209T002242.930Z”
。 ..我们最好用java SimpleDateFormat测试格式列表。

#19 楼

我在Android中使用Calendar和SimpleDateFormat做到了。以下方法返回带有“ GMT”时区的日历(这是世界时区)。然后,您可以使用Calendar类使用Calendar类的setTimeZone()方法设置不同时区之间的小时。

private static final String GMT = "GMT";
private static final String DATE_FORMAT_ISO = "yyyyMMdd'T'HHmmss";

public static Calendar isoToCalendar(final String inputDate) {
    Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone(GMT));
    try {
        SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT_ISO, Locale.US);
        dateFormat.setTimeZone(TimeZone.getTimeZone(GMT));
        Date date = dateFormat.parse(inputDate);
        calendar.setTime(date);
    } catch (ParseException e) {
        Log.e("TAG",e.getMessage());
    }
    return calendar;
}


记住:
Date类不知道TimeZone的存在。因此,如果调试一个日期,则始终会看到当前时区的日期。

#20 楼

他们应该添加从日期到即时的某种简单方法,以及一种称为toISO8601的方法,这是很多人正在寻找的方法。符合ISO 8601格式的日期:

Instant.ofEpochMilli(date.getTime()).toString();


使用自动完成功能时,它不是真正可见的,但:
java.time.Instant.toString(): br />使用ISO-8601的此瞬间的字符串表示形式


#21 楼

DateTimeFormatter.ISO_DATE_TIME
        .withZone(ZoneOffset.UTC)
        .format(yourDateObject.toInstant())


评论


尽管此代码可以回答问题,但提供有关此代码为何和/或如何回答问题的其他上下文,可以提高其长期价值。

– Vishal Chhodwani
18年4月27日在5:13

#22 楼

试试这个,

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSSSZ");
        String date=sdf.format (new Date() );


用于ISO 8601格式

评论


这将使用错误时区中的日期,请参见Carlos的答案。

– Stian Soiland-Reyes
13年3月25日在15:31