LocalDate到GregorianCalendar的转换

时间:2018-04-05 08:36:36

标签: java

我正在尝试将LocalDate转换为GregorianCalendar,但GregorianCalendar输出给出的日期是与LocalDate相比的前一天。

以下是代码段:

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.GregorianCalendar;

public class Test {
    public static void main(String[] arg){
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        final LocalDate localDate = LocalDate.now(ZoneId.of("Australia/Victoria")).withDayOfMonth(16).withMonth(10).withYear(2017);
        final GregorianCalendar gregorianCalendar = GregorianCalendar.from(localDate.atStartOfDay(ZoneId.of("Australia/Victoria")));
        System.out.println(format.format(gregorianCalendar.getTime())); //prints 2017-10-15
    }
}

当代码在具有“澳大利亚/维多利亚”以外的时区的机器上运行时出现问题。

谁能帮助我指出我在做什么错?

2 个答案:

答案 0 :(得分:2)

TimeZone设置为SimpleDateFormat,如

public class Test {
    public static void main(String[] arg){
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        ZoneId zoneId = ZoneId.of("Australia/Victoria");
        format.setTimeZone(TimeZone.getTimeZone(zoneId));
        final LocalDate localDate = LocalDate.now(zoneId).withDayOfMonth(16).withMonth(10).withYear(2017);
        final GregorianCalendar gregorianCalendar = GregorianCalendar.from(localDate.atStartOfDay(zoneId));
        System.out.println(format.format(gregorianCalendar.getTime())); //prints 2017-10-16
    }
}

答案 1 :(得分:1)

tl; dr

您正在将可怕的旧类与现代的 java.time 类混合在一起。 不要这样做。

LocalDate
.parse( "2017-10-16" )
.atStartOfDay(
    ZoneId.of( "Australia/Victoria" )
)

如果必须使用可怕的GregorianCalendar类,请使用添加到旧类中的新转换方法。

GregorianCalendar  // Terrible legacy class. Use only if you *must*. 
.from(
    LocalDate
    .parse( "2017-10-16" )
    .atStartOfDay(
        ZoneId.of( "Australia/Victoria" )
    )
)

详细信息

您的代码是可怕的旧式日期时间类(SimpleDateFormatGregorianCalendar)和现代的 java.time 类(取代了它们)的奇怪混搭( LocalDate)。

具体地说,ZonedDateTime取代了GregorianCalendar

LocalDate仅表示日期,没有时间,也没有时区。相反,ZonedDateTime(和GregorianCalendar)代表时刻:日期,一天中的时间和时区。

LocalDate开始。

LocalDate ld = LocalDate.parse( "2017-10-16" ) ;

指定一天中的时间。

LocalTime lt = LocalTime.of( 15 , 30 ) ;  // 3:30 PM.

指定您要记住的时区。

ZoneId z = ZoneId.of( "Australia/Victoria" ) ;

结合起来以获取ZonedDateTime,时刻和时间轴上的特定点。

ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z ) ;

或者您可能想将一天的第一时间用作时间部分。请勿将其硬编码为00:00:00。某些区域中的某些日期从其他时间开始,例如01:00:00。让 java.time 确定第一时刻。

ZonedDateTime zdt = ld.atStartOfDay( z ) ;  // Determine the first moment of the day on that date in that zone.

在UTC看到同一时刻。提取一个Instant,它始终使用UTC。

Instant instant = zdt.toInstant() ;

请注意,上述代码的 all 全部来自 java.time 包类家族。

尽可能避免使用GregorianCalendar。但是,如果您必须与尚未更新为 java.time 的旧代码进行互操作,请进行转换。查看添加到 old 类的新to… / from…转换方法。在这种情况下,请参见GregorianCalendar.from

GregorianCalendar gc = GregorianCalendar.from( zdt ) ;