如何在Java中没有时间获取日期?


235

继续从Stack Overflow的问题开始,Java程序获取没有时间戳的当前日期

没有时间获取Date对象的最有效方法是什么?除了这两种以外,还有其他方法吗?

// Method 1
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date dateWithoutTime = sdf.parse(sdf.format(new Date()));

// Method 2
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
dateWithoutTime = cal.getTime();

更新

  1. 我知道乔达·时代;我只是想避免为这样一个简单的任务增加库(我认为)。但是根据到目前为止的答案,《乔达时报》似乎非常受欢迎,因此我可以考虑一下。

  2. 通过高效的,我的意思是我想避免临时对象String的创建13759 method 1,同时method 2似乎是一个黑客,而不是一个解决方案。


1
有效率吗 您是否需要比method1提供的效率更高的效率?
JohanSjöberg

2
您所说的“高效”是什么意思?日期基本上是键入的长,您真的不能在比它少的内存中做到这一点。如果您说的是“方便”,那么JODA时间就是路要走。
millimoose

3
+1 正是我的问题。
阿尔巴·门德斯

1
我喜欢方法2。在实用程序类中创建一个静态方法,然后使用它。我已经使用这种方法很多年了。
Wilson Freitas

1
细细了解您的“更新1”:如果它是“如此简单的任务”,我想Sun不会使用如此可怕而低效的API,您(以及很多其他人)也不会问这个问题在所有;-)
弗拉维奥伊特鲁里亚

Answers:


108

您绝对必须使用java.util.Date吗?我将彻底建议您使用Joda Timejava.timeJava 8中的软件包。特别是,虽然“日期”和“日历” 始终代表一个特定的时间瞬间,但没有“仅是日期”这样的概念,但“乔达时间” 确实具有代表此时间的类型(LocalDate)。如果您能够使用表示您实际要执行的操作的类型,则代码将更加清晰。

使用Joda Time或使用java.time内置java.util类型的原因很多很多,它们通常是更好的API。java.util.Date如果需要,例如在进行数据库交互时,您始终可以在自己代码的边界处与a 进行相互转换。


75
在企业应用程序中,我们并不总是可以选择添加/使用其他库。我很欣赏指向Joda Time的指针,但这实际上不是对使用标准Java获取日期部分的原始问题的答案。谢谢。支持Chathuranga的答案。
noogrub

3
@noogrub:Chathugranga的答案没有回答原始问题,该问题询问如何获取Date对象-该答案将日期格式化为字符串,这不是同一回事。从根本上讲,询问a的日期Date是没有任何意义的毫无意义的问题:您使用的时区和日历系统。
乔恩·斯基特

7
“在企业应用程序中,我们并不总是可以选择添加/使用其他库”。真的吗 您是否建议您完全不能使用3rd party库?
Brian Agnew 2014年

3
@BrianAgnew noogrub的评论似乎与非技术限制有关,我想
Jose_GD 2014年

3
从今天的角度来看:“ Joda-Time是Java SE 8之前的Java的事实上的标准日期和时间库。现在,要求用户迁移到java.time(JSR-310)。”
Drux

66

这是我用来获取今天日期的时间,时间设置为00:00:00

DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");

Date today = new Date();

Date todayWithZeroTime = formatter.parse(formatter.format(today));

28
这与原始问题中已经提出的“方法1”有何不同?
克里斯(Chris

不解决发生在哪个时区(留给JVM的任意默认时区)。
Darrell Teague

58

您可以使用Apache Commons库中的DateUtils.truncate

例:

DateUtils.truncate(new Date(), java.util.Calendar.DAY_OF_MONTH)

3
如果要添加一个新的库,则将其设为Joda而不是Apache Commons。
Dibbeke '16

6
+1 @Dibbeke不同之处不仅在于您将添加一个库,而不是添加另一个库。有时,人们不想仅仅为了删除日期中的时间这一琐碎的任务而学习一个全新的库。或不希望使用将前者(有时是后者)的日期/日历与乔达日期混合在一起的代码。或无法负担/证明用另一个如此简单的目的用另一个库替换所有运行良好的基于​​日期/日历的代码。同时建议乔达肯定是好的,因为它是明显的优越性,只是正确的事,有时现实生活中踢英寸
SantiBailors

天才!帮助了我很多
Thiesen

37

除了这两种以外,还有其他方法吗?

就在这里。

LocalDate.now( 
    ZoneId.of( "Pacific/Auckland" ) 
)

java.time

Java 8和更高版本内置了新的java.time软件包。请参阅教程。多的java.time功能后移植到Java 6和7在ThreeTen-反向移植和在进一步适于到Android ThreeTenABP

Joda-Time相似,java.time提供了一个LocalDate类来表示没有日期和时区的仅日期值。

请注意,时区对于确定特定日期至关重要。例如,在巴黎午夜时分,蒙特利尔的日期仍然是“昨天”。

LocalDate today = LocalDate.now( ZoneId.of( "America/Montreal" ) ) ;

默认情况下,java.time使用ISO 8601标准生成日期或日期时间值的字符串表示形式。(与Joda-Time的另一个相似之处。)因此只需调用toString()即可生成类似的文本2015-05-21

String output = today.toString() ; 

关于java.time

java.time框架是建立在Java 8和更高版本。这些类取代麻烦的老传统日期时间类,如java.util.DateCalendar,和SimpleDateFormat

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

要了解更多信息,请参见Oracle教程。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310

在哪里获取java.time类?

ThreeTen-额外项目与其他类扩展java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。你可能在这里找到一些有用的类,比如IntervalYearWeekYearQuarter,和更多


1
感谢您提及时区。在我看来,“今天是什么”不是一个绝对的概念。
ToolmakerSteve

@ToolmakerSteve获取日期始终涉及一个时区。但是诀窍在于,如果您未能指定时区,那么自动应用JVM当前的默认时区来确定日期。最重要的是,JVM的当前默认时区可以改变在任何时刻!JVM内任何应用程序的任何线程中的任何代码都可以TimeZone.setDefault在运行时调用,并立即影响该JVM 中运行的所有其他代码。故事的寓意:始终指定一个时区。
罗勒·布尔克

22

最直接的方法:

long millisInDay = 60 * 60 * 24 * 1000;
long currentTime = new Date().getTime();
long dateOnly = (currentTime / millisInDay) * millisInDay;
Date clearDate = new Date(dateOnly);

5
对我来说,这是目前: “周六19日年2月01:00:00 CET 2011”。如果要使用它,则只能使用UTC。
克里斯·勒彻

4
第三long dateOnly = (currentTime / millisInDay) * millisInDay;行与写作不一样long dateOnly = currentTime;吗?
克里斯(Chris

5
不是因为整数数学。认为它更像Math.floor(currentTime / millisInDay)* millisInDay。这样,他实际上将时间设置为00:00:00。
Nicholas Flynt

2
对于大多数应用程序来说,该解决方案可能是不错的选择,但请注意,一天的60 * 60 * 24 * 1000并非总是正确的。例如,您可能在某些日子里有leap秒。
Pierre-Antoine 2015年

1
相对于其他1行和2行清晰明了的方法,这可以说是最晦涩而不推荐的方法。
Darrell Teague

22

这些问题的标准答案是使用Joda Time。该API更好,如果您使用格式化程序和解析器,则可以避免非直观的线程安全性SimpleDateFormat

使用Joda意味着您可以轻松做到:

LocalDate d = new LocalDate();

更新::使用java 8,可以使用以下方法实现

LocalDate date = LocalDate.now();

Java 8中新的java.time包还提供了LocalDate类似于Joda-Time的类。
罗勒·布尔克

1
理想情况下,您可以将传递DateTimeZone给该LocalDate构造函数。确定当前日期取决于时区,因为巴黎比蒙特利尔早开始一个新日期。如果省略时区,则将应用JVM的默认时区。通常指定比依赖默认值更好。
罗勒·布尔克2014年

8

这是一种简单的方法:

Calendar cal = Calendar.getInstance();
SimpleDateFormat dateOnly = new SimpleDateFormat("MM/dd/yyyy");
System.out.println(dateOnly.format(cal.getTime()));

4
该答案无法解决该问题。目标不是获得格式化的字符串。
罗勒·布尔克

7

在标准Java运行时中,谈论没有时间戳的日期是没有意义的,因为它实质上是向下映射到特定的毫秒而不是日期。毫秒本质上是与一天相关联的,这使其很容易受到时区问题(如夏令时和其他日历调整)的影响。请参阅为什么将这两次相减(在1927年)会得出奇怪的结果?一个有趣的例子。

如果要使用日期而不是毫秒,则需要使用其他方法。对于Java 8,提供了一组新方法,它们提供了您所要求的。对于Java 7和更早版本,请使用http://www.joda.org/joda-time/


3
注意:那些说“午夜的日期”的方法不能很好地解决夏时制和多个时区问题。
托尔比约恩Ravn的安德森

我确认了这一点,我将应用程序中的日期增加了一天,并通过具有DST时区(我所在的国家/地区未使用DST)的用户的错误报告了解了这一点。在DST开始的那一天,我的应用程序将添加11个小时而不是12个小时。也许将中午用作“无时间”日期的小时更好?
Jose_GD 2014年

1
@Jose_GD充其量仍然是一个hack。您可能会发现youtube.com/watch?v=-5wpm-gesOY有趣。
托尔比约恩Ravn的安徒生

@ Thorbjorn,您是对的,只是想避免使用JodaTime,因为为我添加仅一个功能的库听起来就有些过头了。我知道那个视频,确实很有趣。
Jose_GD 2014年

1
@Jose_GD关键是存在一个实际的实际用例,在这种情况下,您的方法将被视为错误。如果找到一个,可能还有更多...我不知道Joda如何处理这个问题,但是您可以看看。还要注意,Java 8带来了一个新的日期时间库(基于Joda的经验),您可能需要研究一下。
托尔比约恩Ravn的安徒生

4

绝对不是最正确的方法,但是如果您只需要一种快速的解决方案来获取日期而又没有时间,并且您不希望使用第三方库,则应该这样做

    Date db = db.substring(0, 10) + db.substring(23,28);

我只需要日期即可用于视觉目的,而乔达则不需要,所以我隐瞒了。


4
// 09/28/2015
System.out.println(new SimpleDateFormat("MM/dd/yyyy").format(Calendar.getInstance().getTime()));

// Mon Sep 28
System.out.println( new Date().toString().substring(0, 10) );

// 2015-09-28
System.out.println(new java.sql.Date(System.currentTimeMillis()));

// 2015-09-28
// java 8
System.out.println( LocalDate.now(ZoneId.of("Europe/Paris")) ); // rest zones id in ZoneId class

3

好吧,据我所知,如果仅使用标准JDK,没有比这更简单的方法了。

当然,您可以将方法2中的逻辑放入帮助程序类的静态函数中,就像在toBeginningOfTheDay方法中所做的一样

然后,您可以将第二种方法缩短为:

Calendar cal = Calendar.getInstance();
Calendars.toBeginningOfTheDay(cal);
dateWithoutTime = cal.getTime();

或者,如果您确实经常需要这种格式的当前日期,则可以将其包装在另一种静态帮助器方法中,从而使其成为一种格式。


3

如果您只想看到类似“ YYYY-MM-DD”的日期,而没有其他混乱,例如“ EDT 2015年5月21日12:08:18”,则只需使用即可java.sql.Date。本示例获取当前日期:

new java.sql.Date(System.currentTimeMillis());

也是java.sql.Date的子类java.util.Date


3

如果您只需要当前日期而没有时间,则另一个选择是:

DateTime.now().withTimeAtStartOfDay()

1
该问题要求无时间安排。您的结果是一个日期时间对象,该对象确实的确具有一天中的时间,00:00:00通常是该时间(可能会因时区而异,例如DST会有所不同)。因此,正如其他Answers所指出的那样LocalDate,从Joda-Time(假设您引用的是Joda-Time –引用未与Java捆绑在一起的类时应明确指出)的角度来看,该类更为合适。
罗勒·布尔克

3

使用LocalDate.now()并转换成Date如下形式:

Date.from(LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant());

1
JVM的当前默认时区可以在运行时随时更改。JVM中任何应用程序的任何线程中的任何代码都可以调用TimeZone.setDefault。您的代码调用了ZoneId.systemDefault两次,第一个在中隐式,LocalDate.now()第二个在中显式atStartOfDay。在运行时的这两个时刻之间,当前默认区域可能会更改。我建议将区域捕获到一个变量中,并传递给这两种方法。
罗勒·布尔克

2

如果您只需要日期部分用于回显,那么

Date d = new Date(); 
String dateWithoutTime = d.toString().substring(0, 10);

1
我不认为这是国际化友好
马克Lapasa

2

那这个呢?

public static Date formatStrictDate(int year, int month, int dayOfMonth) {
    Calendar calendar = Calendar.getInstance();
    calendar.set(year, month, dayOfMonth, 0, 0, 0);
    calendar.set(Calendar.MILLISECOND, 0);
    return calendar.getTime();
}

1

查看Veyder-time。它是java.util和Joda-time的一种简单有效的替代方法。它具有直观的API和仅表示日期的类,没有时间戳。


1

充分利用巨大的Java TimeZone数据库的最直接的方法是正确的:

long currentTime = new Date().getTime();
long dateOnly = currentTime + TimeZone.getDefault().getOffset(currentTime);

1

这是一个干净的解决方案,不转换为字符串,也不转换为字符串,并且在将时间的每个分量重置为零时也不会多次重新计算时间。它也使用%(模数)而不是除法,然后乘以以避免双重运算。

它不需要第三方的依赖关系,并且它会传入传入的日历对象的时区。此函数返回传入日期(日历)所在时区中午12点的时间。

public static Calendar date_only(Calendar datetime) {
    final long LENGTH_OF_DAY = 24*60*60*1000;
    long millis = datetime.getTimeInMillis();
    long offset = datetime.getTimeZone().getOffset(millis);
    millis = millis - ((millis + offset) % LENGTH_OF_DAY);
    datetime.setTimeInMillis(millis);
    return datetime;
}

我不是很确信它将尊重夏季TME(DST)?
Ole VV

0

最好不要使用第三方库。我知道以前提到过这种方式,但这是一种不错的干净方式:

  /*
    Return values:
    -1:    Date1 < Date2
     0:    Date1 == Date2
     1:    Date1 > Date2

    -2:    Error
*/
public int compareDates(Date date1, Date date2)
{
    SimpleDateFormat sdf = new SimpleDateFormat("ddMMyyyy");

    try
    {
        date1 = sdf.parse(sdf.format(date1));
        date2 = sdf.parse(sdf.format(date2));
    }
    catch (ParseException e) {
        e.printStackTrace();
        return -2;
    }

    Calendar cal1 = new GregorianCalendar();
    Calendar cal2 = new GregorianCalendar();

    cal1.setTime(date1);
    cal2.setTime(date2);

    if(cal1.equals(cal2))
    {
        return 0;
    }
    else if(cal1.after(cal2))
    {
        return 1;
    }
    else if(cal1.before(cal2))
    {
        return -1;
    }

    return -2;
}

好吧,不使用GregorianCalendar也许是一种选择!


0

我刚刚为我的应用制作了这个:

public static Date getDatePart(Date dateTime) {
    TimeZone tz = TimeZone.getDefault();
    long rawOffset=tz.getRawOffset();
    long dst=(tz.inDaylightTime(dateTime)?tz.getDSTSavings():0);
    long dt=dateTime.getTime()+rawOffset+dst; // add offseet and dst to dateTime
    long modDt=dt % (60*60*24*1000) ;

    return new Date( dt
                    - modDt // substract the rest of the division by a day in milliseconds
                    - rawOffset // substract the time offset (Paris = GMT +1h for example)
                    - dst // If dayLight, substract hours (Paris = +1h in dayLight)
    );
}

Android API 1级,无外部库。它尊重日光和默认timeZone。没有字符串操作,因此我认为这种方式比您的CPU效率更高,但我尚未进行任何测试。


0

可以使用joda时间。

private Date dateWitoutTime(Date date){
 return new LocalDate(date).toDate()
}

然后致电:

Date date = new Date();
System.out.println("Without Time = " + dateWitoutTime(date) + "/n  With time = " + date);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.