I had a timestamp in Unix with milliseconds, now I need the start of the day and end of the day with milliseconds for the same given timestamp.
Eg: 1637293359000 - Given timestamp
Start of the day to be 1637280000000
End of the day to be 1637323199000
CodePudding user response:
In System default timezone you could try like this
ZoneId zoneId = ZoneId.systemDefault();
long timestamp = 1637293359000L;
LocalDate date = Instant.ofEpochMilli(timestamp).atZone(zoneId).toLocalDate();
LocalDateTime startDay = date.atStartOfDay();
LocalDateTime endDay = date.atTime(LocalTime.MAX);
System.out.println(startDay);
System.out.println(endDay);
long startDayLongValue = startDay.atZone(zoneId).toInstant().toEpochMilli();
long endDayLongValue = endDay.atZone(zoneId).toInstant().toEpochMilli();
System.out.println(startDayLongValue);
System.out.println(endDayLongValue);
CodePudding user response:
We can achieve this using DateTime
import org.joda.time.DateTime;
long timestamp = 1629454215381L;
DateTime dateTime=new DateTime(timestamp );
long StartOfDayMillis = dateTime.withMillis(System.currentTimeMillis()).withTimeAtStartOfDay().getMillis();
long EndOfDayMillis = dateTime.withMillis(StartOfDayMillis).plusDays(1).minusSeconds(1).getMillis();
CodePudding user response:
tl;dr
Here is the complete code to a record representing the day of a specified moment as seen in a particular time zone. A static factory method contains our logic.
package work.basil.example;
import java.time.*;
import java.util.Objects;
public record DayInMillis( long start , long end )
{
public static DayInMillis from ( final long moment , final ZoneId zoneId )
{
Objects.requireNonNull( zoneId );
Instant instant = Instant.ofEpochMilli( moment );
ZonedDateTime zdt = instant.atZone( zoneId );
LocalDate ld = zdt.toLocalDate();
ZonedDateTime start = ld.atStartOfDay( zoneId );
ZonedDateTime end = ld.plusDays( 1 ).atStartOfDay( zoneId );
Instant startInstant = start.toInstant();
Instant endInstant = end.toInstant();
long startMilli = startInstant.toEpochMilli();
long endMilli = endInstant.toEpochMilli();
System.out.println( "instant = " instant );
System.out.println( "zdt = " zdt );
System.out.println( "start/end = " start "/" end );
System.out.println( "startInstant/endInstant = " startInstant "/" endInstant );
System.out.println( "startMilli/endMilli = " startMilli "/" endMilli );
System.out.println( "Duration (not necessarily 24 hours): " Duration.between( startInstant , endInstant ) );
return new DayInMillis( startMilli , endMilli );
}
}
Example usage:
DayInMillis.from( 1_637_293_359_000L , ZoneId.of( "Asia/Tokyo" ) )
When run.
instant = 2021-11-19T03:42:39Z
zdt = 2021-11-19T12:42:39 09:00[Asia/Tokyo]
start/end = 2021-11-19T00:00 09:00[Asia/Tokyo]/2021-11-20T00:00 09:00[Asia/Tokyo]
startInstant/endInstant = 2021-11-18T15:00:00Z/2021-11-19T15:00:00Z
startMilli/endMilli = 1637247600000/1637334000000
Duration (not necessarily 24 hours): PT24H
dayInMillis = DayInMillis[start=1637247600000, end=1637334000000]
Parse count of seconds
Parse your input count of milliseconds since epoch of first moment of 1970 in UTC as a Instant
object.
Instant instant = Instant.ofEpochMilli( 1_637_293_359_000L ) ;
Adjust into time zone
Specify the time zone by which you want to perceive dates.
ZoneId z = ZoneId.of( "America/Edmonton" ) ;
Adjust from UTC (an offset of zero hours-minutes-seconds) to that time zone.
ZonedDateTime zdt = instant.atZone( z ) ;
Get the date
Extract the date-only portion.
LocalDate ld = zdt.toLocalDate() ;
Start of day
Let java.time determine the first moment of the day. Never assume the day starts at 00:00. Some dates in some zones may start at another time such as 01:00.
ZonedDateTime start = ld.atStartOfDay( z ) ;
Half-Open
The last moment of the day is infinitely divisible. For this and other reasons, spans of time are usually best defined using Half-Open approach. In Half-Open, the beginning is inclusive while the ending is exclusive. This means the span of a day starts at the first moment of the day and runs up to, but does not include, the first moment of the following day.
ZonedDateTime end = ld.plusDays( 1 ).atStartOfDay( z ) ;
Now we have the span covered by a pair of ZonedDateTime
objects. But you want to get a count of milliseconds since epoch for both of those.
Tracking count-from-epoch is awkward
Let me say, I do not recommend using a count-since-epoch for time-keeping. The values are inherently ambiguous as to both epoch and granularity. Furthermore, using such counts makes debugging difficult and errors hard to spot, as such values are meaningless to human readers.
ISO 8601
Instead, I suggest communicating such values textually in standard ISO 8601 format. The java.time classes use ISO 8601 formats by default when parsing/generating text.
String outputStart = start.toInstant().toString();
String outputEnd = end.toInstant().toString();
Milliseconds since epoch
But if you insist on the count of milliseconds, first extract Instant
objects from our ZonedDateTime
objects, effectively adjusting to UTC (offset of zero).
Instant startInstant = start.toInstant() ;
Instant endInstant = end.toInstant() ;
Interrogate for a count of milliseconds since epoch.
long startMilli = startInstant.toEpochMilli() ;
long endMilli = endInstant.toEpochMilli() ;
Avoid LocalDateTime
for this problem
Notice that at no point did we use the LocalDateTime
class. That class purposely lacks the context of a time zone or offset-from-UTC. So LocalDateTime
cannot represent a moment, is not a point on the timeline. That makes LocalDateTime
irrelevant to the problem at hand.