How do I check if request is in between this window? I have a time of request as 2011-12-03T15:15:30-05:00 and a time window which could be defined in any zone, example 09:00:00+00:00 and 17:00:00+00:00.
Now if i parse the datetime to LocalTime i loose the timezone.
public LocalTime time(String time){
return LocalTime.from(DateTimeFormatter.ISO_OFFSET_TIME.parse(time));
}
private ZonedDateTime dateTime(String dateTime){
return ZonedDateTime.from(DateTimeFormatter.ISO_DATE_TIME.parse(dateTime));
}
//Compare function
public boolean compare(ZonedDateTime dateTime, LocalTime localTime, LocalTime localTime2) {
LocalTime time = dateTime.withZoneSameInstant(utc).toLocalTime();
int start = time.compareTo(localTime);
int end = time.compareTo(localTime2);
return start >= 0 && end <= 0;
}
now i invoke the above compare function as:
service.compare(dateTime("2011-12-03T15:15:30-05:00"), time("09:00:00+00:00"), time("17:00:00+00:00"));
Here is example of code that will compare a ZonedDateTime value in any time zone, to see if it falls within a time-of-day window define in another (or same) time zone, correctly adjusting for the time zone difference.
Notice that time window values are now OffsetTime, not LocalTime, so the window time zone offset is known.
Also notice that this code was change to be upper-exclusive, which is generally what you want for range comparisons like this.
public static boolean inWindow(ZonedDateTime dateTime, OffsetTime windowStart, OffsetTime windowEnd) {
if (! windowStart.getOffset().equals(windowEnd.getOffset()))
throw new IllegalArgumentException("windowEnd must have same offset as windowStart");
OffsetTime time = dateTime.toOffsetDateTime()
.withOffsetSameInstant(windowStart.getOffset())
.toOffsetTime();
return (! time.isBefore(windowStart) && time.isBefore(windowEnd));
}
Related
I have a method wherein have to check whether a LocalDate falls in between two java.util.Date values.
there are methods after and before in java.util.Date
and there are methods isAfter and isBefore in LocalDate.
The code snippet which i have is as :
/**
* checks if date passed falls between start & end date
*
* #param date
* #param startDate
* #param endDate
* #return
*/
public static boolean isBetween(Date date, Date startDate, Date endDate) {
return (startDate == null || date.after(startDate) || date.equals(startDate))
&& (endDate == null || date.before(endDate) || date.equals(endDate));
}
There is no method in the API to compare across..
You need to decide on many corner and edge cases. Here’s a shot.
public static boolean isBetween(LocalDate date, Date startDate, Date endDate) {
ZoneId zone = ZoneId.systemDefault();
// Is before start?
if (startDate != null) {
LocalDate startLocalDate = startDate.toInstant().atZone(zone).toLocalDate();
if (date.isBefore(startLocalDate)) {
return false;
}
}
// Is after end?
if (endDate != null) {
LocalDate endLocalDate = endDate.toInstant().atZone(zone).toLocalDate();
if (date.isAfter(endLocalDate)) {
return false;
}
}
// If we end up here, the date is between start and end inclusive
return true;
}
I am assuming that the old-fashioned Date objects are to be interpreted in the default time zone of the JVM. On one hand this is standard, on the other hand the default time zone can be changed at any time, also from other programs running in the same JVM, so this is fragile. I am discarding the time of day part of the thus interpreted date. Whether the time is 00:00 or it’s 23:59:59.999, I deem the LocalDate inside the interval if the date agrees. You may want quite different behaviour.
If you wanted to take the time into account, you should probably convert everything to Instant or ZonedDateTime instead.
As you can see, mixing old-fashioned and modern classes leads to quite some complication. I am converting Date to LocalDate in order to take advantage of java.time, which in turn also gets more complicated since the Dates may be null.
Convert LocalDate to String and convert this String to java.util.Date and you can use your method.
To convert LocalDate to String:
LocalDate localDate = LocalDate.now();
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
String localDateToString = localDate.format(dateFormatter1);
And to convert String to Date:
SimpleDateFormat formatter=new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss");
Date date1=formatter1.parse(sDate1);
Once you've converted LocalDate to Date, you can compare dates using your method.
You will have to convert java.util.Date to LocalDate instances for comparison. Since you have to compare LocalDate with other dates, so losing the time part seems to be a logical compromise here.
public static boolean isBetween(LocalDate localDate, Date start, Date end){
LocalDate startLocalDate = Instant.ofEpochMilli(start.getTime()).atZone(ZoneId.systemDefault()).toLocalDate();
LocalDate endLocalDate = Instant.ofEpochMilli(end.getTime()).atZone(ZoneId.systemDefault()).toLocalDate();
return (localDate.isEqual(startLocalDate) || localDate.isEqual(endLocalDate)) || (localDate.isAfter(startLocalDate) && localDate.isBefore(endLocalDate));
}
I have made the endDate as inclusive upper limit.
I have a long value that represents a datetime like this 20200319234500 (translates into March 19th, 2020 11:45:00PM)
I want this long value (20200319234500) converted into another timezone again in long format so I can do a greater than and less than comparison with the current date time in local timezone.
I want to do it efficiently so I dont have to create any objects during run time or do string creations after the start up.
but it looks like I must first convert long time to a string and then call ZonedDateTime.parse() function to get a datetime and then do a comparison. Is there another way of doing this?
//This is known at compile time
ZoneId baseZone = ZoneId.of("Europe/Paris");
//This is known at compile time
ZoneId localZone = ZoneId.of("America/New_York");
//This is known at compile time
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuuMMddHHmmss").withZone(baseZone);
long baseDateTime = 20210321234500L;
//Dont want o be doing string operations. Is there a way to keep it in long and get another long in a different zone?
ZonedDateTime convertedBaseDateTime = ZonedDateTime.parse(Long.toString(baseDateTime), formatter);
//Can I just get a long that represents current time in local zone? local zone is not JVM zone
ZonedDateTime localDateTime = ZonedDateTime.now(localZone);
//Thats the only operation I want to perform
boolean result = convertedBaseDateTime.isBefore( localDateTime);
You can do some maths to get the year, month, day, hour. minute, second from the long, and then you can pass it to ZonedDateTime.of
long baseDateTime = 20210321234500L;
int year = (int)(baseDateTime / 10000000000L);
int month = (int)(baseDateTime / 100000000L % 100);
int day = (int)(baseDateTime / 1000000L % 100);
int hour = (int)(baseDateTime / 10000L % 100);
int minute = (int)(baseDateTime / 100L % 100);
int second = (int)(baseDateTime % 100);
ZonedDateTime convertedBaseDateTime = ZonedDateTime.of(year, month, day, hour, minute, second, 0, baseZone);
This won't create new strings.
After that, notice that if you just want to check if a date time is before "now", you don't need a zone for "now". You just need to compare the numbers of (milli/nano)seconds since the epoch of then, and now.
// don't need these
// ZoneId localZone = ZoneId.of("America/New_York");
// ZonedDateTime localDateTime = ZonedDateTime.now(localZone);
// you just need to compare
convertedBaseDateTime.toEpochSecond() * 1000 < System.currentTimeMillis()
That said, if performance is so important for you, maybe you shouldn't use Java, and should instead use a more low-level language.
long baseDateTime = 20210321234500L;
LocalDateTime time=LocalDateTime.ofEpochSecond(baseDateTime /1000,0,ZoneOffset.ofHours(8));
//then you can use time2.isAfter() or some other methond to comparable that is link to jdk 8 API .
I have two timestamps 1498329000000 and 1485282600000 in Europe/Brussels-
In which first one exist in Day Light saving and second one is non day light saving
How to get offset in positive or negative (difference) from UTC? i.e either 1hr or 2 hr , based on DST.
With the java.time-API it's quite easy:
public static ZoneOffset getZoneOffset(long epochMillis, String zoneName) {
Instant instant = Instant.ofEpochMilli(epochMillis);
ZonedDateTime zonedDateTime = instant.atZone(ZoneId.of(zoneName));
return zonedDateTime.getOffset();
}
public static void main(String[] args) {
System.out.println(getZoneOffset(1498329000000l, "Europe/Brussels")); // +02:00
System.out.println(getZoneOffset(1485282600000l, "Europe/Brussels")); // +01:00
}
Also have a look at the class ZoneRules which have sone helpful methods for working with timezones and Daylight Savings Time (DST):
boolean isDaylightSavings(Instant instant)
Checks if the specified instant is in daylight savings.
This checks if the standard offset and the actual offset are the same for the specified instant. If they are not, it is assumed that daylight savings is in operation.
This default implementation compares the actual and standard offsets.
Parameters:
instant - the instant to find the offset information for, not null, but null may be ignored if the rules have a single offset for all instants
Returns:
the standard offset, not null
Duration getDaylightSavings(Instant instant)
Gets the amount of daylight savings in use for the specified instant in this zone.
This provides access to historic information on how the amount of daylight savings has changed over time. This is the difference between the standard offset and the actual offset. Typically the amount is zero during winter and one hour during summer. Time-zones are second-based, so the nanosecond part of the duration will be zero.
This default implementation calculates the duration from the actual and standard offsets.
Parameters:
instant - the instant to find the daylight savings for, not null, but null may be ignored if the rules have a single offset for all instants
Returns:
the difference between the standard and actual offset, not null
ZoneOffsetTransition nextTransition(Instant instant)
Gets the next transition after the specified instant.
This returns details of the next transition after the specified instant. For example, if the instant represents a point where "Summer" daylight savings time applies, then the method will return the transition to the next "Winter" time.
Parameters:
instant - the instant to get the next transition after, not null, but null may be ignored if the rules have a single offset for all instants
Returns:
the next transition after the specified instant, null if this is after the last transition
To get the the ZoneRules you can use:
ZoneRules rules = ZoneId.of("Europe/Brussels").getRules();
You can get the timezone offset from UTC in seconds in Brussels timezone of a particular timestamp, using this code snippet:
ZoneId zone = ZoneId.of("Europe/Brussels");
Instant instant = Instant.ofEpochMilli(timestamp);
OffsetDateTime dateTime = OffsetDateTime.ofInstant(instant, zone);
int offsetInSeconds = dateTime.get(ChronoField.OFFSET_SECONDS);
If you want to get it in hours you need to do some more work, and some countries have timezone offsets that are not whole hours.
public static void main(String[] args) {
System.out.println(utcOffsetInHoursInBrussels(1498329000000L));
System.out.println(utcOffsetInHoursInBrussels(1485282600000L));
}
public static int utcOffsetInHoursInBrussels(long timestamp) {
ZoneId zone = ZoneId.of("Europe/Brussels");
Instant instant = Instant.ofEpochMilli(timestamp);
OffsetDateTime dateTime = OffsetDateTime.ofInstant(instant, zone);
int offsetInSeconds = dateTime.get(ChronoField.OFFSET_SECONDS);
if (offsetInSeconds % 3600 == 0) {
return offsetInSeconds / 3600;
} else {
throw new IllegalArgumentException("Offset is not a whole hour");
}
}
Output:
2
1
You don’t necessarily need to go through a ZonedDateTime or OffsetDateTime as in the other answers.
ZoneOffset offset = ZoneId.of("Europe/Brussels")
.getRules()
.getOffset(Instant.ofEpochMilli(1_498_329_000_000L));
Which you prefer is probably a matter of taste.
Oles answer is the best because your simple problem to query the timezone offset for a given instant does not require to use complex types like ZonedDateTime at all.
Java-8 or later (see also Oles answer):
ZoneRules rules = ZoneId.of("Europe/Brussels").getRules();
ZoneOffset offsetDST =
rules.getOffset(Instant.ofEpochMilli(1498329000000L));
System.out.println(offsetDST); // +02:00
ZoneOffset offsetSTD =
rules.getOffset(Instant.ofEpochMilli(1485282600000L));
System.out.println(offsetSTD); // +01:00
Old API (which is surprisingly even the simplest approach):
TimeZone tz = TimeZone.getTimeZone("Europe/Brussels");
System.out.println(tz.getOffset(1498329000000L)); // 7200000 ms
System.out.println(tz.getOffset(1485282600000L)); // 3600000 ms
Using the following block of code I am trying to convert a UTC JODA time to a specified timezone using a string vale, e.g "Asia/Tokyo"
public void handleTimezoneConversion(TimesheetEntry timesheetEntry, String timezone) {
System.out.println("TO :"+timezone);
System.out.println(timesheetEntry.getStartDateTime());
LocalDateTime startDateTime = timesheetEntry.getStartDateTime();
startDateTime.toDateTime(DateTimeZone.forID(timezone));
timesheetEntry.setStartDateTime(startDateTime);
System.out.println(timesheetEntry.getStartDateTime());
LocalDateTime endDateTime = timesheetEntry.getEndDateTime();
endDateTime.toDateTime(DateTimeZone.forID(timezone));
timesheetEntry.setEndDateTime(endDateTime);
}
When i run it the time stays the same evn though there should be a noticeable difference.
Where am I going wrong, are my methods off course completely?
LocalDateTime's toDateTime() method returns a DateTime. In your code, you're calling toDateTime() but discarding the return value. Instead, you'll want to do something like this:
DateTime newDateTime = startDateTime.toDateTime(DateTimeZone.forID(timezone));
I am wondering if there is a way to get current milliseconds since 1-1-1970 (epoch) using the new LocalDate, LocalTime or LocalDateTime classes of Java 8.
The known way is below:
long currentMilliseconds = new Date().getTime();
or
long currentMilliseconds = System.currentTimeMillis();
I'm not entirely sure what you mean by "current milliseconds" but I'll assume it's the number of milliseconds since the "epoch," namely midnight, January 1, 1970 UTC.
If you want to find the number of milliseconds since the epoch right now, then use System.currentTimeMillis() as Anubian Noob has pointed out. If so, there's no reason to use any of the new java.time APIs to do this.
However, maybe you already have a LocalDateTime or similar object from somewhere and you want to convert it to milliseconds since the epoch. It's not possible to do that directly, since the LocalDateTime family of objects has no notion of what time zone they're in. Thus time zone information needs to be supplied to find the time relative to the epoch, which is in UTC.
Suppose you have a LocalDateTime like this:
LocalDateTime ldt = LocalDateTime.of(2014, 5, 29, 18, 41, 16);
You need to apply the time zone information, giving a ZonedDateTime. I'm in the same time zone as Los Angeles, so I'd do something like this:
ZonedDateTime zdt = ldt.atZone(ZoneId.of("America/Los_Angeles"));
Of course, this makes assumptions about the time zone. And there are edge cases that can occur, for example, if the local time happens to name a time near the Daylight Saving Time (Summer Time) transition. Let's set these aside, but you should be aware that these cases exist.
Anyway, if you can get a valid ZonedDateTime, you can convert this to the number of milliseconds since the epoch, like so:
long millis = zdt.toInstant().toEpochMilli();
What I do so I don't specify a time zone is,
System.out.println("ldt " + LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
System.out.println("ctm " + System.currentTimeMillis());
gives
ldt 1424812121078
ctm 1424812121281
As you can see the numbers are the same except for a small execution time.
Just in case you don't like System.currentTimeMillis, use Instant.now().toEpochMilli()
Since Java 8 you can call java.time.Instant.toEpochMilli().
For example the call
final long currentTimeJava8 = Instant.now().toEpochMilli();
gives you the same results as
final long currentTimeJava1 = System.currentTimeMillis();
To avoid ZoneId you can do:
LocalDateTime date = LocalDateTime.of(1970, 1, 1, 0, 0);
System.out.println("Initial Epoch (TimeInMillis): " + date.toInstant(ZoneOffset.ofTotalSeconds(0)).toEpochMilli());
Getting 0 as value, that's right!
You can use java.sql.Timestamp also to get milliseconds.
LocalDateTime now = LocalDateTime.now();
long milliSeconds = Timestamp.valueOf(now).getTime();
System.out.println("MilliSeconds: "+milliSeconds);
To get the current time in milliseconds (since the epoch), use System.currentTimeMillis().
You can try this:
long diff = LocalDateTime.now().atZone(ZoneOffset.UTC).toInstant().toEpochMilli();
Why didn't anyone mentioned the method LocalDateTime.toEpochSecond():
LocalDateTime localDateTime = ... // whatever e.g. LocalDateTime.now()
long time2epoch = localDateTime.toEpochSecond(ZoneOffset.UTC);
This seems way shorter that many suggested answers above...
For LocalDateTime I do it this way:
LocalDateTime.of(2021,3,18,7,17,24,341000000)
.toInstant(OffsetDateTime.now().getOffset())
.toEpochMilli()
I think this is more simpler:
ZonedDateTime zdt = ZonedDateTime.of(LocalDateTime.now(), ZoneId.systemDefault());
Assert.assertEquals(System.currentTimeMillis(), zdt.toInstant().toEpochMilli());
get the millis like System.currentTimeMillis() (from UTC).
There are some methods available that no one has mentioned here. But I don't see a reason why they should not work.
In case of LocalDate, you can use the toEpochDay() method. It returns the number of days since 01/01/1970. That number then can be easily converted to milliseconds:
long dateInMillis = TimeUnit.DAYS.toMillis(myLocalDate.toEpochDays());
Documentation can be found here.
In case of LocalDateTime, you can use the toEpochSecond() method. It returns the number of seconds since 01/01/1970. That number then can be converted to milliseconds, too:
long dateTimeInMillis = TimeUnit.SECONDS.toMillis(myLocalDateTime.toEpochSeconds());
Documentation for that is here.
If you have a Java 8 Clock, then you can use clock.millis() (although it recommends you use clock.instant() to get a Java 8 Instant, as it's more accurate).
Why would you use a Java 8 clock? So in your DI framework you can create a Clock bean:
#Bean
public Clock getClock() {
return Clock.systemUTC();
}
and then in your tests you can easily Mock it:
#MockBean private Clock clock;
or you can have a different bean:
#Bean
public Clock getClock() {
return Clock.fixed(instant, zone);
}
which helps with tests that assert dates and times immeasurably.
Date and time as String to Long (millis):
String dateTimeString = "2020-12-12T14:34:18.000Z";
DateTimeFormatter formatter = DateTimeFormatter
.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ENGLISH);
LocalDateTime localDateTime = LocalDateTime
.parse(dateTimeString, formatter);
Long dateTimeMillis = localDateTime
.atZone(ZoneId.systemDefault())
.toInstant()
.toEpochMilli();
default LocalDateTime getDateFromLong(long timestamp) {
try {
return LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneOffset.UTC);
} catch (DateTimeException tdException) {
// throw new
}
}
default Long getLongFromDateTime(LocalDateTime dateTime) {
return dateTime.atOffset(ZoneOffset.UTC).toInstant().toEpochMilli();
}