日历的日期对象 [Java]

Posted

技术标签:

【中文标题】日历的日期对象 [Java]【英文标题】:Date object to Calendar [Java] 【发布时间】:2011-02-13 05:41:08 【问题描述】:

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

据我所知,不推荐使用 Date 的时间操纵函数,因此这是不好的做法,但另一方面,我看不到将 Date 对象转换为日历对象以操纵时间并将其重新转换为 Date 对象的方法. 有办法吗?如果有什么是最佳做法

【问题讨论】:

如果您经常使用日期,我发现 Joda Time 比 Java 的 Date 和 Calendar 类要好得多:joda-time.sourceforge.net 应该惩罚分发涉及日期/日历的作业的人。 :-) 如果我处于你的位置,我会使用 JAVA 7 中添加的健全的 API。 类似问题:Converting a Date object to a calendar object 【参考方案1】:

Calendar.setTime()

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

【讨论】:

【参考方案2】:
Calendar tCalendar = Calendar.getInstance();
tCalendar.setTime(date);

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

【讨论】:

Calendar.getInstance() 返回一个 locale-specific Calendar 实现,因此通常更可取。【参考方案3】:

您无需为此转换为Calendar,只需使用getTime()/setTime()即可。

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

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

一秒有 1000 毫秒,一分钟有 60 秒。算一算吧。

    Date now = new Date();
    Date oneMinuteInFuture = new Date(now.getTime() + 1000L * 60);
    System.out.println(now);
    System.out.println(oneMinuteInFuture);

1000 中的 L 后缀表示它是 long 文字;这些计算通常很容易溢出int

【讨论】:

【参考方案4】:

您可以做的是创建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;

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

【讨论】:

Java 的日期/时间实现是如此糟糕,以至于我不确定更糟糕的是 - 保留 JodaTime - 即使时间计算只是我的应用程序整体功能的一小部分 - 或者切换到日期/日历和花费数小时涉足本应是实施良好、可靠的组件的半途而废的烂摊子。 @Melllvar 如此真实。现在您有了第三种选择:Java 8 及更高版本中内置的 java.time 类。对于 Java 6 和 7,java.time 的大部分功能已被向后移植到 ThreeTen-Backport 项目中。对于早期的 android,请参阅 ThreeTenABP 项目。至于 Joda-Time,该项目现在处于维护模式,指定 java.time 为其正式继任者,其创建者 Stephen Colebourne 领导了这两个项目。【参考方案5】:

类似

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

【讨论】:

【参考方案6】:

tl;博士

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

java.time

其他答案是正确的,尤其是the Answer by Borgwardt。但是这些答案使用过时的遗留类。

与 Java 捆绑的原始日期时间类已被 java.time 类取代。在 java.time 类型中执行您的业务逻辑。仅在需要使用尚未更新以处理 java.time 类型的旧代码时才转换为旧类型。

如果您的Calendar 实际上是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 

如果您的Calendar 不是Gregorian,请调用toInstant 以获取Instant 对象。 Instant 类代表UTC 中时间轴上的一个时刻,分辨率为nanoseconds。

Instant instant = myCal.toInstant();

同样,如果以 java.util.Date 对象开头,则转换为 InstantInstant 类代表UTC 时间线上的时刻,分辨率为nanoseconds(最多九 (9) 位小数)。

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 之间转换的更多讨论以及漂亮的图表,请参阅my Answer 到另一个问题。

Duration

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

Duration d = Duration.ofMinutes( yourMinutesGoHere );

您可以将其添加到开始以确定停止。

Instant stop = startInstant.plus( d ); 

关于java.time

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

Joda-Time 项目现在位于maintenance mode,建议迁移到 java.time。

要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310。

从哪里获得 java.time 类?

Java SE 8SE 9 及更高版本 内置。 标准 Java API 的一部分,带有捆绑实现。 Java 9 添加了一些小功能和修复。 Java SE 6SE 7 ThreeTen-Backport 中的大部分 java.time 功能都向后移植到 Java 6 和 7。 Android ThreeTenABP 项目专门针对 Android 改编 ThreeTen-Backport(如上所述)。 见How to use…

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuarter 和more。

【讨论】:

【参考方案7】:

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

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 类所取代。【参考方案8】:

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

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

【讨论】:

以上是关于日历的日期对象 [Java]的主要内容,如果未能解决你的问题,请参考以下文章

Java全栈JavaSE:19.常用类之大数运算日期和日历包装类

日期对象到日历对象的转换

将日期对象转换为日历对象 [重复]

如何将日期字符串转换为日期或日历对象?

怎么在java日历程序所输入的日期上加入符号?

Java日期类题目