将Date对象转换为Calendar对象 [Java]

69

我有一个电影类:Movie,其中包括开始日期、持续时间和结束日期。开始和结束日期是Date对象(私有的Date startDate...)(这是一个任务所以我不能改变它)。现在我想通过将持续时间(以分钟为单位)添加到开始日期来自动计算停止日期。

据我所知,使用Date的时间操作函数已经过时,因此不好的实践方法,但另一方面,我看不到将Date对象转换为Calendar对象以便操作时间并重新转换为Date对象的方法。是否有方法?如果有,最佳做法是什么?


4
如果您经常处理日期,我发现Joda Time比Java的Date和Calendar类要好得多:http://joda-time.sourceforge.net/ - Michael Williamson
3
如果有人分发与日期/日历相关的任务,应该受到惩罚。 :-)如果我处在你的位置,我会使用JAVA 7中添加的合理API。 - soc
类似问题:将日期对象转换为日历对象 - Basil Bourque
8个回答

101

你可以创建一个GregorianCalendar的实例,然后将Date设置为开始时间:

Date date;
Calendar myCal = new GregorianCalendar();
myCal.setTime(date);

然而,另一种方法是根本不使用Date。您可以使用类似于以下方式的方法:

private Calendar startTime;
private long duration;
private long startNanos;   //Nano-second precision, could be less precise
...
this.startTime = Calendar.getInstance();
this.duration = 0;
this.startNanos = System.nanoTime();

public void setEndTime() {
        this.duration = System.nanoTime() - this.startNanos;
}

public Calendar getStartTime() {
        return this.startTime;
}

public long getDuration() {
        return this.duration;
}

通过这种方式,您可以访问开始时间并获取从开始到停止的持续时间。当然,精度取决于您。


1
Java的日期/时间实现太糟糕了,以至于我不确定哪个更糟糕 - 保留JodaTime - 即使时间计算只是我的应用程序整体功能的一小部分 - 还是切换到Date / Calendar并花费数小时浏览那些本应该是良好实现、稳定组件的半吊子混乱。 - Melllvar
@Melllvar 太对了。现在你有第三种选择:Java 8及以后内置的java.time类。对于Java 6&7java.time功能的大部分已经在ThreeTen-Backport项目中进行了回溯。对于早期的Android,请参见ThreeTenABP项目。至于Joda-Time,该项目现在处于维护模式,将java.time指定为其正式继承者,其创建者Stephen Colebourne领导了这两个项目。 - Basil Bourque

29
Calendar tCalendar = Calendar.getInstance();
tCalendar.setTime(date);

date是一个java.util.Date对象。你也可以使用Calendar.getInstance()来获取日历实例(更加高效)。


1
Calendar.getInstance() 返回一个与地区相关的 Calendar 实现,因此通常更可取。 - hotshot309

6
你不需要将其转换为Calendar,你可以使用getTime()/setTime()

getTime(): 返回此 Date 对象表示的自 1970 年 1 月 1 日 00:00:00 GMT 以来的毫秒数。

setTime(long time):将此 Date 对象设置为表示 1970 年 1 月 1 日 00:00:00 GMT 后 time 毫秒的时间点。

一秒钟有1000毫秒,一分钟有60秒。只需进行简单计算即可。

    Date now = new Date();
    Date oneMinuteInFuture = new Date(now.getTime() + 1000L * 60);
    System.out.println(now);
    System.out.println(oneMinuteInFuture);
1000L中的L后缀表示这是一个long型字面量;这些计算通常很容易就会使int类型发生溢出。

6

Calendar.setTime()

通常查看API方法的签名和描述是非常有用的,而不仅仅是它们的名称。即使在Java标准API中,名称有时也会具有误导性。


2

tl;dr

Instant stop = 
    myUtilDateStart.toInstant()
                   .plus( Duration.ofMinutes( x ) ) 
;

java.time

其他答案都是正确的,特别是 Borgwardt的答案。但是这些答案使用了过时的遗留类。
Java原始的日期时间类已经被java.time类所取代。在java.time类型中执行业务逻辑。只有在需要与尚未更新以处理java.time类型的旧代码一起工作时才转换为旧类型。
如果你的日历实际上是一个GregorianCalendar,你可以将其转换为ZonedDateTime。查找添加到旧类中的新方法以便于转换为/从java.time类型。
if( myUtilCalendar instanceof GregorianCalendar ) {
    GregorianCalendar gregCal = (GregorianCalendar) myUtilCalendar; // Downcasting from the interface to the concrete class.
    ZonedDateTime zdt = gregCal.toZonedDateTime();  // Create `ZonedDateTime` with same time zone info found in the `GregorianCalendar`
end if 

如果您的日历不是公历,调用toInstant以获取Instant对象。Instant类表示时间线上的一个时刻,在UTC中具有纳秒的分辨率。
Instant instant = myCal.toInstant();

同样地,如果从一个 java.util.Date 对象开始,将其转换为一个 InstantInstant 类表示一个时间线上的时刻,在 UTC 上,分辨率为 纳秒(小数点后最多九位数字)。
Instant instant = myUtilDate.toInstant();

应用时区以获取一个ZonedDateTime
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );

要获取一个 java.util.Date 对象,请通过 Instant 进行操作。
java.util.Date utilDate = java.util.Date.from( zdt.toInstant() );

更多关于将传统日期时间类型和java.time之间转换的讨论以及漂亮的图表,请参见我的答案中的另一个问题。

持续时间

将时间跨度表示为Duration对象。您在问题中提到的持续时间输入是分钟数。

Duration d = Duration.ofMinutes( yourMinutesGoHere );

你可以在开头加上这个来确定结束。
Instant stop = startInstant.plus( d ); 

关于 java.time

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

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

要了解更多,请查看 Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规范是 JSR 310
在哪里获取 java.time 类? 该项目是ThreeTen-Extra,它扩展了java.time的附加类。该项目是java.time可能未来添加的概念实验场所。您可能会在这里找到一些有用的类,例如{{link2:Interval}}, YearWeek, YearQuarter, 以及更多

1

将日期转换为日历的 Kotlin 扩展。

fun Date?.toCalendar(): Calendar? {
    return this?.let { date ->
        val calendar = Calendar.getInstance()
        calendar.time = date
        calendar
    }
}

0

像这样的

movie.setStopDate(movie.getStartDate() + movie.getDurationInMinutes()* 60000);

0

这里是一个完整的示例,演示如何将日期转换为不同类型:

Date date = Calendar.getInstance().getTime();

    // Display a date in day, month, year format
    DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");
    String today = formatter.format(date);
    System.out.println("Today : " + today);

    // Display date with day name in a short format
    formatter = new SimpleDateFormat("EEE, dd/MM/yyyy");
    today = formatter.format(date);
    System.out.println("Today : " + today);

    // Display date with a short day and month name
    formatter = new SimpleDateFormat("EEE, dd MMM yyyy");
    today = formatter.format(date);
    System.out.println("Today : " + today);

    // Formatting date with full day and month name and show time up to
    // milliseconds with AM/PM
    formatter = new SimpleDateFormat("EEEE, dd MMMM yyyy, hh:mm:ss.SSS a");
    today = formatter.format(date);
    System.out.println("Today : " + today);

这里使用的麻烦的日期时间类(DateCalendar)现在已经过时,多年前被现代的java.time类所取代。 - Basil Bourque

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