I am trying to convert a date formatted in yyyy-mm-dd to LocalDate to milliseconds with this code.
LocalDate.parse("2022-08-01", DateTimeFormatter.ofPattern("yyyy-MM-dd"))
.atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli()
It returns 1659283200000 which is not correct and behind 1 day. Is there better solution for this? The expected value is 1659312000000 in UTC.
Your code is correct, if you want a count of milliseconds since the epoch reference of first moment of 1970 as seen with an offset of zero hours-minutes-seconds from UTC, 1970-01-01T00:00Z.
By the way, no need to specify a formatting pattern. Your input text complies with the ISO 8601 standard used by default in the java.time classes for parsing/generating text.
long millis =
LocalDate
.parse(
"2022-08-01"
)
.atStartOfDay(
ZoneId.systemDefault()
)
.toInstant()
.toEpochMilli()
;
Time Zone
I imagine the problem with getting an unexpected result is the time zone. Your results will vary by time zone.
Understand that the day starts earlier in the east. At any moment, it can be “tomorrow” in Tokyo Japan 🇯🇵 while still “yesterday” in Edmonton Alberta Canada 🇨🇦 .
(photo: NASA)
👉 To avoid surprises, specify your desired/expected time zone explicitly rather than relying on the JVM’s current default time zone.
Example
Same date used in examples below, for two time zones and one offset.
String input = "2022-08-01" ;
Tokyo
ZoneId zoneIdTokyo = ZoneId.of( "Asia/Tokyo" ) ;
long millisTokyo =
LocalDate
.parse(
input
)
.atStartOfDay(
zoneIdTokyo
)
.toInstant()
.toEpochMilli()
;
Edmonton
ZoneId zoneIdEdmonton = ZoneId.of( "America/Edmonton" ) ;
long millisEdmonton =
LocalDate
.parse(
input
)
.atStartOfDay(
zoneIdEdmonton
)
.toInstant()
.toEpochMilli()
;
UTC (offset of zero)
ZoneOffset offsetUtc = ZoneOffset.UTC ;
long millisUtc =
LocalDate
.parse(
input
)
.atStartOfDay(
offsetUtc
)
.toInstant()
.toEpochMilli()
;
Dump to console.
System.out.println( "Tokyo: " + millisTokyo ) ;
System.out.println( "Edmonton: " + millisEdmonton ) ;
System.out.println( "UTC: " + millisUtc ) ;
See this code run live at Ideone.com.
Tokyo: 1659279600000
Edmonton: 1659333600000
UTC: 1659312000000
Interval
You said:
The input date String should represent the current date and past 30 days which should be based on user's timezone. Example is 2022-07-08 to 2022-08-08
I suggest adding the ThreeTen-Extra library to your project. Doing so gives you access to the Interval class to represent a span of time as a pair of Instant objects.
Interval intervalOfPrior30DaysInUtc ( LocalDate end ) {
return
Interval
.of(
end.minusDays( 30 ).atStartOfDay( ZoneOffset.UTC ).toInstant() ,
end.atStartOfDay( ZoneOffset.UTC ).toInstant()
)
;
}
Related
I can get the current date using
Instant.now()
I am looking to get 18-<current month>-<current year>
I endorse Basil Bourque's answer. However, if you are looking for an Instant object, you can get it by adjusting the current OffsetDateTime at UTC to 18th day of the month as shown below:
public class Main {
public static void main(String[] args) {
Instant thisInstantOn18th = OffsetDateTime.now(ZoneOffset.UTC)
.with(ChronoField.DAY_OF_MONTH, 18)
.toInstant();
System.out.println(thisInstantOn18th);
}
}
Output:
2022-12-18T19:19:20.128313Z
Learn more about the modern Date-Time API from Trail: Date Time.
tl;dr
YearMonth // Represents a year and month only, no day of month.
.now(
ZoneId.of( "America/Edmonton" ) // Returns a `ZoneId` object.
)
.atDay( 18 ) // Returns a `LocalDate` object.
.format(
DateTimeFormatter
.ofPattern( "dd-MM-uuuu" )
) // Returns a `String` object.
Details
As Comments by Ole V.V. explain, you are using the wrong class. No need for Instant here.
To represent a date, use LocalDate.
To represent a year and month, use YearMonth.
Capture the current year-month.
Doing so requires a time zone. For any given moment, the date varies around the globe by time zone. So the current month could be simultaneously “next month” in Tokyo Japan while “last month” in Toledo Ohio.
ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
YearMonth ym = YearMonth.now( z ) ;
If you want the current month as seen with an offset of zero hours-minutes-seconds from UTC, use ZoneOffset.UTC constant.
YearMonth ym = YearMonth.now( ZoneOffset.UTC ) ;
Apply a day of month to get a date.
LocalDate ld = ym.atDay( 18 ) ;
Generate text in standard ISO 8601 format.
String output = ld.toString() ;
Generate text in a specific format.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "dd-MM-uuuu" ) ;
String output = ld.format( f ) ;
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
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);
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();
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 countOfMillisSinceEpoch , final ZoneId zoneId )
{
Objects.requireNonNull( zoneId );
Instant instant = Instant.ofEpochMilli( countOfMillisSinceEpoch );
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.
Tip: ThreeTen-Extra library
If you routinely work with pairs of moments, considering adding the ThreeTen-Extra library to your project. This provides the Interval class for representing a pair of Instant objects. The class carries several handy comparison methods such as abuts, overlaps, contains, and so on.
I want to get the UTC instant (since my DB is storing in UTC) from Java (which is also in UTC) of a particular time zone, this is what I have tried so far:
public static Instant getStartOfTheDayDateTime(Instant instant, String zoneId) {
ZonedDateTime zoned = instant.atZone(ZONE_ID_TO_ZONE_MAP.get(zoneId));
ZoneId zone = ZoneId.of(zoneId);
return zoned.toLocalDate().atStartOfDay(zone).toInstant();
// ZonedDateTime startOfTheDay = zoned.withHour(0)
// .withMinute(0)
// .withSecond(0)
// .withNano(0);
//
// return startOfTheDay.toInstant();
}
public static Instant getEndOfTheDayDateTime(Instant instant, String zoneId) {
ZonedDateTime zoned = instant.atZone(ZONE_ID_TO_ZONE_MAP.get(zoneId));
ZonedDateTime endOfTheDay = zoned.withHour(0)
.withMinute(0)
.withSecond(0)
.withNano(0)
.plusDays(1);
return endOfTheDay.toInstant();
}
Every attempt shows:
2020-04-10 22:00:00.0(Timestamp), 2020-04-11 22:00:00.0(Timestamp)
Is this the start/end of the day UTC time in Europe/Paris zone ?
I was expecting to have 2020-04-11 02:00:00.0(Timestamp), 2020-04-12 02:00:00.0(Timestamp)
Right now, Paris is on summer time: UTC+2. Paris is 'ahead' of UTC by 2 hours.
So 00:00:00 in Paris local time is 22:00:00 UTC.
Is this the start/end of the day UTC time in Europe/Paris zone ?
Yes. Europe/Paris is in daylight savings time. Midnight in Paris occurred at 22:00 UTC time.
I was expecting to have 2020-04-11 02:00:00.0(Timestamp), 2020-04-12 02:00:00.0(Timestamp)
That's not right, 02:00 UTC would have been 04:00 in Paris time.
Ask programmatically if a moment is in DST
Is this the start/end of the day UTC time in Europe/Paris zone ?
Get start of day.
ZoneId z = ZoneId.of( "Europe/Paris" );
ZonedDateTime zdtStartOfDay = instant.atZone( z ).toLocalDate().atStartOfDay( z ) ;
Ask if that moment is in DST for that zone.
ZoneRules rules = z.getRules();
boolean isDst = rules.isDaylightSavings( zdtStartOfDay.toInstant() );
Pass date-time objects rather than mere strings
public static Instant getStartOfTheDayDateTime(Instant instant, String zoneId)
I suggest you ask the calling programmer to pass a valid ZoneId object rather than a mere string. It should not be the job of this method to validate their string input. If it is reasonable to expect a Instant then it is also reasonable to expect a ZoneId.
public static Instant getStartOfTheDayDateTime(Instant instant, ZoneID zoneId )
Half-Open
public static Instant getEndOfTheDayDateTime(Instant instant, String zoneId) {
Trying to determine the last moment of the day is impossible because of infinitely divisible last second.
Also this approach to defining a span of time is awkward. It makes abutting multiple spans tricky. Various software systems and protocols differ in their resolution of that last fractional second, using milliseconds, microseconds, nanoseconds, or some other fraction.
The common practice in date-time handling is to track a span of time using the Half-Open approach. In Half-Open, the beginning is inclusive while the ending is exclusive.
So a full day begins with the first moment of the day and runs up to, but does not include, the first moment of the next day.
ZoneId z = ZoneId.of( "Europe/Paris" );
ZonedDateTime zdtStartOfDay = instant.atZone( z ).toLocalDate().atStartOfDay( z ) ;
ZonedDateTime zdtStartOfNextDay = instant.atZone( z ).toLocalDate().plusDays( 1 ).atStartOfDay( z ) ;
You might want to break that code out to more lines, for easier reading/debugging.
Instant instant = Instant.now() ; // Or passed in.
ZoneId z = ZoneId.of( "Europe/Paris" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
LocalDate ld = zdt.toLocalDate() ;
LocalDate ldNextDay = ld.plusDays( 1 ) ;
ZonedDateTime zdtStartOfNextDay = ldNextDay.atStartOfDay( z ) ;
See this code run live at IdeOne.com. For example:
System.out.println( instant ) ; // 2020-04-13T00:15:25.235341Z
System.out.println( zdt ) ; // 2020-04-13T02:15:25.235341+02:00[Europe/Paris]
System.out.println( ld ) ; // 2020-04-13
System.out.println( ldNextDay ) ; // 2020-04-14
System.out.println( zdtStartOfNextDay ) ; // 2020-04-14T00:00+02:00[Europe/Paris]
ThreeTen-Extra Interval
If you do this kind of work with spans of time often, then I suggest adding the ThreeTen-Extra library to your project. That library includes the Interval class to track a span-of-time as a a pair of Instant objects.
Interval interval = Interval.of( zdtStartOfDay.toInstant() , zdtStartOfNextDay.toInstant() ) ;
You can then make use the several handy comparison methods such as abuts, contains, encloses, intersection, overlaps, and union.
Timestamp
Never use the java.sql.Timestamp class. This class is part of the terrible date-time classes that shipped with the earliest versions of Java. These classes are now legacy, supplanted entirely by the modern java.time classes defined in JSR 310 and built into Java 8 and later.
As of JDBC 4.2 we can exchange java.time objects with a database. Use getObject and setObject and updateObject.
The JDBC spec oddly requires support for OffsetDateTime but not the more commonly used Instant and ZonedDateTime. Your particular driver may support these other types. If not, convert.
Retrieval from database.
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
Instant instant = odt.toInstant() ;
Sending to the database.
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
myPreparedStatement.setObject( … , odt ) ;
I want to create one hour time slots between two date and save all one hour slots with start and end date. How can do it?
For example
start date:08/09/2019 13.00
enddate:08/09/2019 16.00
and ı want to get
08/09/2019 13.00- 08/09/2019 14.00
08/09/2019 14.00- 08/09/2019 15.00
08/09/2019 15.00- 08/09/2019 16.00
Thanks,
java.time
The modern solution uses the java.time classes.
LocalDateTime
Use LocalDateTime to represent a date with time-of-day. Be aware that without a time zone of offset-from-UTC, this type does not represent a moment, is not a point in the timeline.
LocalDateTime start = LocalDateTime.parse( "2019-09-08T13:00:00" ) ;
LocalDateTime stop = LocalDateTime.parse( "2019-09-08T16:00:00" ) ;
Loop, hour by hour
Loop, adding an hour at a time, until past the stopping point.
List< LocalDateTime > slots = new ArrayList<>() ;
LocalDateTime ldt = start ;
while (
ldt.isBefore( stop )
) {
slots.add( ldt ) ;
// Prepare for the next loop.
ldt = ldt.plusHours( 1 ) ;
}
ZonedDateTime
If you want to track actual moments, specify a time zone.
ZoneId z = ZoneId.of( "Africa/Casablanca" ) ;
LocalDateTime ldt = LocalDateTime.parse( "2019-09-08T13:00:00" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ;
Then follow the same logic we saw in code above. Loop hour-by-hour, collecting ZonedDateTime objects.
I need to pass in a Date object into a service which my API is calling. I have the info on the day, month, and year for the Date but also need a timestamp. The service is expecting it in this format:
<date>2015-04-01T00:00:00-05:00</date>
How can I add something to the Date to get this format?
Never use java.util.Date. Supplanted by java.time.Instant.
Get your date portion.
LocalDate ld = LocalDate.of( 2015 , 4 , 1 ) ;
Or use the readable Month enum.
LocalDate ld = LocalDate.of( 2015 , Month.APRIL , 1 ) ;
Get the time of day when the day starts in some particular time zone. Do not assume the day starts at 00:00:00, may be some other time such as 01:00:00. Let java.time figure that out for you.
ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = ld.atStartOfDay( z ) ;
Generate a string in your desired format, a standard ISO 8601 format.
DateTimeFormatter f = DateTimeFormatter.ISO_OFFSET_DATE_TIME ;
String output = zdt.format( f ) ;
To see that moment in UTC, extract a Instant.
Instant instant = zdt.toInstant() ;
Conversion
If you must inter-operate with old code not yet updated for java.time, you can call new conversion methods added to the old classes. These include Date::from( Instant ).
java.util.Date d = java.util.Date.from( instant ) ;
Going the other direction.
Instant instant = d.toInstant() ;
Get back to a time zone other than UTC.
ZonedDateTime zdt = instant.atZone( ZoneId.of( "Pacific/Auckland" ) ) ; // Same moment, different wall-clock time.
Working with dates in Java is an ugly mess, always has been. Date class is mostly deprecated now. I am using LocalDateTime where you can construct it by calling year, month, day, hour, minute, and seconds. Here is what I could come up with:
LocalDateTime ldt = LocalDateTime.of(1997, Month.SEPTEMBER, 2, 1, 23, 0);
ZonedDateTime systemTime = ldt.atZone(ZoneId.systemDefault());
DateTimeFormatter formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME; //Basil's idea
System.out.println(systemTime.format(formatter));
Output:
1997-09-02T01:23:00-05:00
You could use SimpleDateFormat for this.
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
dateFormat.format(new Date());