43

java.util.Date 方法以toString()本地时区显示日期。

有几种常见的场景,我们希望数据以UTC格式打印,包括日志、数据导出和与外部程序的通信。

  • java.util.Date在 UTC中创建字符串表示的最佳方法是什么?
  • 如何用更好的格式替换toString()无法排序的 juDate 格式(感谢@JonSkeet!)?

附录

我认为以自定义格式和时区打印日期的标准方法非常乏味:

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));

我一直在寻找像这样的单线:

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

7 回答 7

41
于 2013-12-12T18:32:14.593 回答
18

根据有用的评论,我已经完全重建了日期格式化程序。用法应该是:

  • 短(一个班轮)
  • 将一次性对象(时区、格式)表示为字符串
  • 支持有用的、可排序的 ISO 格式和开箱即用的旧格式

如果您认为此代码有用,我可能会在 github 上发布源代码和 JAR。

用法

// 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 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);
    }
}
于 2012-07-02T13:05:52.927 回答
8

以下简化的代码,基于上面接受的答案,对我有用:

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();
    }
}

我希望这对某人有所帮助。

于 2014-09-26T07:50:32.120 回答
3

java.time.Instant

只需使用Instant.java.time

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

这刚刚打印:

2018-01-27T09:35:23.179612Z

Instant.toString总是给出 UTC 时间。

输出通常是可排序的,但也有不幸的例外。toString为您提供足够的三位小数组来呈现它所拥有的精度。在我的 Mac 上的 Java 9 上,精度Instant.now()似乎是微秒,但我们应该预计,在大约千分之一的情况下,它会达到整数毫秒并且只打印三位小数。小数位数不相等的字符串将以错误的顺序排序(除非您编写自定义比较器来考虑这一点)。

Instant是现代 Java 日期和时间 API 中的类之一java.time,我强烈建议您使用它来代替过时的Date类。java.time内置于 Java 8 及更高版本,也已向后移植到 Java 6 和 7。

于 2018-01-27T09:41:34.127 回答
1

如果 XStream 是依赖项,请尝试:

new com.thoughtworks.xstream.converters.basic.DateConverter().toString(date)
于 2013-05-22T01:32:51.653 回答
0

好吧,如果您只想使用 java.util.Date ,可以使用以下小技巧:

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

于 2017-01-09T11:20:57.487 回答
-1

为什么不直接使用 java.text.SimpleDateFormat ?

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

或见: http ://www.tutorialspoint.com/java/java_date_time.htm

于 2013-11-19T14:33:17.987 回答