在Java中以UTC格式获取日期对象

48

我已经编写了以下代码。我想以UTC格式获取Date对象。

我能够使用SimpleDateFormat获得预期的UTC日期字符串。但是,使用相同的SimpleDateFormat对象,我无法获得UTC格式的对象。它返回带有IST格式的对象。

经过搜索,我发现Date对象不存储时间戳信息。

如何以UTC格式获取日期对象?

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

public class dddd {

    /**
     * @param args
     */
    public static void main(String[] args) {
        System.out.println("Input - "+1393572325000L);
        DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
        Date date= new Date(1393572325000L);  
        String dateString = formatter.format(date);

        System.out.println("Converted UTC TIME (using Format method) : "+dateString);

        Date date2 =null;
        try {
            date2 = formatter.parse(dateString);
        } catch (ParseException e) {
            e.printStackTrace();
        }


        System.out.println("Parsed Date Object (using Parse method) : "+date2);

        System.out.println("Expected Date Object : Fri Feb 28 07:25:25 UTC 2014");

    }

}

这将打印以下输出:

Input - 1393572325000
Converted UTC TIME (using Format method) : 2014-02-28 07:25:25
Parsed Date Object (using Parse method) : Fri Feb 28 12:55:25 IST 2014
Expected Date Object : Fri Feb 28 07:25:25 UTC 2014

1
Instant.now.toString() 简短而简单。 - arulraj.net
1
请注意,像java.util.Datejava.util.Calendarjava.text.SimpleDateFormat这样的旧日期时间类现在已经成为遗留系统,被内置于Java 8及更高版本中的java.time类所取代。请参阅Oracle的教程 - Basil Bourque
5个回答

85
final Date currentTime = new Date();
final SimpleDateFormat sdf = new SimpleDateFormat("EEE, MMM d, yyyy hh:mm:ss a z");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println("UTC time: " + sdf.format(currentTime));

2
我已经完成了这个。这将返回以字符串格式表示的日期,我正在获取它。我想要得到日期对象而不是字符串。 - Ninad Pingale
1
@user2745792,你说你想要获取一个“Date对象而不是字符串”。但是在你的main方法的第四行中,你已经得到了一个Date对象。 - Basil Bourque
1
FYI,像 java.util.Datejava.util.Calendarjava.text.SimpleDateFormat 等麻烦的老日期时间类现已成为遗留系统,被内置于Java 8及更高版本中的 java.time 类所替代。请参阅Oracle的教程 - Basil Bourque

23

日期本身没有时区信息。您所看到的只是使用 Date.toString() 方法格式化日期时,该方法会使用系统本地的时区来将无时区信息的日期转换为您可以理解的字符串。

如果您想使用UTC时区显示无时区信息日期的字符串,则需要使用带有UTC时区的SimpleDateFormat(就像您在问题中已经使用的那样)。

换句话说,时区不是日期的属性,而是用于将日期转换为字符串的格式的属性。


我正在以UTC格式获取日期字符串。那么没有办法获取UTC格式的日期对象吗? - Ninad Pingale
11
不。日期没有时区,也没有格式。日期只是一个包装在“long”中的东西,表示毫秒数。 - JB Nizet

18

简而言之

Instant.ofEpochMilli ( 1_393_572_325_000L )
       .toString()

2014年2月28日07:25:25 Z

详情

(a) 您似乎对日期的概念感到困惑。正如JB Nizet的回答所说,日期跟踪自Unix 纪元(1970年第一时刻)以来的毫秒数,在UTC时区(即没有时区偏移)。因此,日期没有时区。它也没有“格式”。我们从日期的值中创建字符串表示形式,但日期本身不是字符串,也没有字符串

(b)你提到了“UTC格式”。UTC不是我听说过的格式。协调世界时(UTC)是时区的起点。伦敦格林威治皇家天文台以东的时区比UTC快一些小时和分钟。向西的时区比UTC慢。

你似乎在提到ISO 8601格式化字符串。你使用了可选格式,省略了(1)中间的T和(2)最后的UTC偏移量。除非将字符串呈现给应用程序用户界面中的用户,否则建议您通常使用通常的格式:

  • 2014-02-27T23:03:14+05:30
  • 2014-02-27T23:03:14Z('Z'代表Zulu或UTC,带有+00:00的偏移量)
(c) 避免使用三或四个字母的时区代码,它们既不标准化也不唯一。例如,“IST”可以表示印度标准时间或爱尔兰标准时间。
(d) 在发帖前请尽力搜索StackOverflow,你会找到所有答案。
(e) 避免使用Java附带的java.util.Date & Calendar类,它们经常出现问题。使用Joda-Time库或Java 8的新java.time包(受Joda-Time启发,由JSR 310定义)。

java.time

Java.time类在解析和生成字符串时默认使用标准的ISO 8601格式。
OffsetDateTime odt = OffsetDateTime.parse( "2014-02-27T23:03:14+05:30" ); 
Instant instant = Instant.parse( "2014-02-27T23:03:14Z" );

将您从1970年第一时刻起的毫秒计数解析为UTC时间。
Instant instant = Instant.ofEpochMilli ( 1_393_572_325_000L );

instant.toString(): 2014-02-28T07:25:25Z

将该 Instant 转换为所需的时区。

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );

zdt.toString(): 2014年2月28日02时25分25秒,美国蒙特利尔时区


关于 java.time

java.time 框架是内置于 Java 8 及以后版本中的。这些类取代了老旧的 遗留 日期时间类,如 java.util.DateCalendarSimpleDateFormat

Joda-Time项目现在处于维护模式,建议迁移到java.time类。

想要了解更多信息,请参阅Oracle教程。并搜索Stack Overflow以获取许多示例和解释。规范为JSR 310

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

如何获取java.time类?

ThreeTen-Extra项目通过添加额外的类扩展了java.time。该项目是java.time可能未来增加内容的试验场。您可能会在这里找到一些有用的类,例如Interval, YearWeek, YearQuarter, 以及更多


Joda-Time

更新:Joda-Time项目现在处于维护模式,建议迁移到java.time类。

Joda-Time使用ISO 8601作为其默认格式。

Joda-Time DateTime对象知道它所在的时区,而java.util.Date对象则不知道。

通常最好显式指定时区,而不是依赖于默认时区。

代码示例

long input = 1393572325000L;
DateTime dateTimeUtc = new DateTime( input, DateTimeZone.UTC );

DateTimeZone timeZoneIndia = DateTimeZone.forID( "Asia/Kolkata" );
DateTimeZone timeZoneIreland = DateTimeZone.forID( "Europe/Dublin" );

DateTime dateTimeIndia = dateTimeUtc.withZone( timeZoneIndia );
DateTime dateTimeIreland = dateTimeIndia.withZone( timeZoneIreland );

// Use a formatter to create a String representation. The formatter can adjust time zone if you so desire.
DateTimeFormatter formatter = DateTimeFormat.forStyle( "FM" ).withLocale( Locale.CANADA_FRENCH ).withZone( DateTimeZone.forID( "America/Montreal" ) );
String output = formatter.print( dateTimeIreland );

将数据转储到控制台...

// All three of these date-time objects represent the *same* moment in the timeline of the Universe.
System.out.println( "dateTimeUtc: " + dateTimeUtc );
System.out.println( "dateTimeIndia: " + dateTimeIndia );
System.out.println( "dateTimeIreland: " + dateTimeIreland );

System.out.println( "output for Montréal: " + output );

当运行时...
dateTimeUtc: 2014-02-28T07:25:25.000Z
dateTimeIndia: 2014-02-28T12:55:25.000+05:30
dateTimeIreland: 2014-02-28T07:25:25.000Z
output for Montréal: vendredi 28 février 2014 02:25:25

实际上,java.util.Date 确实有一个时区。该时区被分配在其源代码深处。然而,对于大多数实际目的,该类忽略了该时区。它的toString方法应用JVM的当前默认时区,而不是内部时区。令人困惑吗?是的。这是避免旧的java.util.Date/.Calendar类的许多原因之一。改用java.time和/或Joda-Time。


7
在Java 8中,使用java 8 java.time.Instant库非常容易获取UTC时间戳:
Instant.now();

那几行代码将返回UTC时间戳。

没有回答问题,输入是1393572325000L。请查看我的答案,其中包含完整的解析此输入的代码。 - Basil Bourque

3

您可以从当前时间减去时区差异。

final Calendar calendar  = Calendar.getInstance();
final int      utcOffset = calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET);
final long     tempDate  = new Date().getTime();

return new Date(tempDate - utcOffset);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接