Jodatime start of day and end of day
Asked Answered
H

7

51

I want to create an interval between the beginning of the week, and the end of the current week.

I have the following code, borrowed from this answer:

private LocalDateTime calcNextSunday(LocalDateTime d) {
    if (d.getDayOfWeek() > DateTimeConstants.SUNDAY) {
        d = d.plusWeeks(1);
    }
    return d.withDayOfWeek(DateTimeConstants.SUNDAY);
}

private LocalDateTime calcPreviousMonday(LocalDateTime d) {
    if (d.getDayOfWeek() < DateTimeConstants.MONDAY) {
        d = d.minusWeeks(1);
    }
    return d.withDayOfWeek(DateTimeConstants.MONDAY);
}

But now I want the Monday LocalDateTime to be at 00:00:00, and the Sunday LocalDateTime at 23:59:59. How would I do this?

Hafnium answered 5/2, 2012 at 21:41 Comment(1)
It is always a very bad idea to subtract a "small unit" from the end of time intervals. Time intervals have their start included and their end excluded. Checking if a (date)time is included in the interval you do: start <= time && time < end. Otherwise you end up with a small amount of values (actually in the interval) that suddenly get excluded. Think about the last second in your case. 23:59:59.5 is not in that interval. Using small units just makes the number of excluded values small, but doesn't remove the problem. Using the right comparison does.Leonelleonelle
M
25

How about:

private LocalDateTime calcNextSunday(LocalDateTime d) {
    return d.withHourOfDay(23).withMinuteOfHour(59).withSecondOfMinute(59).withDayOfWeek(DateTimeConstants.SUNDAY);
}

private LocalDateTime calcPreviousMonday(final LocalDateTime d) {
    return d.withHourOfDay(0).withMinuteOfHour(0).withSecondOfMinute(0).withDayOfWeek(DateTimeConstants.MONDAY);
}
Mccarter answered 5/2, 2012 at 22:18 Comment(6)
setXxx by convention has no return type in Java so it wouldn't allow chaining. This here reminds of the builder pattern (which originally would not work on an existing object).Duwalt
Indeed. This lets you string the calls together, rather than having them all on different lines, and gets you all the benefits of immutable objects.Wolfish
I think the "pattern" is called "Fluent interface" martinfowler.com/bliki/FluentInterface.html - gives a lot of benefits in readability and clarity in my opinion.Mccarter
I wrote up the "with" verb in 2006 - blog.joda.org/2006/05/immutable-pojos-improving-on_6406.html and updated that in 2011 - blog.joda.org/2011/08/common-java-method-names.html . Immutable setters are very different from normal setters in terms of how you use them (you must use the return value).Alexiaalexin
@Latoyia response is the best answer. This one is correct but has the the worst performance of current answers as it creates many objects in each withXXX method. d.millisOfDay().withMaximumValue(); is the one to accomplish the best posible way.Stumpy
Wouldn't these potentially fail with an exception if the local timezone had a daylight savings time change that prevented the specified times existing?Pickett
A
156

You can use the withTime method:

 d.withTime(0, 0, 0, 0);
 d.withTime(23, 59, 59, 999);

Same as Peter's answer, but shorter.

Alexiaalexin answered 7/2, 2012 at 10:19 Comment(9)
Beginning of the day can also be got with d.withTimeAtStartOfDay()Befriend
withTimeAtStartOfDay() is not available for LocalDateTime, but it is available for DateTimeEliseoelish
+1. One note: LocalDateTime is immutable, so there are no set methods. Instead, this method returns a new instance with the value of millis of day changed. So you have to assign the result to some variable.Plasterboard
Oh, I'm sorry. I have just noticed that I addressed my above note to the author of Joda-Time. Quite confusing. Sorry, sir.Plasterboard
Keep in mind that with this method, you're missing one millisecond of each day. I'd suggest using d.plusDays(1).withTime(0, 0, 0, 0) for the end of that day.Javelin
@Befriend where is withTimeAtStartOfDay()? there is no such in LocalDateTimeBickering
better to use plusDays(1).withTime(0,0,0,0) approach as @Javelin pointed out, as it works with leap seconds, as for 2015-06-30T23:59:60Hartal
Pay attention the daylightsaving. Better to use d.millisOfDay().withMaximumValue();Isothermal
This will throw IllegalInstantException on some instances of daytime saving. Eg, on Lebanon daytime saving occured on March 26th, 2023 at 0:00 and the clocks are then set one hour forward. We can't have DateTime(2023,3,26)withTime(0,0,0,0)Perren
L
100

A simple way is:

d.millisOfDay().withMaximumValue();
Latoyia answered 21/8, 2015 at 6:51 Comment(2)
This should be the accepted answer, as compared with the other answers is the best in terms of performance (less objects created as DateTime is inmutable). The method withMaximunValue Documentation even says is the best way to accomplish what the question is askingStumpy
What is the difference with getMaximumValueOverall?Bustos
M
25

How about:

private LocalDateTime calcNextSunday(LocalDateTime d) {
    return d.withHourOfDay(23).withMinuteOfHour(59).withSecondOfMinute(59).withDayOfWeek(DateTimeConstants.SUNDAY);
}

private LocalDateTime calcPreviousMonday(final LocalDateTime d) {
    return d.withHourOfDay(0).withMinuteOfHour(0).withSecondOfMinute(0).withDayOfWeek(DateTimeConstants.MONDAY);
}
Mccarter answered 5/2, 2012 at 22:18 Comment(6)
setXxx by convention has no return type in Java so it wouldn't allow chaining. This here reminds of the builder pattern (which originally would not work on an existing object).Duwalt
Indeed. This lets you string the calls together, rather than having them all on different lines, and gets you all the benefits of immutable objects.Wolfish
I think the "pattern" is called "Fluent interface" martinfowler.com/bliki/FluentInterface.html - gives a lot of benefits in readability and clarity in my opinion.Mccarter
I wrote up the "with" verb in 2006 - blog.joda.org/2006/05/immutable-pojos-improving-on_6406.html and updated that in 2011 - blog.joda.org/2011/08/common-java-method-names.html . Immutable setters are very different from normal setters in terms of how you use them (you must use the return value).Alexiaalexin
@Latoyia response is the best answer. This one is correct but has the the worst performance of current answers as it creates many objects in each withXXX method. d.millisOfDay().withMaximumValue(); is the one to accomplish the best posible way.Stumpy
Wouldn't these potentially fail with an exception if the local timezone had a daylight savings time change that prevented the specified times existing?Pickett
L
2

With Kotlin you could write an extension function:

fun DateTime.withTimeAtEndOfDay() : DateTime = this.withTime(23,59,59,999)

This would allow you to write:

d.withDayOfWeek(DateTimeConstants.SUNDAY).withTimeAtEndOfDay()
Lacteous answered 13/5, 2020 at 23:55 Comment(0)
C
1

For those coming here looking for the answer for "js-joda", you have two options depending on what you're looking to accomplish

Option 1: You want the start of the day in the same timezone

Since you've chosen to calculate your times based on an instant in time in relation to a timezone, you should use ZonedDateTime:

import { ZonedDateTime, LocalDate, ZoneId, DateTimeFormatter} from "js-joda";
import 'js-joda-timezone';

const nowInNewYorkCity = ZonedDateTime.now(ZoneId.of("America/New_York"))
const startOfTodayInNYC = nowInNewYorkCity.truncatedTo(ChronoUnit.DAYS);
console.log(startOfTodayInNYC.toString()) // Prints "2019-04-15T00:00-04:00[America/New_York]"
// And if you want to print it in ISO format
console.log(startOfTodayInNYC.format(DateTimeFormatter.ISO_INSTANT)) // "2019-04-14T04:00:00Z"

Option 2: You know the exact day that you want to get the time for

Then you can use the following methods off of LocalDate to derive the relative time (i.e. ZonedDateTime) you'd like:

    atStartOfDay(): LocalDateTime
    atStartOfDay(zone: ZoneId): ZonedDateTime
    atStartOfDayWithZone(zone: ZoneId): ZonedDateTime

Option 3: I want just the day the instant occurred on

Notice with this code, you get the day that it would be relative to where you are. So for those in New York City, it's "2019-04-14" and for those in London it would be "2019-04-15" (which is great!) because the instant in time was during the period of time where it's actually tomorrow in London ("2019-04-15T00:00:05Z"). Pretend that you were calling someone in London from NYC, and the Londoner would say, "geez, why are you calling me so early... it's 5 seconds past midnight."

import { ZonedDateTime, LocalDate, ZoneId} from "js-joda";
import 'js-joda-timezone';

const aTimeWhenLondonIsAlreadyInTomorrow = "2019-04-15T00:00:05.000Z";
const inBetweenTimeInLondon = ZonedDateTime.parse(aTimeWhenLondonIsAlreadyInTomorrow);
const inBetweenTimeInNYC = inBetweenTimeInLondon.withZoneSameInstant(ZoneId.of("America/New_York"))
const dayInLondon = inBetweenTimeInLondon.toLocalDate();
const dayInNYC = inBetweenTimeInNYC.toLocalDate();
console.log(inBetweenTimeInLondon.toString()); // "2019-04-15T00:00:05Z"
console.log(dayInLondon.toString()); // "2019-04-15"
console.log(inBetweenTimeInNYC.toString()) // "2019-04-14T20:00:05-04:00[America/New_York]"
console.log(dayInNYC.toString()); // "2019-04-14"

References: https://js-joda.github.io/js-joda/class/src/LocalDate.js~LocalDate.html#instance-method-atStartOfDayWithZone

Coverture answered 24/1, 2019 at 17:5 Comment(0)
E
0
begin = d
    // Go to previous or same Sunday
    .with(TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY))
    // Beginning of day
    .truncatedTo(ChronoUnit.DAYS)

end = d
    // Go to next Sunday
    .with(TemporalAdjusters.next(DayOfWeek.SUNDAY))
    // Beginning of day
    .truncatedTo(ChronoUnit.DAYS)

I also think it is a bad idea to represent the end of week interval with small amount of time before the actual, exclusive end. It is better to treat begin as inclusive, and end as exclusive instead (when doing comparisons etc.).

Exsiccate answered 26/5, 2019 at 7:37 Comment(0)
H
0
DateTime.now().withTimeAtStartOfDay(); // start of day
DateTime.now().plusDays(1).withTimeAtStartOfDay().minusSeconds(1); // end of day
Hessney answered 2/5, 2023 at 7:42 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.