如何设置java.util.Date的时区?

时间:2010-05-23 10:29:50

标签: java date timezone java.util.date

我已经从java.util.Date解析了String,但它将本地时区设置为date对象的时区。

在解析String的{​​{1}}中未指定时区。我想设置Date对象的特定时区。

我该怎么做?

11 个答案:

答案 0 :(得分:275)

使用DateFormat。例如,

SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
isoFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = isoFormat.parse("2010-05-23T09:01:02");

答案 1 :(得分:152)

请注意java.util.Date个对象本身不包含任何时区信息 - 您无法在Date对象上设置时区。 Date对象包含的唯一内容是自“epoch” - 1970年1月1日00:00:00 UTC以来的毫秒数。

正如ZZ编码器所示,您在DateFormat对象上设置时区,告诉它您要在哪个时区显示日期和时间。

答案 2 :(得分:70)

TL;博士

  

...解析...来自String ...时区未指定...我想设置一个特定的时区

LocalDateTime.parse( "2018-01-23T01:23:45.123456789" )  // Parse string, lacking an offset-from-UTC and lacking a time zone, as a `LocalDateTime`.
    .atZone( ZoneId.of( "Africa/Tunis" ) )              // Assign the time zone for which you are certain this date-time was intended. Instantiates a `ZonedDateTime` object.

j.u.Date中没有时区

正如其他正确答案所述,java.util.Date没有时区。它代表UTC / GMT(没有时区偏移)。非常混乱,因为它的toString方法在生成字符串表示时应用JVM的默认时区。

避免使用j.u.Date

出于这个原因和其他许多原因,你应该避免使用内置的java.util.Date& .Calendar& java.text.SimpleDateFormat中。众所周知,它们很麻烦。

而是使用与java.time package捆绑在一起的Java 8

java.time

java.time类可以用三种方式表示时间轴上的一个时刻:

  • UTC(Instant
  • 带偏移量(OffsetDateTimeZoneOffset
  • 使用时区(ZonedDateTimeZoneId

Instant

java.time中,基本构建块为Instant,是UTC时间线上的一个时刻。使用Instant个对象来实现大部分业务逻辑。

Instant instant = Instant.now();

OffsetDateTime

应用offset-from-UTC调整到某个地区的wall-clock time

应用ZoneOffset获取OffsetDateTime

ZoneOffset zoneOffset = ZoneOffset.of( "-04:00" );
OffsetDateTime odt = OffsetDateTime.ofInstant( instant , zoneOffset );

ZonedDateTime

最好是应用time zone,偏移加上处理Daylight Saving Time (DST)等异常的规则。

ZoneId应用于Instant以获得ZonedDateTime。始终指定proper time zone name。切勿使用ESTIST等3-4个缩写,既不是唯一的也不是标准化的。

ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );

LocalDateTime

如果输入字符串缺少任何偏移量或区域指示符,则解析为LocalDateTime

如果您确定预定的时区,请指定ZoneId以生成ZonedDateTime。请参阅上面 tl; dr 部分中的代码示例。

格式化字符串

在这三个类中的任何一个上调用toString方法,以标准ISO 8601格式生成表示日期时间值的String。 ZonedDateTime类通过在括号中附加时区名称来扩展标准格式。

String outputInstant = instant.toString(); // Ex: 2011-12-03T10:15:30Z
String outputOdt = odt.toString(); // Ex: 2007-12-03T10:15:30+01:00
String outputZdt = zdt.toString(); // Ex: 2007-12-03T10:15:30+01:00[Europe/Paris]

对于其他格式,请使用DateTimeFormatter类。通常最好让该类使用用户期望的人类语言和文化规范生成本地化格式。或者您可以指定特定格式。


关于 java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendar和& SimpleDateFormat

现在位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

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

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore


约达时间

虽然Joda-Time仍在积极维护,但其制造商已告诉我们尽快迁移到java.time。我保留此部分作为参考,但我建议使用上面的java.time部分。

Joda-Time中,日期时间对象(DateTime)确实知道其指定的时区。这意味着从UTC 偏移该时区的夏令时(DST)和其他此类异常的规则和历史记录。

String input = "2014-01-02T03:04:05";
DateTimeZone timeZone = DateTimeZone.forID( "Asia/Kolkata" );
DateTime dateTimeIndia = new DateTime( input, timeZone );
DateTime dateTimeUtcGmt = dateTimeIndia.withZone( DateTimeZone.UTC );

调用toString方法以ISO 8601格式生成字符串。

String output = dateTimeIndia.toString();

Joda-Time还提供丰富的功能来生成各种其他字符串格式。

如果需要,您可以从Joda-Time DateTime转换为java.util.Date。

Java.util.Date date = dateTimeIndia.toDate();

搜索StackOverflow" joda date"找到更多的例子,有些非常详细。


实际上嵌入java.util.Date中的时区,用于某些内部函数(请参阅本答案中的注释)。但是此内部时区不作为属性公开,并且无法设置。此内部时区 toString方法在生成日期时间值的字符串表示形式时使用的时区;相反,JVM的当前默认时区是即时应用的。所以,作为简写,我们经常说“j.u.Date没有时区”。混乱?是。避免这些疲惫不堪的老班的另一个原因。

答案 3 :(得分:64)

您还可以在JVM级别设置时区

Date date1 = new Date();
System.out.println(date1);

TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
// or pass in a command line arg: -Duser.timezone="UTC"

Date date2 = new Date();
System.out.println(date2);

输出:

Thu Sep 05 10:11:12 EDT 2013
Thu Sep 05 14:11:12 UTC 2013

答案 4 :(得分:6)

java.util.Calendar是使用JDK类处理时区的常用方法。 Apache Commons有一些可能有用的替代/实用工具。 编辑 Spong的笔记提醒我,我听说过Joda-Time非常好的事情(虽然我自己没有用过)。

答案 5 :(得分:6)

如果您必须只使用标准JDK类,则可以使用:

/**
 * Converts the given <code>date</code> from the <code>fromTimeZone</code> to the
 * <code>toTimeZone</code>.  Since java.util.Date has does not really store time zome
 * information, this actually converts the date to the date that it would be in the
 * other time zone.
 * @param date
 * @param fromTimeZone
 * @param toTimeZone
 * @return
 */
public static Date convertTimeZone(Date date, TimeZone fromTimeZone, TimeZone toTimeZone)
{
    long fromTimeZoneOffset = getTimeZoneUTCAndDSTOffset(date, fromTimeZone);
    long toTimeZoneOffset = getTimeZoneUTCAndDSTOffset(date, toTimeZone);

    return new Date(date.getTime() + (toTimeZoneOffset - fromTimeZoneOffset));
}

/**
 * Calculates the offset of the <code>timeZone</code> from UTC, factoring in any
 * additional offset due to the time zone being in daylight savings time as of
 * the given <code>date</code>.
 * @param date
 * @param timeZone
 * @return
 */
private static long getTimeZoneUTCAndDSTOffset(Date date, TimeZone timeZone)
{
    long timeZoneDSTOffset = 0;
    if(timeZone.inDaylightTime(date))
    {
        timeZoneDSTOffset = timeZone.getDSTSavings();
    }

    return timeZone.getRawOffset() + timeZoneDSTOffset;
}

归功于此post

答案 6 :(得分:1)

在这里您可以获得类似“ 2020-03-11T20:16:17”的日期并返回“ 11 / Mar / 2020-20:16”

 private String transformLocalDateTimeBrazillianUTC(String dateJson) throws  ParseException {
    String localDateTimeFormat = "yyyy-MM-dd'T'HH:mm:ss";
    SimpleDateFormat formatInput = new SimpleDateFormat(localDateTimeFormat);

    //Here is will set the time zone
    formatInput.setTimeZone(TimeZone.getTimeZone("UTC-03"));

    String brazilianFormat = "dd/MMM/yyyy - HH:mm";
    SimpleDateFormat formatOutput = new SimpleDateFormat(brazilianFormat);
    Date date = formatInput.parse(dateJson);
    return formatOutput.format(date);
}

答案 7 :(得分:0)

如果有人需要这个,如果您需要将XMLGregorianCalendar时区从UTC转换为当前时区,那么您需要做的就是将时区设置为0,然后调用{{1它将保持相同的时区,但toGregorianCalendar()知道如何将其转换为您的时区,因此您可以从那里获取数据。

Date

结果:

XMLGregorianCalendar xmlStartTime = DatatypeFactory.newInstance()
    .newXMLGregorianCalendar(
        ((GregorianCalendar)GregorianCalendar.getInstance());
xmlStartTime.setTimezone(0);
GregorianCalendar startCalendar = xmlStartTime.toGregorianCalendar();
Date startDate = startCalendar.getTime();
XMLGregorianCalendar xmlStartTime = DatatypeFactory.newInstance()
    .newXMLGregorianCalendar(startCalendar);
xmlStartTime.setHour(startDate.getHours());
xmlStartTime.setDay(startDate.getDate());
xmlStartTime.setMinute(startDate.getMinutes());
xmlStartTime.setMonth(startDate.getMonth()+1);
xmlStartTime.setTimezone(-startDate.getTimezoneOffset());
xmlStartTime.setSecond(startDate.getSeconds());
xmlStartTime.setYear(startDate.getYear() + 1900);
System.out.println(xmlStartTime.toString());

答案 8 :(得分:0)

将Date转换为String并使用SimpleDateFormat进行。

    SimpleDateFormat readFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
    readFormat.setTimeZone(TimeZone.getTimeZone("GMT" + timezoneOffset));
    String dateStr = readFormat.format(date);
    SimpleDateFormat writeFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
    Date date = writeFormat.parse(dateStr);

答案 9 :(得分:0)

此代码对我正在使用的应用程序很有帮助:

    Instant date = null;
    Date sdf = null;
    String formatTemplate = "EEE MMM dd yyyy HH:mm:ss";
    try {
        SimpleDateFormat isoFormat = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss");
        isoFormat.setTimeZone(TimeZone.getTimeZone(ZoneId.of("US/Pacific")));
        sdf = isoFormat.parse(timeAtWhichToMakeAvailable);
        date = sdf.toInstant();

    } catch (Exception e) {
        System.out.println("did not parse: " + timeAtWhichToMakeAvailable);
    }

    LOGGER.info("timeAtWhichToMakeAvailable: " + timeAtWhichToMakeAvailable);
    LOGGER.info("sdf: " + sdf);
    LOGGER.info("parsed to: " + date);

答案 10 :(得分:0)

这个答案可能是最短的,它只使用了 Date 类:

long current = new Date().getTime() + 3_600_000;              //e.g. your JVM time zone +1 hour (3600000 milliseconds)
System.out.printf("%1$td.%1$tm.%1$tY %1$tH:%1$tM\n", current);//european time format

但是,如果可以,请使用更现代的方法来做同样的事情。