简体   繁体   English

将 Java 日期转换为 UTC 字符串

[英]Convert Java Date to UTC String

The java.util.Date toString() method displays the date in the local time zone. java.util.Date toString()方法显示本地时区的日期。

There are several common scenarios where we want the data to be printed in UTC , including logs, data export and communication with external programs.有几种常见的场景我们希望数据以UTC打印,包括日志、数据导出和与外部程序通信。

  • What's the best way to create a String representation of java.util.Date in UTC?在 UTC 中创建java.util.Date的字符串表示形式的最佳方法是什么?
  • How to replace the juDate's toString() format, which isn't sortable (thanks, @JonSkeet?) with a better format?如何用更好的格式替换不可排序的 juDate 的toString()格式(感谢@JonSkeet?)?

Addendum附录

I think that the standard way of printing the date in a custom format and time zone is quite tedious:我认为以自定义格式和时区打印日期的标准方式非常乏味:

final Date date = new Date();
final String ISO_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS zzz";
final SimpleDateFormat sdf = new SimpleDateFormat(ISO_FORMAT);
final TimeZone utc = TimeZone.getTimeZone("UTC");
sdf.setTimeZone(utc);
System.out.println(sdf.format(date));

I was looking for a one-liner like:我一直在寻找像这样的单线:

System.out.println(prettyPrint(date, "yyyy-MM-dd'T'HH:mm:ss.SSS zzz", "UTC"));

tl;dr tl;博士

You asked:您询问:

I was looking for a one-liner like:我一直在寻找像这样的单线:

Ask and ye shall receive.祈求,你们就会得到。 Convert from terrible legacy class Date to its modern replacement, Instant .从糟糕的遗留类Date转换为现代替代类Instant

myJavaUtilDate.toInstant().toString()

2020-05-05T19:46:12.912Z 2020-05-05T19:46:12.912Z

java.time java.time

In Java 8 and later we have the new java.time package built in ( Tutorial ).在 Java 8 及更高版本中,我们内置了新的java.time 包教程)。 Inspired by Joda-Time, defined by JSR 310, and extended by the ThreeTen-Extra project.受 Joda-Time 的启发,由 JSR 310 定义,并由ThreeTen-Extra项目扩展。

The best solution is to sort your date-time objects rather than strings .最好的解决方案是对日期时间对象而不是字符串进行排序 But if you must work in strings, read on.但是,如果您必须使用字符串,请继续阅读。

An Instant represents a moment on the timeline, basically in UTC (see class doc for precise details). Instant代表时间轴上的一个时刻,基本上是UTC 时间(请参阅类文档了解详细信息)。 The toString implementation uses the DateTimeFormatter.ISO_INSTANT format by default. toString实现默认使用DateTimeFormatter.ISO_INSTANT格式。 This format includes zero, three, six or nine digits digits as needed to display fraction of a second up to nanosecond precision.此格式根据需要包括零、三、六或九位数字,以显示高达纳秒精度的秒分数。

String output = Instant.now().toString(); // Example: '2015-12-03T10:15:30.120Z'

If you must interoperate with the old Date class, convert to/from java.time via new methods added to the old classes.如果您必须与旧Date类进行互操作,请通过添加到旧类的新方法与 java.time 相互转换。 Example: Date::toInstant .示例: Date::toInstant

myJavaUtilDate.toInstant().toString()

You may want to use an alternate formatter if you need a consistent number of digits in the fractional second or if you need no fractional second.如果您需要一致的小数秒位数或者不需要小数秒,则可能需要使用备用格式化程序。

Another route if you want to truncate fractions of a second is to use ZonedDateTime instead of Instant , calling its method to change the fraction to zero .如果要截断秒的小数部分,另一种方法是使用ZonedDateTime而不是Instant ,调用其方法将小数部分更改为零

Note that we must specify a time zone for ZonedDateTime (thus the name).请注意,我们必须为ZonedDateTime (因此名称)指定一个时区。 In our case that means UTC.在我们的例子中,这意味着 UTC。 The subclass ofZoneID , ZoneOffset , holds a convenient constant for UTC . ZoneID的子类ZoneOffset拥有一个方便的 UTC 常量 If we omit the time zone, the JVM's current default time zone is implicitly applied.如果我们省略时区,则隐式应用 JVM 当前的默认时区

String output = ZonedDateTime.now( ZoneOffset.UTC ).withNano( 0 ).toString();  // Example: 2015-08-27T19:28:58Z

Java 中的日期时间类型表,包括现代的和传统的


About java.time关于java.time

The java.time framework is built into Java 8 and later. java.time框架内置于 Java 8 及更高版本中。 These classes supplant the troublesome old legacy date-time classes such as java.util.Date , Calendar , & SimpleDateFormat .这些类取代了麻烦的旧的遗留日期时间类,例如java.util.DateCalendarSimpleDateFormat

To learn more, see the Oracle Tutorial .要了解更多信息,请参阅Oracle 教程 And search Stack Overflow for many examples and explanations.并在 Stack Overflow 中搜索许多示例和解释。 Specification is JSR 310 .规范是JSR 310

The Joda-Time project, now in maintenance mode , advises migration to the java.time classes.现在处于维护模式Joda-Time项目建议迁移到java.time类。

You may exchange java.time objects directly with your database.您可以直接与数据库交换java.time对象。 Use a JDBC driver compliant with JDBC 4.2 or later.使用符合JDBC 4.2或更高版本的JDBC 驱动程序 No need for strings, no need for java.sql.* classes.不需要字符串,不需要java.sql.*类。 Hibernate 5 & JPA 2.2 support java.time . Hibernate 5 & JPA 2.2 支持java.time

Where to obtain the java.time classes?在哪里获取 java.time 类?


Joda-Time乔达时间

UPDATE: The Joda -Time project is now in maintenance mode, with the team advising migration to the java.time classes.更新: Joda -Time 项目现在处于维护模式,团队建议迁移到 java.time 类。

I was looking for a one-liner我一直在寻找单线

Easy if using the Joda-Time 2.3 library.如果使用Joda-Time 2.3 库,则很容易。 ISO 8601 is the default formatting. ISO 8601是默认格式。

Time Zone时区

In the code example below, note that I am specifying a time zone rather than depending on the default time zone.在下面的代码示例中,请注意我指定了一个时区,而不是依赖于默认时区。 In this case, I'm specifying UTC per your question.在这种情况下,我根据您的问题指定了UTC The Z on the end, spoken as "Zulu", means no time zone offset from UTC.末尾的Z ,读作“Zulu”,表示没有与 UTC 的时区偏移。

Example Code示例代码

// import org.joda.time.*;

String output = new DateTime( DateTimeZone.UTC );

Output…输出…

2013-12-12T18:29:50.588Z

Following the useful comments, I've completely rebuilt the date formatter.根据有用的评论,我已经完全重建了日期格式化程序。 Usage is supposed to:用法应该是:

  • Be short (one liner)要短(一个班轮)
  • Represent disposable objects (time zone, format) as Strings将一次性对象(时区、格式)表示为字符串
  • Support useful, sortable ISO formats and the legacy format from the box支持有用的、可排序的 ISO 格式和开箱即用的旧格式

If you consider this code useful, I may publish the source and a JAR in github.如果您认为此代码有用,我可能会在 github 中发布源代码和 JAR。

Usage用法

// The problem - not UTC
Date.toString()                      
"Tue Jul 03 14:54:24 IDT 2012"

// ISO format, now
PrettyDate.now()        
"2012-07-03T11:54:24.256 UTC"

// ISO format, specific date
PrettyDate.toString(new Date())         
"2012-07-03T11:54:24.256 UTC"

// Legacy format, specific date
PrettyDate.toLegacyString(new Date())   
"Tue Jul 03 11:54:24 UTC 2012"

// ISO, specific date and time zone
PrettyDate.toString(moonLandingDate, "yyyy-MM-dd hh:mm:ss zzz", "CST") 
"1969-07-20 03:17:40 CDT"

// Specific format and date
PrettyDate.toString(moonLandingDate, "yyyy-MM-dd")
"1969-07-20"

// ISO, specific date
PrettyDate.toString(moonLandingDate)
"1969-07-20T20:17:40.234 UTC"

// Legacy, specific date
PrettyDate.toLegacyString(moonLandingDate)
"Wed Jul 20 08:17:40 UTC 1969"

Code代码

(This code is also the subject of a question on Code Review stackexchange ) (此代码也是Code Review stackexchange 上的一个问题的主题)

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

/**
 * Formats dates to sortable UTC strings in compliance with ISO-8601.
 * 
 * @author Adam Matan <adam@matan.name>
 * @see http://stackoverflow.com/questions/11294307/convert-java-date-to-utc-string/11294308
 */
public class PrettyDate {
    public static String ISO_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS zzz";
    public static String LEGACY_FORMAT = "EEE MMM dd hh:mm:ss zzz yyyy";
    private static final TimeZone utc = TimeZone.getTimeZone("UTC");
    private static final SimpleDateFormat legacyFormatter = new SimpleDateFormat(LEGACY_FORMAT);
    private static final SimpleDateFormat isoFormatter = new SimpleDateFormat(ISO_FORMAT);
    static {
        legacyFormatter.setTimeZone(utc);
        isoFormatter.setTimeZone(utc);
    }

    /**
     * Formats the current time in a sortable ISO-8601 UTC format.
     * 
     * @return Current time in ISO-8601 format, e.g. :
     *         "2012-07-03T07:59:09.206 UTC"
     */
    public static String now() {
        return PrettyDate.toString(new Date());
    }

    /**
     * Formats a given date in a sortable ISO-8601 UTC format.
     * 
     * <pre>
     * <code>
     * final Calendar moonLandingCalendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
     * moonLandingCalendar.set(1969, 7, 20, 20, 18, 0);
     * final Date moonLandingDate = moonLandingCalendar.getTime();
     * System.out.println("UTCDate.toString moon:       " + PrettyDate.toString(moonLandingDate));
     * >>> UTCDate.toString moon:       1969-08-20T20:18:00.209 UTC
     * </code>
     * </pre>
     * 
     * @param date
     *            Valid Date object.
     * @return The given date in ISO-8601 format.
     * 
     */

    public static String toString(final Date date) {
        return isoFormatter.format(date);
    }

    /**
     * Formats a given date in the standard Java Date.toString(), using UTC
     * instead of locale time zone.
     * 
     * <pre>
     * <code>
     * System.out.println(UTCDate.toLegacyString(new Date()));
     * >>> "Tue Jul 03 07:33:57 UTC 2012"
     * </code>
     * </pre>
     * 
     * @param date
     *            Valid Date object.
     * @return The given date in Legacy Date.toString() format, e.g.
     *         "Tue Jul 03 09:34:17 IDT 2012"
     */
    public static String toLegacyString(final Date date) {
        return legacyFormatter.format(date);
    }

    /**
     * Formats a date in any given format at UTC.
     * 
     * <pre>
     * <code>
     * final Calendar moonLandingCalendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
     * moonLandingCalendar.set(1969, 7, 20, 20, 17, 40);
     * final Date moonLandingDate = moonLandingCalendar.getTime();
     * PrettyDate.toString(moonLandingDate, "yyyy-MM-dd")
     * >>> "1969-08-20"
     * </code>
     * </pre>
     * 
     * 
     * @param date
     *            Valid Date object.
     * @param format
     *            String representation of the format, e.g. "yyyy-MM-dd"
     * @return The given date formatted in the given format.
     */
    public static String toString(final Date date, final String format) {
        return toString(date, format, "UTC");
    }

    /**
     * Formats a date at any given format String, at any given Timezone String.
     * 
     * 
     * @param date
     *            Valid Date object
     * @param format
     *            String representation of the format, e.g. "yyyy-MM-dd HH:mm"
     * @param timezone
     *            String representation of the time zone, e.g. "CST"
     * @return The formatted date in the given time zone.
     */
    public static String toString(final Date date, final String format, final String timezone) {
        final TimeZone tz = TimeZone.getTimeZone(timezone);
        final SimpleDateFormat formatter = new SimpleDateFormat(format);
        formatter.setTimeZone(tz);
        return formatter.format(date);
    }
}

The following simplified code, based on the accepted answer above , worked for me:以下简化代码基于上面接受的答案,对我有用:

public class GetSync {
    public static String ISO_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS zzz";
    private static final TimeZone utc = TimeZone.getTimeZone("UTC");
    private static final SimpleDateFormat isoFormatter = new SimpleDateFormat(ISO_FORMAT);
    static {
        isoFormatter.setTimeZone(utc);
    }

    public static String now() {
        return isoFormatter.format(new Date()).toString();
    }
}

I hope this helps somebody.我希望这对某人有帮助。

java.time.Instant java.time.Instant

Just use Instant of java.time .只需使用Instantjava.time

    System.out.println(Instant.now());

This just printed:这只是打印:

2018-01-27T09:35:23.179612Z

Instant.toString always gives UTC time. Instant.toString始终提供 UTC 时间。

The output is usually sortable, but there are unfortunate exceptions.输出通常是可排序的,但也有不幸的例外。 toString gives you enough groups of three decimals to render the precision it holds. toString为您提供了足够多的三位小数来呈现它所拥有的精度。 On the Java 9 on my Mac the precision of Instant.now() seems to be microseconds, but we should expect that in approximately one case out of a thousand it will hit a whole number of milliseconds and print only three decimals.在我的 Mac 上的 Java 9 上, Instant.now()的精度似乎是微秒,但我们应该期望在千分之一的情况下它会达到整数毫秒并且只打印三位小数。 Strings with unequal numbers of decimals will be sorted in the wrong order (unless you write a custom comparator to take this into account).小数位数不相等的字符串将以错误的顺序排序(除非您编写自定义比较器来考虑这一点)。

Instant is one of the classes in java.time , the modern Java date and time API, which I warmly recommend that you use instead of the outdated Date class. Instant是现代 Java 日期和时间 API java.time中的类之一,我强烈建议您使用它来代替过时的Date类。 java.time is built into Java 8 and later and has also been backported to Java 6 and 7. java.time内置于 Java 8 及更高版本中,也已向后移植到 Java 6 和 7。

If XStream is a dependency, try:如果 XStream 是依赖项,请尝试:

new com.thoughtworks.xstream.converters.basic.DateConverter().toString(date)

Well if you want to use java.util.Date only, here is a small trick you can use:好吧,如果你只想使用 java.util.Date,这里有一个你可以使用的小技巧:

String dateString = Long.toString(Date.UTC(date.getYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds())); String dateString = Long.toString(Date.UTC(date.getYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds()));

Why not just use java.text.SimpleDateFormat?为什么不直接使用 java.text.SimpleDateFormat?

Date someDate = new Date();
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
String s = df.format(someDate);

Or see: http://www.tutorialspoint.com/java/java_date_time.htm或者查看: http ://www.tutorialspoint.com/java/java_date_time.htm

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM