Wrong Day Of Week from java time api - java

I am using java 8 time API to convert time in milliseconds to date and I am getting wrong day of week from that date.
here is my code -
long millis = 1406865600000L;
LocalDate localDate = LocalDate.ofEpochDay(millis/1000);
DayOfWeek dow = localDate.getDayOfWeek();
System.out.println(dow);
it prints out THURSDAY, while this is date Friday 1 AUG.
Please help.

LocalDate.ofEpochDay() expects day count as its argument, and you're passing second count (which is what you get when dividing millisecond count by 1000).

The Answer by NPE is correct.
Solution code example
Here is code to handle the situation correctly.
If your input number is a number of milliseconds since the epoch of start of 1970 in UTC, then create an Instant.
Instant instant = Instant.ofEpochMilli( 1406865600000L );
Determining a date requires a time zone. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still being “yesterday” in Montréal Québec.
So adjust your Instant into a ZonedDateTime object by applying your desired/expected time zone.
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );
Ask for the day-of-week. Java represents each of the seven days of the week in the enum DayOfWeek.
DayOfWeek dow = zdt.getDayOfWeek();
Ask the DayOfWeek object to translate the name of the day of the week to a human language defined in a Locale.
String output = dow.getDisplayName( TextStyle.FULL_STANDALONE , Locale.CANADA_FRENCH );
Dump to console. Results, at least for America/Montreal, are as you expect, Friday 1 AUG.
System.out.println ( "input: " + input + " | instant: " + instant + " | zdt: " + zdt + " | dow: " + dow + " | output: " + output );
input: 1406865600000 | instant: 2014-08-01T04:00:00Z | zdt: 2014-08-01T00:00-04:00[America/Montreal] | dow: FRIDAY | output: vendredi

Related

Compare ZoneDateTime with different time zones

Hi I've already search for similar questions but without luck.
I'm calling a ws that sends me back a token and when it's valid example:
{
"token": ...,
"notBefore":"Thu 21 Jul 2022 at 10:50:43",
"notOnOrAfter":"Thu 21 Jul 2022 at 12:50:43"
}
I know that this dates are GMT+2 (Rome), now I'm taking the current time and convert the two strings:
ZonedDateTime currentTime = LocalDateTime.now().atZone(ZoneId.of("GMT+2"));
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(token.getTimePattern(), Locale.ENGLISH);
ZonedDateTime tokenNotValidAfter = LocalDateTime.parse(token.getNotOnOrAfter(), dateTimeFormatter).atZone(ZoneId.of("GMT+2"));
ZonedDateTime tokenNotValidBefore = LocalDateTime.parse(token.getNotBefore(), dateTimeFormatter).atZone(ZoneId.of("GMT+2"));
if (!currentTime.isAfter(tokenNotValidBefore) || !currentTime.isBefore(tokenNotValidAfter)) {
throw new CifTokenExpiredException(ExceptionHandlerConfig.CIF_TOKEN_EXPIRED);
}
Now locally everthing is working fine, when i deploy on cloud i get:
ZonedDateTime currentTime = LocalDateTime.now().atZone(ZoneId.of("GMT+2"));
two hours behind.
How can i solve this without adding two hours to currentTime? (doing like this locally will not work)
Regards
GMT+2 is an offset, Middle Europe +1 hour plus 1 hour summer time.
That would go wrong in the coming winter. In fact you are using the incomplete OffsetDateTime, which without Locale is inconclusive for the real Zone.
ZonedDateTime currentTime = ZonedDateTime.now(ZoneId.of("Europe/Rome"));
As you see, no need to revert to LocalDateTime.
Now you can get currentTime.toInstant() for an absolute UTC number.
An Instant is even Comparable, but Before/After is fine.
You assume that before and after limits are also in the Italian time zone, but that may be as it is.
There are some things to consider, because of DST (summer time, daylight savings time):
With a count down ("Still 243 hours till the end") you can get awkward jumps of 1 hour per day.
Twice a year there is the 02:00-03:00 gap or repetition (Western Europe). These stati can be queried.
The answer by Joop Eggen is correct. I'll add some more complete code example.
I suggest you educate the publisher of your data on two points:
Date-time values being exchanged textually should use standard ISO 8601 format rather than inventing a localized format as seen in your case.
Moments (specific points on the timeline) should always be communicated in the context of a time zone or offset. Preferably with an offset of zero hours-minutes-seconds. This implied time zone of Rome is just asking for trouble. Or, if not a moment but a time-of-day that should remain the same even if politicians change the time zone rules, then communicate the intended time zone as another field in the date stream, in Continent/Region format such as Europe/Rome.
I suggest adding the ThreeTen-Extra library to your project. Doing so gives you the Interval class that represents a span of time attached to the timeline as a pair of Instant objects. Handy methods include contains, abuts, overlaps, and more.
String inputBegin = "Thu 21 Jul 2022 at 10:50:43";
String inputEnd = "Thu 21 Jul 2022 at 12:50:43";
Locale locale = Locale.US;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "EEE d MMM uuuu 'at' HH:mm:ss" ).withLocale( locale );
ZoneId zoneId = ZoneId.of( "Europe/Rome" ); // Assumed to be the intended time zone.
LocalDateTime beginLdt = LocalDateTime.parse( inputBegin , f );
LocalDateTime endLdt = LocalDateTime.parse( inputEnd , f );
ZonedDateTime begin = beginLdt.atZone( zoneId );
ZonedDateTime end = endLdt.atZone( zoneId );
Interval whenValid = Interval.of( begin.toInstant() , end.toInstant() );
Instant now = Instant.now();
boolean isValidNow = whenValid.contains( now );
System.out.println( begin + "/" + end );
String message = "Interval: " + whenValid + " contains now: " + now + " = " + isValidNow;
System.out.println( message );
2022-07-21T10:50:43+02:00[Europe/Rome]/2022-07-21T12:50:43+02:00[Europe/Rome]
Interval: 2022-07-21T08:50:43Z/2022-07-21T10:50:43Z contains now: 2022-07-21T21:17:54.458095Z = false
In the cloud time is always considered to be GMT. So the best action is to change ZonedDateTime currentTime = LocalDateTime.now().atZone(ZoneId.of("GMT+2"));
to
ZonedDateTime currentTime = ZonedDateTime.now()

Get the start and end timestamp of the given timestamp in java

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.

Java API to get the start and end detail of Daylight saving time for a particular timezone for a year

So I am using getAvailableZoneIds() method under java.time.ZoneId to fetch a list of available timezones.
I wanted to know if there is a way by which for a specific timezone eg- “America/Chicago” , I can find out the starting and ending date time detail of daylight saving time for a year.
Like when does it start and ends.
Gone though various classes including ZoneId ,ZonedDateTime, ZoneOffset,TimeZone available in java but not able to find any way by which I can fetch this details.
I tried the below code and gives output mentioned below
ZoneId zoneId= ZoneId.of("America/Sao_Paulo");
ZoneRules zoneRules = zoneId.getRules();
System.out.println("previous Transition of DST ==> " + zoneRules.previousTransition(Instant.now()));
System.out.println("next Transition of DST ==> " + zoneRules.nextTransition(Instant.now()));
Output:
previous Transition of DST ==> Transition[Overlap at 2019-02-17T00:00-02:00 to -03:00]
next Transition of DST ==> Transition[Gap at 2019-11-03T00:00-03:00 to -02:00]
But I need to find out for a particular year , what time it starts and what time does it end .
For a particular year, you can give ZoneRules a year as part of specifying a moment. For any given moment, you can ask next or previous ZoneOffsetTransition.
Here is example code for Europe/Sofia time zone.
ZoneId zoneSofia = ZoneId.of( "Europe/Sofia" );
ZoneRules zoneRules = zoneSofia.getRules();
// Pick a moment, arbitrarily.
ZonedDateTime zdt = ZonedDateTime.of( 2019 , 10 , 15 , 10 , 0 , 0 , 0 , zoneSofia );
// Is DST in effect at that moment?
boolean isDst = zoneRules.isDaylightSavings( zdt.toInstant() );
// When are the closest offset transitions, previous (in the past), and next (in the future).
ZoneOffsetTransition previousTransition = zoneRules.previousTransition( zdt.toInstant() );
ZoneOffsetTransition nextTransition = zoneRules.nextTransition( zdt.toInstant() );
// When is the next transition happening in UTC? In Sofia time?
Instant nextTransitionInstant = nextTransition.getInstant(); // An `Instant`` is always in UTC, by definition.
ZonedDateTime nextTransactionZdt = nextTransitionInstant.atZone( zoneSofia ); // Same moment, same point on the timeline, different wall-clock time.
boolean isDstAfterTransition = zoneRules.isDaylightSavings( nextTransactionZdt.toInstant() );
Dump to console.
System.out.println( "zone = " + zoneSofia );
System.out.println( "zdt: " + zdt );
System.out.println( "isDst: " + isDst );
System.out.println( "previousTransition = " + previousTransition );
System.out.println( "nextTransition = " + nextTransition );
System.out.println( "nextTransitionInstant = " + nextTransitionInstant );
System.out.println( "nextTransactionZdt = " + nextTransactionZdt );
System.out.println( "isDstAfterTransition = " + isDstAfterTransition );
zone = Europe/Sofia
zdt: 2019-10-15T10:00+03:00[Europe/Sofia]
isDst: true
previousTransition = Transition[Gap at 2019-03-31T03:00+02:00 to +03:00]
nextTransition = Transition[Overlap at 2019-10-27T04:00+03:00 to +02:00]
nextTransitionInstant = 2019-10-27T01:00:00Z
nextTransactionZdt = 2019-10-27T03:00+02:00[Europe/Sofia]
isDstAfterTransition = false
We can see than the next transition in Europe/Sofia happens at the moment that would look like 4 AM while 3 hours ahead of UTC:
nextTransition = Transition[Overlap at 2019-10-27T04:00+03:00 to +02:00]
…but since we are doing a Daylight Saving Time (DST) “Fall back”, we turn the hands of the clock back to 3 AM to be 2 hours ahead of UTC:
nextTransactionZdt = 2019-10-27T03:00+02:00[Europe/Sofia]
And we can see with isDstAfterTransition that at that moment we are no longer in DST.
Notice how, on this date of the 27th, the people of the the Sofia region experience the hour of 3-4 AM twice. This first 3-4 AM hour is at 3 hours ahead of UTC. The second 3-4 AM hour is at 2 hours ahead of UTC.
And, this means the day of the 27th runs 25 hours long rather than 24.

Generating reports for different time zones in Java

as a part of my requirement,I have to fire a SQL query which takes yesterday's midnight and today's midnight in the respective time zone as input.Is there a way to achieve this?
Use ZonedDateTime:
String DATE_FORMAT = "dd-M-yyyy hh:mm:ss a";
String dateInString = "22-1-2015 10:15:55 AM";
LocalDateTime ldt = LocalDateTime.parse(dateInString, DateTimeFormatter.ofPattern(DATE_FORMAT));
ZoneId singaporeZoneId = ZoneId.of("Asia/Singapore");
System.out.println("TimeZone : " + singaporeZoneId);
//LocalDateTime + ZoneId = ZonedDateTime
ZonedDateTime asiaZonedDateTime = ldt.atZone(singaporeZoneId);
System.out.println("Date (Singapore) : " + asiaZonedDateTime);
ZoneId newYokZoneId = ZoneId.of("America/New_York");
System.out.println("TimeZone : " + newYokZoneId);
ZonedDateTime nyDateTime = asiaZonedDateTime.withZoneSameInstant(newYokZoneId);
System.out.println("Date (New York) : " + nyDateTime);
DateTimeFormatter format = DateTimeFormatter.ofPattern(DATE_FORMAT);
System.out.println("\n---DateTimeFormatter---");
System.out.println("Date (Singapore) : " + format.format(asiaZonedDateTime));
System.out.println("Date (New York) : " + format.format(nyDateTime));
Output is:
TimeZone : Asia/Singapore
Date (Singapore) : 2015-01-22T10:15:55+08:00[Asia/Singapore]
TimeZone : America/New_York
Date (New York) : 2015-01-21T21:15:55-05:00[America/New_York]
---DateTimeFormatter---
Date (Singapore) : 22-1-2015 10:15:55 AM
Date (New York) : 21-1-2015 09:15:55 PM
Use the methods from here to get what you need
Example taken from: Java – Convert date and time between timezone
simply run your cronjob at every hour and generate only the reports in which timezones the day just ended
java.time
Use a driver compliant with JDBC 4.2 or later, running on Java 8 or later, to benefit from use of the modern java.time classes that supplant the troublesome old legacy date-time classes.
Determining "today" and "yesterday" means determining a date. Determining a date requires a time zone. For any given moment, the date varies around the globe by zone.
ZoneId z = ZoneId.of( "America/Montreal" ) ;
LocalDate today = LocalDate.now( z ) ;
LocalDate yesterday = today.minusDays( 1 ) ;
To query for timestamps in the database, we need specific moments. The Question specifies midnight. The term "midnight" is vague. Let's use "first moment of the day" instead.
Never assume the day starts at 00:00:00. Anomalies such as Daylight Saving Time (DST) mean it may start at another time such as 01:00:00. Let java.time determine first moment of the day.
ZonedDateTime start = yesterday.atStartOfDay( z ) ;
Generally, the best approach to defining a span of time is though the Half-Open approach where the beginning is inclusive while the ending is exclusive. So we want to start at first moment of one day and run up to, but not include, the first moment of the next day.
ZonedDateTime stop = today.atStartOfDay( z ) ;
In Half-Open, we do not use the SQL command BETWEEN.
SQL
SELECT * FROM t
WHERE event >= ? AND event < ? ;
Java
myPreparedStatement.setObject( 1 , start ) ;
myPreparedStatement.setObject( 2 , stop ) ;
To retrieve the timestamps, use getObject.
Instant instant = myResultSet.getObject( "event" , Instant.class ) ;
To move from UTC to a zone, apply a ZoneId.
ZonedDateTime zdt = instant.atZone( z ) ;

Converting date time to epoch time losing an hour in Java/scala

I'm trying to convert the date time string 10/10/2015 10:00:00 to the seconds since the unix epoch, which is 1444471200. However, weirdly I'm getting back the value 1444467600 which is actually 10/10/2015 09:00:00. Here's my code:
// using "joda-time" % "joda-time" % "2.9",
// "org.joda" % "joda-convert" % "1.8.1",
import org.joda.time.DateTime
import org.joda.time.format.DateTimeFormat
val dt = DateTime.parse(dateTimeString, DateTimeFormat.forPattern("MM/dd/yyyy HH:mm:ss"))
dt.getMillis / 1000
Where's this hour offset coming from and how can I get rid of it? My local timezone is GMT (which == UTC at the moment anyway)...
Apparently, it's not parsing with GMT/UTC. Just add that to your DateTimeFormat.
DateTimeFormat.forPattern("MM/dd/yyyy HH:mm:ss").withZoneUTC()
java.time
The Answer by Sotirios Delimanolis is correct. Here is the same kind of code for the java.time framework built into Java 8 and later, intended as the successor to Joda-Time.
First we define a formatter. Notice the call-chain, calling withZone to specify the zone by which we want the string parsed. This is not optional, as the input string lacks offset or time zone data.
Then we call the static parse method on ZonedDateTime to actually do the parsing.
Lastly we call the convenience method toEpochSecond to convert this date-time to the number of seconds from the epoch of 1970-01-01T00:00:00Z.
String input = "10/10/2015 10:00:00";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "MM/dd/yyyy HH:mm:ss" ).withZone ( ZoneOffset.UTC );
ZonedDateTime zdt = ZonedDateTime.parse ( input , formatter );
long secondsFromEpoch = zdt.toEpochSecond ();
Dump to console.
System.out.println ( "input: " + input + " | zdt: " + zdt + " | secondsFromEpoch: " + secondsFromEpoch );
input: 10/10/2015 10:00:00 | zdt: 2015-10-10T10:00Z | secondsFromEpoch: 1444471200

Categories

Resources