【问题标题】:How do I get a Date without time in Java?如何在 Java 中获取没有时间的日期?
【发布时间】:2011-06-30 07:51:15
【问题描述】:

从堆栈溢出问题继续Java program to get the current date without timestamp

在没有时间的情况下获取 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. 我知道Joda-Time;我只是想避免为这样一个简单的(我认为)任务添加额外的库。但根据目前为止的答案,Joda-Time 似乎非常受欢迎,所以我可能会考虑它。

  2. 高效,我的意思是我想避免method 1 使用的临时对象String 创建,同时method 2 似乎是一种技巧而不是解决方案。

【问题讨论】:

  • 高效?您是否需要比方法 1 提供的效率更高的效率?
  • “高效”是什么意思?日期基本上是一个长类型的,你不能在比这更少的内存中真正做到这一点。如果你的意思是“方便”,JODA time 是最好的选择。
  • 我喜欢方法2。在实用程序类中创建一个静态方法并使用它。多年来我一直采用这种方法。
  • 对您的“更新 1”进行吹毛求疵:如果它是“如此简单的任务”,我猜 Sun 不会使用如此可怕和低效的 API,而您(以及许多其他人) ) 根本不会问这个问题 ;-)
  • @RobertoLinares:为什么它“不短”很重要?每一行都高效。我敢肯定它比方法 1 快很多,方法 1 涉及格式化和解析。

标签: java date


【解决方案1】:

你绝对使用java.util.Date吗?我会彻底建议您改用 Java 8 中的 Joda Timejava.time 包。特别是,虽然 Date 和 Calendar always 代表一个特定的时刻,没有“只是一个日期”这样的概念,但 Joda Time 确实有一个表示这个的类型(@ 987654325@)。如果您能够使用代表您实际尝试执行的类型的类型,您的代码将会更加清晰。

使用 Joda Time 或 java.time 而不是内置的 java.util 类型还有很多其他原因 - 它们通常是更好的 API。如果需要,您可以随时在您自己的代码边界处转换为java.util.Date/从java.util.Date 转换,例如用于数据库交互。

【讨论】:

  • 在企业应用程序中,我们并不总是可以选择添加/使用其他库。我很欣赏指向 Joda Time 的指针,但这并不是对使用标准 Java 获取日期部分的原始问题的答案。谢谢。支持查图兰加的回答。
  • @noogrub:Chathugranga 的回答没有回答最初的问题,即询问如何获取Date 对象 - 回答 formats 日期到字符串,这不是一回事。从根本上说,在没有更多信息的情况下询问Date 的日期是一个毫无意义的问题:时区和您正在使用的日历系统。
  • “在企业应用程序中,我们并不总是可以选择添加/使用其他库”。真的吗 ?您是否建议您根本不能使用 3rd 方库?
  • @BrianAgnew noogrub 的评论似乎与非技术限制有关,我认为
  • 从今天的角度来看:“Joda-Time 是 Java SE 8 之前 Java 的事实上的标准日期和时间库。现在要求用户迁移到 java.time (JSR-310)。”
【解决方案2】:

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

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

Date today = new Date();

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

【讨论】:

  • 这与原问题中已经提出的“方法1”有什么不同?
  • 没有说明这发生在哪个时区(留给 JVM 的任意默认时区)。
【解决方案3】:

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

例子:

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

【讨论】:

  • 如果你要添加一个新库,让它成为 Joda 而不是 Apache Commons。
  • +1 @Dibbeke 不同之处不仅在于您将添加一个库而不是另一个库。有时人们不想仅仅为了从日期中截断时间的琐碎任务而学习一个全新的库。或者不想让代码将日期/日历与 Joda 日期混合使用,有时使用前者,有时使用后者。或者不能承受/证明用另一个库替换所有运行良好的基于​​ Date / Calendar 的代码以实现如此微不足道的目的。虽然暗示 Joda 肯定很好,因为它显然更优越,而且只是正确的事情,但有时现实生活会开始。
【解决方案4】:

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

是的,有。

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

java.time

Java 8 及更高版本带有新的内置 java.time package。见Tutorial。大部分 java.time 功能在 ThreeTen-Backport 中向后移植到 Java 6 和 7,并在 ThreeTenABP 中进一步适应 Android。

类似于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 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

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

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

从哪里获得 java.time 类?

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

【讨论】:

  • @ToolmakerSteve 获取日期始终涉及时区。但诀窍在于,如果您未能指定时区,您的 JVM 当前的默认时区会自动应用于确定日期。最重要的是,JVM 当前的默认时区可以随时更改! JVM 内任何应用程序的任何线程中的任何代码都可以在运行时调用TimeZone.setDefault,并立即影响在该 JVM 中运行的所有其他代码。故事的寓意:始终指定时区。
【解决方案5】:

最直接的方法:

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

【讨论】:

  • 对我来说,目前是:“2011 年 2 月 19 日星期六 01:00:00 CET”。如果你想使用它,那么只能使用 UTC。
  • 第3行long dateOnly = (currentTime / millisInDay) * millisInDay;和写long dateOnly = currentTime;不一样吗?
  • 不是,因为整数数学。把它想象成 Math.floor(currentTime / millisInDay) * millisInDay。他有效地将时间设置为 00:00:00。
  • 这个解决方案可能适用于大多数应用程序,但请注意一天有 60 * 60 * 24 * 1000 的假设并不总是正确的。例如,您可以在某些日子有闰秒。
  • 与其他 1 行和 2 行清晰简洁的方法相比,这可以说是最迟钝且不推荐的方法。
【解决方案6】:

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

使用 Joda 意味着您可以简单地做到:

LocalDate d = new LocalDate();

更新:: 使用 java 8 可以使用

LocalDate date = LocalDate.now();

【讨论】:

  • Java 8 中新的 java.time 包还提供了一个类似于 Joda-Time 的 LocalDate 类。
  • 理想情况下,您应该将 DateTimeZone 传递给该 LocalDate 构造函数。确定当前日期取决于时区,因为巴黎开始的新日期早于蒙特利尔。如果省略时区,则应用 JVM 的默认时区。通常最好指定而不是依赖默认值。
【解决方案7】:

这是一个简单的方法:

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

【讨论】:

  • 这个答案无法解决这个问题。获取格式化字符串不是目标。
【解决方案8】:

对于标准 java 运行时中的 Date 例程,谈论没有时间戳的日期是没有意义的,因为它本质上映射到特定的毫秒而不是日期。所述毫秒本质上附有一天中的时间,这使其容易受到夏令时和其他日历调整等时区问题的影响。一个有趣的例子见Why is subtracting these two times (in 1927) giving a strange result?

如果你想使用日期而不是毫秒,你需要使用其他东西。对于 Java 8,有一组新方法可以提供您所要求的内容。对于 Java 7 及更早版本,请使用 http://www.joda.org/joda-time/

【讨论】:

  • 注意:那些说“午夜日期”的方法不能很好地处理夏令时和多个时区。
  • 我确认,我在我的应用程序中将日期增加了一天,并通过 DST 时区用户的错误报告了解到这一点(我的国家不使用 DST)。在 DST 开始的那一天,我的应用增加了 11 小时而不是 12 小时。也许使用中午作为“无时间”日期的时间会更好?
  • @Jose_GD 充其量只是一个 hack。您可能会觉得 youtube.com/watch?v=-5wpm-gesOY 很有趣。
  • @Thorbjorn,你说得对,只是想避免使用 JodaTime,因为只为一个功能添加一个库对我来说听起来有点矫枉过正。我知道那个视频,确实很有趣。
  • @Jose_GD 重点是在现实生活中存在一个实际用例,在这种用例中,您的方法将被视为错误。如果你找到了,可能还有更多……我不知道 Joda 是如何处理这个问题的,但你可以看看。另请注意,Java 8 带来了一个新的日期时间库(基于 Joda 的经验),您可能想研究一下。
【解决方案9】:
// 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

【讨论】:

    【解决方案10】:

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

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

    我只需要日期用于视觉目的,而 Joda 不能,所以我添加了字符串。

    【讨论】:

      【解决方案11】:

      如果您只想看到“YYYY-MM-DD”这样的日期,而没有其他所有混乱,例如“2015 年 5 月 21 日星期四 12:08:18 EDT”然后只需使用 java.sql.Date。此示例获取当前日期:

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

      同样java.sql.Datejava.util.Date 的子类。

      【讨论】:

        【解决方案12】:

        好吧,据我所知,如果您只使用标准 JDK,没有更简单的方法可以实现这一点。

        当然,您可以将方法 2 中的逻辑放入辅助类中的静态函数中,例如完成 here in the toBeginningOfTheDay-method

        那么你可以将第二种方法缩短为:

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

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

        【讨论】:

          【解决方案13】:

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

          DateTime.now().withTimeAtStartOfDay()
          

          【讨论】:

          • 该问题要求没有时间。你的结果是一个日期时间对象,它确实有一个时间,那个时间通常是00:00:00(可能因时区而异,例如DST)。因此,正如其他答案所指出的那样,LocalDate 类更合适,来自 Joda-Time(假设您引用 Joda-Time——在引用未与 Java 捆绑的类时,您应该明确指出这一点)。
          【解决方案14】:

          使用LocalDate.now() 并转换为Date,如下所示:

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

          【讨论】:

          • JVM 当前的默认时区可以在运行时随时更改。 JVM 内任何应用程序的任何线程中的任何代码都可以调用TimeZone.setDefault。您的代码调用了两次ZoneId.systemDefault,第一次在LocalDate.now() 中是隐式的,第二次在atStartOfDay 中是显式的。在运行时的这两个时刻之间,当前的默认区域可能会发生变化。我建议将区域捕获到一个变量中,并传递给这两种方法。
          【解决方案15】:

          如果您需要日期部分只是为了回显目的,那么

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

          【讨论】:

          • 我不认为这对 i18n 友好
          【解决方案16】:

          这个怎么样?

          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();
          }
          

          【讨论】:

            【解决方案17】:

            你可以使用joda time。

            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);
            

            【讨论】:

              【解决方案18】:

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

              【讨论】:

                【解决方案19】:

                充分利用Java庞大的TimeZone Database的最直截了当且正确的方式:

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

                【讨论】:

                  【解决方案20】:

                  这是一个干净的解决方案,没有转换为字符串和返回,而且当您将时间的每个组成部分重置为零时,它也不会重新计算多次。它还使用%(模数)而不是先除后乘,以避免双重运算。

                  它不需要第三方依赖,并且它尊重传入的日历对象的时区。此函数返回您传入的日期(日历)的时区中凌晨 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;
                  }
                  

                  【讨论】:

                  • 我不太相信它会尊重夏季时间 (DST)?
                  【解决方案21】:

                  尽量不要使用第三方库。我知道之前提到过这种方式,但这里有一个很好的干净方式:

                    /*
                      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 可能是一种选择!

                  【讨论】:

                    【解决方案22】:

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

                    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,没有外部库。 它尊重日光和默认时区。没有字符串操作,所以我认为这种方式比你的 CPU 效率更高,但我没有进行任何测试。

                    【讨论】:

                      【解决方案23】:

                      我们可以使用 SimpleDateFormat 来设置我们喜欢的日期格式。下面是一个工作示例:-

                      SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
                      System.out.println(dateFormat.format(new Date())); //data can be inserted in this format function
                      

                      输出:

                      15/06/2021
                      

                      【讨论】:

                      • 我们也不能。 SimpleDateFormat 类是一个臭名昭著的类麻烦制造者,所以我们应该避免它。
                      猜你喜欢
                      • 2020-02-23
                      • 1970-01-01
                      • 2012-06-22
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2011-02-17
                      相关资源
                      最近更新 更多