如何获得一天的开始时间和结束时间?

时间:2012-04-25 01:53:01

标签: java date

如何获取一天的开始时间和结束时间?

像这样的代码不准确:

 private Date getStartOfDay(Date date) {
    Calendar calendar = Calendar.getInstance();
    int year = calendar.get(Calendar.YEAR);
    int month = calendar.get(Calendar.MONTH);
    int day = calendar.get(Calendar.DATE);
    calendar.set(year, month, day, 0, 0, 0);
    return calendar.getTime();
}

private Date getEndOfDay(Date date) {
    Calendar calendar = Calendar.getInstance();
    int year = calendar.get(Calendar.YEAR);
    int month = calendar.get(Calendar.MONTH);
    int day = calendar.get(Calendar.DATE);
    calendar.set(year, month, day, 23, 59, 59);
    return calendar.getTime();
}

毫秒不准确。

18 个答案:

答案 0 :(得分:130)

Java 8


public static Date atStartOfDay(Date date) {
    LocalDateTime localDateTime = dateToLocalDateTime(date);
    LocalDateTime startOfDay = localDateTime.with(LocalTime.MIN);
    return localDateTimeToDate(startOfDay);
}

public static Date atEndOfDay(Date date) {
    LocalDateTime localDateTime = dateToLocalDateTime(date);
    LocalDateTime endOfDay = localDateTime.with(LocalTime.MAX);
    return localDateTimeToDate(endOfDay);
}

private static LocalDateTime dateToLocalDateTime(Date date) {
    return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
}

private static Date localDateTimeToDate(LocalDateTime localDateTime) {
    return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
}

更新:我已将这两种方法添加到我的Java Utility类here

它位于Maven Central Repository:

<dependency>
  <groupId>com.github.rkumsher</groupId>
  <artifactId>utils</artifactId>
  <version>1.3</version>
</dependency>

Java 7及早期


使用Apache Commons

public static Date atEndOfDay(Date date) {
    return DateUtils.addMilliseconds(DateUtils.ceiling(date, Calendar.DATE), -1);
}

public static Date atStartOfDay(Date date) {
    return DateUtils.truncate(date, Calendar.DATE);
}

没有Apache Commons

public Date atEndOfDay(Date date) {
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(date);
    calendar.set(Calendar.HOUR_OF_DAY, 23);
    calendar.set(Calendar.MINUTE, 59);
    calendar.set(Calendar.SECOND, 59);
    calendar.set(Calendar.MILLISECOND, 999);
    return calendar.getTime();
}

public Date atStartOfDay(Date date) {
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(date);
    calendar.set(Calendar.HOUR_OF_DAY, 0);
    calendar.set(Calendar.MINUTE, 0);
    calendar.set(Calendar.SECOND, 0);
    calendar.set(Calendar.MILLISECOND, 0);
    return calendar.getTime();
}

答案 1 :(得分:78)

半开

answer by mprivat是正确的。他的观点是不要试图获得一天的结束,而是要比较“在第二天开始之前”。他的想法被称为“半开放式”方法,其中一段时间​​的开头是包容性的,而结尾是独占的

  • 当前的日期 - 时间框架是Java(java.util.Date/Calendar和Joda-Time)都使用epoch的毫秒数。但在Java 8中,新的JSR 310 java.time。*类使用纳秒分辨率。如果切换到新类,那么基于强制一天中最后一刻的毫秒计数而编写的任何代码都将是不正确的。
  • 如果使用其他分辨率,则比较来自其他来源的数据会出错。例如,Unix库通常使用整秒,而Postgres等数据库将日期时间解析为微秒。
  • 某些夏令时变化发生在午夜,这可能会进一步混淆事情。

enter image description here

Joda-Time 2.3为此目的提供了一种方法,以获取当天的第一时刻:withTimeAtStartOfDay()。同样在java.time中,LocalDate::atStartOfDay

Search StackOverflow for "joda half-open"了解更多讨论和示例。

请参阅Bill Schneider撰写的这篇文章Time intervals and other ranges should be half-open

避免遗留日期时间类

java.util.Date和.Calendar类非常麻烦。避免他们。

使用Joda-Time或最好使用java.time。 java.time框架是非常成功的Joda-Time库的官方继承者。

java.time

java.time框架内置于Java 8及更高版本中。后端移植到Java 6&amp; ThreeTen-Backport项目中的7,在ThreeTenABP项目中进一步适应Android。

InstantUTC中时间轴上的一个时刻,分辨率为nanoseconds

Instant instant = Instant.now();

应用时区以获取某个地区的wall-clock time

ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );

要获得当天的第一时间,请查看LocalDate课程及其atStartOfDay方法。

ZonedDateTime zdtStart = zdt.toLocalDate().atStartOfDay( zoneId );

使用半开放式方法,获得第二天的第一时刻。

ZonedDateTime zdtTomorrowStart = zdtStart.plusDays( 1 );

目前,java.time框架缺少一个Interval类,如下面针对Joda-Time所述。但是,ThreeTen-Extra项目使用其他类扩展了java.time。该项目是未来可能添加到java.time的试验场。其中的课程是Interval。通过传递一对Interval对象构造Instant。我们可以从Instant个对象中提取ZonedDateTime

Interval today = Interval.of( zdtStart.toInstant() , zdtTomorrowStart.toInstant() );

约达时间

更新:Joda-Time项目现在处于维护模式,并建议迁移到 java.time 类。我将这段保留完整的历史记录。

Joda-Time有三个类,以各种方式表示时间跨度:IntervalPeriodDurationInterval具有特定的开始和结束于宇宙的时间轴。这符合我们代表“一天”的需要。

我们调用方法withTimeAtStartOfDay而不是将时间设置为零。由于夏令时和其他异常情况,当天的第一时刻可能不是00:00:00

使用Joda-Time 2.3的示例代码。

DateTimeZone timeZone = DateTimeZone.forID( "America/Montreal" );
DateTime now = DateTime.now( timeZone );
DateTime todayStart = now.withTimeAtStartOfDay();
DateTime tomorrowStart = now.plusDays( 1 ).withTimeAtStartOfDay();
Interval today = new Interval( todayStart, tomorrowStart );

如果必须,您可以转换为java.util.Date。

java.util.Date date = todayStart.toDate();

答案 2 :(得分:25)

在getEndOfDay中,您可以添加:

calendar.set(Calendar.MILLISECOND, 999);

虽然从数学角度讲,除了说“在第二天开始之前”之外,你不能指定一天结束。

所以,不要说if(date >= getStartOfDay(today) && date <= getEndOfDay(today)),而应该说:if(date >= getStartOfDay(today) && date < getStartOfDay(tomorrow))。这是一个更加可靠的定义(您不必担心毫秒精度)。

答案 3 :(得分:7)

java.time

使用Java 8中内置的java.time框架。

import java.time.LocalTime;
import java.time.LocalDateTime;

LocalDateTime now = LocalDateTime.now(); // 2015-11-19T19:42:19.224
// start of a day
now.with(LocalTime.MIN); // 2015-11-19T00:00
now.with(LocalTime.MIDNIGHT); // 2015-11-19T00:00
// end of a day
now.with(LocalTime.MAX); // 2015-11-19T23:59:59.999999999

答案 4 :(得分:2)

最短的答案,因为您的时区是 TZ

LocalDateTime start = LocalDate.now(TZ).atStartOfDay()
LocalDateTime end = start.plusDays(1)

比较使用 isAfter()isBefore() 方法,或者使用 toEpochSecond()toInstant() 方法进行转换。

答案 5 :(得分:2)

使用java8 java.time.ZonedDateTime而不是通过LocalDateTime查找一天开始的其他方法只是将输入ZonedDateTime截断为DAYS:

zonedDateTimeInstance.truncatedTo( ChronoUnit.DAYS );

答案 6 :(得分:2)

对于java 8,以下单行语句正在运行。在这个例子中,我使用UTC时区。请考虑更改您当前使用的TimeZone。

System.out.println(new Date());

final LocalDateTime endOfDay       = LocalDateTime.of(LocalDate.now(), LocalTime.MAX);
final Date          endOfDayAsDate = Date.from(endOfDay.toInstant(ZoneOffset.UTC));

System.out.println(endOfDayAsDate);

final LocalDateTime startOfDay       = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
final Date          startOfDayAsDate = Date.from(startOfDay.toInstant(ZoneOffset.UTC));

System.out.println(startOfDayAsDate);

如果与输出没有时差。尝试:ZoneOffset.ofHours(0)

答案 7 :(得分:1)

另一个不依赖于任何框架的解决方案是:

static public Date getStartOfADay(Date day) {
    final long oneDayInMillis = 24 * 60 * 60 * 1000;
    return new Date(day.getTime() / oneDayInMillis * oneDayInMillis);
}

static public Date getEndOfADay(Date day) {
    final long oneDayInMillis = 24 * 60 * 60 * 1000;
    return new Date((day.getTime() / oneDayInMillis + 1) * oneDayInMillis - 1);
}

请注意,它会返回基于UTC的时间

答案 8 :(得分:1)

Java 8或ThreeTenABP

ZonedDateTime

ZonedDateTime curDate = ZonedDateTime.now();

public ZonedDateTime startOfDay() {
    return curDate
    .toLocalDate()
    .atStartOfDay()
    .atZone(curDate.getZone())
    .withEarlierOffsetAtOverlap();
}

public ZonedDateTime endOfDay() {

    ZonedDateTime startOfTomorrow =
        curDate
        .toLocalDate()
        .plusDays(1)
        .atStartOfDay()
        .atZone(curDate.getZone())
        .withEarlierOffsetAtOverlap();

    return startOfTomorrow.minusSeconds(1);
}

// based on https://stackoverflow.com/a/29145886/1658268

LocalDateTime

LocalDateTime curDate = LocalDateTime.now();

public LocalDateTime startOfDay() {
    return curDate.atStartOfDay();
}

public LocalDateTime endOfDay() {
    return startOfTomorrow.atTime(LocalTime.MAX);  //23:59:59.999999999;
}

// based on https://stackoverflow.com/a/36408726/1658268

我希望能帮助别人。

答案 9 :(得分:1)

private Date getStartOfDay(Date date) {
    Calendar calendar = Calendar.getInstance();
    int year = calendar.get(Calendar.YEAR);
    int month = calendar.get(Calendar.MONTH);
    int day = calendar.get(Calendar.DATE);
    calendar.setTimeInMillis(0);
    calendar.set(year, month, day, 0, 0, 0);
    return calendar.getTime();
    }

private Date getEndOfDay(Date date) {
    Calendar calendar = Calendar.getInstance();
    int year = calendar.get(Calendar.YEAR);
    int month = calendar.get(Calendar.MONTH);
    int day = calendar.get(Calendar.DATE);
    calendar.setTimeInMillis(0);
    calendar.set(year, month, day, 23, 59, 59);
    return calendar.getTime();
    }

calendar.setTimeInMillis(0); 使您的准确度达到毫秒级

答案 10 :(得分:0)

我尝试了这段代码,效果很好!

final ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
final ZonedDateTime startofDay =
    now.toLocalDate().atStartOfDay(ZoneOffset.UTC);
final ZonedDateTime endOfDay =
    now.toLocalDate().atTime(LocalTime.MAX).atZone(ZoneOffset.UTC);

答案 11 :(得分:0)

我知道这有点晚了,但是对于Java 8,如果您使用的是OffsetDateTime(它具有很多优势,例如TimeZone,Nanoseconds等),则可以使用以下代码:

require "colorize"

class Filecalculation

    def initialize
        @books = "You can use this knowledge to create small tools that might help you."
    end

    def calc_1 paragraph            
        word_count = paragraph.strip.squeeze(' ').count(' ') + 1  
        puts "#{word_count} words"   
    end

    def select

        loop do
            puts "# Will we search : Calculation_lines paragraph(1)".cyan
            print "\n>>>>>> ".yellow
            input = gets.chomp
            search_method = "calc_#{input}" #.to_sym

            if (respond_to?(search_method))
                contents = send(search_method, @books)
            else
                puts "exit "
                exit
            end
       end 
    end
end

Filecalculation.new.select

答案 12 :(得分:0)

我对所有解决方案都有一些不便之处,因为我需要 Instant 变量的类型,并且时区总是干扰更改所有内容,因此结合解决方案我发现这是一个不错的选择。

        LocalDate today = LocalDate.now();
        Instant startDate = Instant.parse(today.toString()+"T00:00:00Z");
        Instant endDate = Instant.parse(today.toString()+"T23:59:59Z");

结果就是我们

        startDate = 2020-01-30T00:00:00Z
        endDate = 2020-01-30T23:59:59Z

希望对您有帮助

答案 13 :(得分:0)

我认为最简单的方法是:

// Joda Time

DateTime dateTime=new DateTime(); 

StartOfDayMillis = dateTime.withMillis(System.currentTimeMillis()).withTimeAtStartOfDay().getMillis();
EndOfDayMillis = dateTime.withMillis(StartOfDayMillis).plusDays(1).minusSeconds(1).getMillis();

然后可以根据您对Joda Time的要求,将这些毫秒数转换为Calendar,Instant或LocalDate。

答案 14 :(得分:0)

 //this will work for user in time zone MST with 7 off set or UTC with saving time 

 //I have tried all the above and they fail the only solution is to use some math
 //the trick is to rely on $newdate is time()     //strtotime is corrupt it tries to read to many minds
 //convert to time to use with javascript*1000
 
 $dnol = strtotime('today')*1000;
 $dn = ($newdate*1000)-86400000;
 $dz=$dn/86400000;      //divide into days
 $dz=floor($dz);     //filter off excess time
 $dzt=$dz*86400000;     // put back into days UTC
 $jsDate=$dzt*1+(7*3600000);     // 7 is the off set you can store the 7 in database
 $dzt=$dzt-3600000;      //adjusment for summerTime UTC additional table for these dates will drive you crazy
 //solution get users [time off sets] with browser, up date to data base for user with ajax when they ain't lookin



 <?php
 $t=time();
 echo($t . "<br>");
 echo(date("Y-m-d",$t));
 echo '<BR>'.$dnol;
 echo '<BR>'.$dzt.'<BR>';
 echo(date("Y-m-d",$dzt/1000));      //convert back for php /1000
 echo '<BR>';
 echo(date('Y-m-d h:i:s',$dzt/1000));

 ?>

答案 15 :(得分:0)

以下代码采用 OP 的原始公式,并针对 ms 的不精确性进行了调整:

    private static Date getStartOfDay() {
        Calendar calendar = Calendar.getInstance();
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH);
        int day = calendar.get(Calendar.DATE);
        calendar.set(year, month, day, 0, 0, 0);
        long approximateTimestamp = calendar.getTime().getTime();
        long extraMillis = (approximateTimestamp % 1000);
        long exactTimestamp = approximateTimestamp - extraMillis;
        return new Date(exactTimestamp);
    }

    private static Date getEndOfDay() {
        Calendar calendar = Calendar.getInstance();
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH);
        int day = calendar.get(Calendar.DATE);
        calendar.set(year, month, day, 23, 59, 59);
        long approximateTimestamp = calendar.getTime().getTime();
        long extraMillis = (approximateTimestamp % 1000);
        long exactTimestamp = approximateTimestamp - extraMillis + 999;
        return new Date(exactTimestamp);
    }

与此线程上的许多其他答案不同,它与旧版本的 Java 和 Android API 兼容。

答案 16 :(得分:-2)

public static Date beginOfDay(Date date) {
    Calendar cal = Calendar.getInstance();
    cal.setTime(date);
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);

    return cal.getTime();
}

public static Date endOfDay(Date date) {
    Calendar cal = Calendar.getInstance();
    cal.setTime(date);
    cal.set(Calendar.HOUR_OF_DAY, 23);
    cal.set(Calendar.MINUTE, 59);
    cal.set(Calendar.SECOND, 59);
    cal.set(Calendar.MILLISECOND, 999);

    return cal.getTime();
}

答案 17 :(得分:-3)

我试过这段代码,效果很好! :

Date d= new Date();
GregorianCalendar c = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
String s_d=d.getYear()+"-"+(d.getMonth()+1)+"-"+d.getDay();
DateFormat dateFormat = DateFormat.getDateInstance();
try {
// for the end of day :
c.setTime(dateFormat.parse(s_d+" 23:59:59"));
// for the start of day:
//c.setTime(dateFormat .parse(s_d+" 00:00:00"));
} catch (ParseException e) {
e.printStackTrace();
}