I want to compare two different time stamp using System.currentTimeMillis().
Basically I want to check whether the time stamps are within 3 hours range on a particular day.
How to do this?
Considering you have time1 and time2, where time1 <= time2 you can do this:
if (time1 >= time2-(60*60*3*1000)) {
// interval is up to 3 hours
} else {
// interval is more than 3 hours
}
Use Instant to get the time in the epoch and convert it to LocalDateTime to get the information about the day and check, if the first time plus 3 hours is smaller than the second time:
long millis1 = System.currentTimeMillis();
...
long millis2 = System.currentTimeMillis();
Instant instant1 = Instant.EPOCH.plusMillis(millis1);
Instant instant2 = Instant.EPOCH.plusMillis(millis2);
LocalDateTime t1 = LocalDateTime.ofInstant(instant1, ZoneId.systemDefault());
LocalDateTime t2 = LocalDateTime.ofInstant(instant2, ZoneId.systemDefault());
System.out.println("same day: " + (t1.getDayOfYear() == t2.getDayOfYear()));
System.out.println("t1+3h >= t2: " + (t1.plusHours(3).compareTo(t2) >= 0));
Here is a sample program that might help you out. The crux here is the method "findIfDatesWithinThreeHours" which helps whether to find if two instances are three hours apart.
package com.inrvu.adapter;
import java.util.Calendar;
import java.util.Date;
public class Tester {
public static void main(String[] args) {
Date[] dates = getTwoDatesThreeHoursApart();
System.out.println(String.format("%b", findIfDatesWithinThreeHours(dates[0],dates[1])));
dates = getTwoDatesWithinThreeHours();
System.out.println(String.format("%b", findIfDatesWithinThreeHours(dates[0],dates[1])));
}
public static Date[] getTwoDatesThreeHoursApart()
{
Calendar calendar = Calendar.getInstance();
Date date1 = calendar.getTime();
calendar.add(Calendar.HOUR,4);
Date date2 = calendar.getTime();
return new Date[]{date1,date2};
}
public static Date[] getTwoDatesWithinThreeHours()
{
Calendar calendar = Calendar.getInstance();
Date date1 = calendar.getTime();
calendar.add(Calendar.HOUR,3);
Date date2 = calendar.getTime();
return new Date[]{date1,date2};
}
public static boolean findIfDatesWithinThreeHours(Date date1, Date date2) {
// here the time of a single hour is defined as 60*60*1000
System.out.println(date1);
System.out.println(date2);
return Math.abs(date1.getTime()-date2.getTime()) <= 3*60*60*1000;
}
}
Your Question is vague. This might get you pointed in the right direction.
If by "timestamp" you meant a count of milliseconds since the epoch of 1970 UTC, construct an Instant. This class represents a moment on the timeline in UTC with a resolution of nanoseconds (finer than milliseconds).
Instant instant = Instant.ofEpochMilli( millis );
Get current moment.
Instant now = Instant.now();
Calculate three hours.
Instant in3Hours = now.plus( 3 , ChronoUnit.HOURS );
See if your moment lies between now and three hours later.
Boolean contained = ( ( ! instant.isBefore( now ) ) && instant.isBefore( in3Hours ) );
If you meant you want to compare a pair of moments to see if the elapsed time is less than 3 hours, use a Duration. This class represents a span of time in terms of seconds and nanoseconds.
Instant earlierInstant = … ;
Instant laterInstant = … ;
Duration duration = Duration.between( earlierInstant , laterInstant );
if ( duration.isNegative() ) {
… handle error of unexpected data inputs where the second instant is *before* the first instant.
}
… else …
Boolean elapsedUnderThreeHours = ( duration.compareTo( Duration.ofHours( 3 ) ) == -1 );
Related
Introduction
I'm trying to get the difference in seconds from two Epochs
i.e
2019-05-22 18:28:56 -> 1558542536 seconds
2019-07-22 19:00:00 -> 1563814800 seconds
The diff will be: 5,272,264 seconds
This date format comes from a binary file as a String
My code
public static void main(String[] args) throws ParseException
{
String regEpoch = "";
long result = 0;
//System.out.println((fecha = dateFormat.format(date)));
try(RandomAccessFile raf = new RandomAccessFile("binario2.txt", "rw")){
//user inputs a code (for now, doesn't matter if exists or not)
System.out.print("Input a code to look for: ");
String code = scan.next();
while(!code.matches("\\d+"))
{
System.out.println("[ERROR] Only digits accepted");
System.out.print("Input a code to look for: ");
code = scan.next();
}
//Gets the current date in seconds
long getSecs = (new Date().getTime())/1000;
System.out.println("Current tiem in secs: " + getSecs);
//We are "randomly accessing" a binary file. The is no problem here at all. It just works.
//Sets the pointer where I want it, again... this works fine.
raf.seek(27+(80*Integer.parseInt(code)));
//Read the String date correctly, which is 2019-05-22 18:28:56
System.out.println(raf.readUTF());
/*
//Attempt 2
System.out.println(java.time.Instant.ofEpochSecond(Long.parseLong(raf.readUTF())));
Long millis = new SimpleDateFormat("yyyy/MM/ss hh:mm:ss").parse(raf.readUTF()).getTime();
System.out.println(millis);
*/
//Let's try to convert it into seconds... No we can't due to -> Unparseable date: "2019-05-22 18:28:56"
Date dt = dateFormat.parse(raf.readUTF());
long epoch = dt.getTime();
System.out.println("Result is: " + (int)(epoch*1000));
}catch(IOException e){System.out.println("[ERROR] " + e);}
}
Problem
I have read many questions in how to turn seconds into Epoch, but what about the reverse?
Do I have to do it manually?
Is there any library I haven't heard of?
So far what I tried only gets the seconds from the Date with SimpleDateFormat but those are not what I expected...
What do I expect from this
I am currently doing homework and I have been task with calculating the price for a parking ticket and I thought, what if the car doesn't leave, let's say... in a week?
If I work only in the format of hh:mm:ss those cars who stay there a whole week will only pay for one day.
ChronoUnit
I always use ChronoUnit for calculations like this. Works fine.
package test;
import java.text.ParseException;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
public class Test2 {
public static void main(String[] args) throws ParseException {
LocalDateTime date1 = LocalDateTime.parse("2019-05-22T18:58:56");
LocalDateTime date2 = LocalDateTime.parse("2019-05-23T19:00:00"); //LocalDateTime.now();
long seconds = ChronoUnit.SECONDS.between(date1, date2);
System.out.println(seconds);
}
}
Output
86464
For converting to date with SimpleDateFormat, you can see e.g. Java time since the epoch
Duration
Let java.time classes calculate a Duration.
Parse your input after adjusting to standard ISO 8601 format.
LocalDateTime ldtStart = LocalDateTime.parse( "2019-05-22 18:28:56".replace( " " , "T" ) ) ;
Time zone
Specify the time zone, to account for anomalies such as Daylight Saving a Time (DST). Days are not always 24 hours long.
ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdtStart = ldtStart.atZone( z ) ;
Calculate a duration.
Duration d = Duration.between( zdtStart , zdtStop ) ;
long seconds = d.toSeconds() ; // Or `getSeconds` before Java 9.
For parking charges, you more likely want hours.
long hours = d.toHours() ;
This should work
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2019-05-22 18:28:56").getTime();
I have a Kotlin function to get the total number of weeks in a month
Code
fun getTotalWeeksInMonth(instant: Instant): Int {
val calendar = Calendar.getInstance()
calendar.time = Date.from(instant)
return calendar.getActualMaximum(Calendar.WEEK_OF_MONTH)
}
However this is using a mix of the old Java date/time APIs (Date and Calendar) and the new APIs (Instant)
How would I achieve the same result, using just the new APIs?
You can try something like this pair of lines:
YearMonth currentYearMonth =
YearMonth.now(
ZoneId.systemDefault()
)
;
int weeks =
currentYearMonth
.atEndOfMonth()
.get(
WeekFields.ISO.weekOfMonth()
)
;
You can evaluate the "week of month" of last day of this month, in java:
static int getTotalWeeksInMonth(Instant instant) {
LocalDate localDate = LocalDate.ofInstant(instant, ZoneId.systemDefault());
LocalDate lastDayOfMonth = localDate.withDayOfMonth(localDate.lengthOfMonth());
int lastWeekOfMonth = lastDayOfMonth.get(WeekFields.ISO.weekOfMonth());
return lastWeekOfMonth;
}
See if this fits you, be careful about what Zone you are actually passing, and about WeekFields.ISO, in some regions it may work fine, but in others it may not:
Instant now = Instant.now();
ZonedDateTime zonedNow = now.atZone(ZoneId.systemDefault());
ZonedDateTime monthEnd = zonedNow.with(TemporalAdjusters.lastDayOfMonth());
System.out.println(monthEnd.get(WeekFields.ISO.weekOfMonth()));
Having an Instant I would convert it to date first:
val date = LocalDateTime.ofInstant(instant, ZoneId.systemDefault())
Then go with either
YearMonth.from(date).atEndOfMonth().get(ChronoField.ALIGNED_WEEK_OF_MONTH)
or
YearMonth.from(date).atEndOfMonth().get(WeekFields.ISO.weekOfMonth())
Complete example:
fun getTotalWeeksInMonth(instant: Instant): Int {
val date = LocalDateTime.ofInstant(instant, ZoneId.systemDefault())
return YearMonth.from(date).atEndOfMonth().get(ChronoField.ALIGNED_WEEK_OF_MONTH)
}
In my application one of third party API returning timestamp in epoch.
Sometime it returns epoch time in seconds and sometime in miliseconds not confirmed. My application using below code to
convert it to java date and display to user but when I am receiving time in miliseconds it is failing on year.
String time = "1519377196185"; //Time in miliseconds
//String time = "1521575819"; //Time in seconds.
String timeZone = "US/Pacific";
long epochdate = Long.parseLong(time);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd, yyyy hh:mm a");
LocalDateTime date34 =
Instant.ofEpochSecond(epochdate)
.atZone(ZoneId.of(timeZone))
.toLocalDateTime();
String date = date34.format(formatter).toString();
System.out.println("date : " + date);
if I use Instant.ofEpochMilli(epochdate) for miliseconds then it is working fine. So my question is how I can know that coming timestamp is in miliseconds or seconds so on that basis I will switch between ofEpochMilli and ofEpochSecond
Year Offset
I would try to parse first the date as seconds, given that if the date is in millis the year would be something extremely big (in this case 50000), then if the year is not greater than the year defined offset (e.g. 3000), that date is returned, otherwise the date is returned as millis.
public ZonedDateTime getZonedDateTime(String time) {
long longTime = Long.parseLong(time), yearOffset = 3000L;
String timeZone = "US/Pacific";
ZoneId zoneId = ZoneId.of(timeZone);
ZonedDateTime zdt = Instant.ofEpochSecond(longTime).atZone(zoneId);
if (zdt.getLong(ChronoField.YEAR_OF_ERA) >= yearOffset) {
return Instant.ofEpochMilli(longTime).atZone(zoneId);
} else {
return zdt;
}
}
Using the functions prints:
getZonedDateTime("1519377196185"); // 2018-02-23T01:13:16.185-08:00[US/Pacific]
getZonedDateTime("1521575819"); // 2018-03-20T12:56:59-07:00[US/Pacific]
Margin of Error
Any method that you decide to use, would have the possibility of an error and that the date is transformed incorrectly, specially when the date is in milliseconds and is too close of the epoch 1970-01-01T00:00:00Z.
The margin errors using the year offset of 3000 would be:
When the date is originally in milliseconds in the range from 1970-01-01T00:00:00Z until 1971-01-12T04:48:00Z
Would be considered as date in seconds
When the date is originally in seconds and the date is equal or after 3000-01-01T00:00:00Z (improbable date in normal apps)
Would be considered as date in milliseconds
Calculate the range of error in milliseconds dates
You can calculate the range of error for dates originally in milliseconds with:
Instant.ofEpochMilli(LocalDateTime.of(3000, 1, 1, 0, 0) // year = 3000
.toEpochSecond(ZoneOffset.UTC)); // 1971-01-12T04:48:00Z
One easy (temporary, sort of) solution would be to just check the length of your time String. If the length is equal to 13, then it represents milliseconds. This will be true until 1 ms after 2286-11-20T17:46:39.999Z, which is a long time from now. The time in seconds would take even more time to reach a length of 13.
Inspect length of String input
As stated by Jacob G. his Answer, check the length.
String input = "1519377196185"; // Milliseconds since epoch.
//String input = "1519377196" ; // Seconds since epoch.
Instant instant = null;
int length = input.length();
switch ( length )
{
case 13:
instant = Instant.ofEpochMilli( Long.parseLong( input ) );
break;
case 10:
instant = Instant.ofEpochSecond( Long.parseLong( input ) );
break;
default:
throw new IllegalStateException( "Unexpected length of input text for count-from-epoch number: " + input + ". Message # 2188d054-5720-4393-9b18-829913d7ba1c." );
}
System.out.println( input + " ➞ " + instant.toString() ); // Generate a String representing textually the value of the `Instant` object.
1519377196185 ➞ 2018-02-23T09:13:16.185Z
Or:
1519377196 ➞ 2018-02-23T09:13:16Z
ZonedDateTime
To move from UTC in an Instant to some particular time zone, provide the context of a time zone (ZoneId) to get a ZonedDateTime object.
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
zdt.toString(): 2018-02-23T10:13:16.185+01:00[Africa/Tunis]
LocalDateTime - not appropriate here
The LocalDateTime class is the wrong class to use, as seen in the Question. This class purposely lacks any concept of time zone or offset-from-UTC. So it does not represent a moment, and is not a point on the timeline. This class represents potential moments along a range of about 26-27 hours.
Use LocalDateTime only when the zone/offset is unknown (a terrible situation) or when you need an indefinite value such as “Christmas starts on first moment of December 25, 2018”.
You can solve this other way by converting epoch in seconds to epoch in milliseconds and apply only Instant.ofEpochMilli() for both:
String time = "1519377196185"; //Time in miliseconds or seconds
if(time.length() == 10) { // length of epoch in seconds is 10
time = time + "000";
}
String timeZone = "US/Pacific";
long epochdate = Long.parseLong(time);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd, yyyy hh:mm a");
LocalDateTime date34 = Instant.ofEpochMilli(time)
.atZone(ZoneId.of(timeZone))
.toLocalDateTime();
String date = date34.format(formatter).toString();
System.out.println("date: " + date);
I actually have found the last three dates and what I want to do is subtract 5 hours and 45 minutes from each date. How can implement it?
The code I have done so far is:
public static List<Date> getPastThreeDays() {
List<Date> pDates = new ArrayList<Date>();
for (int i = 1; i <= 3; i++) {
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DATE, -i);
Date date = cal.getTime();
String pastDate = sdf.format(date);
Date pstThreesDates;
try {
pstThreesDates = sdf.parse(pastDate);
pDates.add(pstThreesDates);
} catch (ParseException e) {
e.printStackTrace();
}
}
return pDates;
}
public static void main(String[] args) throws ParseException {
// for getting past three dates
System.out.println("-----Formatted Past Three Days-----");
List<Date> pastThreeDatesList = getPastThreeDays();
for (Date date : pastThreeDatesList) {
System.out.println("Orignal:" + date);
}
You can use the API DateTime from JodaTime and make something like this:
Date date = new Date();
DateTime dateTime = new DateTime(date);
DateTime newDateTime = dateTime.minusHours(5).minusMinutes(45);
How about stay out of dependencies?
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DATE, -i);
Calendar calLess5_45 = Calendar.getInstance();
calLess5_45.setTimeInMillis(cal.getTimeInMillis() - (1000*60*45) - (1000*60*60*5));
or with Date:
Date initialDate = cal.getTime();
Date dateLess5_45 = new Date(initialDate.getTime() - (1000*60*45) - (1000*60*60*5));
convert the date into milliseconds then substract the 5hr 45min from it as follows:
public static void main(String[] args) {
System.out.println("-----Formatted Past Three Days-----");
List<Date> pastThreeDatesList = getPastThreeDays();
for (Date date : pastThreeDatesList) {
System.out.println("Orignal:"+date);
long mDateMills= date.getTime() - ((5*3600 *1000)+ 45*60*1000); //you convert your date to millisecond then subtract 5h45min( in milliseconds from it)
String mNewDate= millsToDateFormat(mDateMills);
System.out.println("new Date:"+mNewDate);
}
}
public static String millsToDateFormat(long mills) {
Date date = new Date(mills);
DateFormat formatter = new SimpleDateFormat("HH:mm:ss");
String dateFormatted = formatter.format(date);
return dateFormatted;
}
java.time
The troublesome old date-time classes are now legacy, supplanted by the java.time classes.
A time zone is crucial in determining a date and in adding subtracting days. The date, and length of day, varies around the globe by zone.
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdtNow = ZonedDateTime.now( z );
Subtract a day. Accounts for anomalies such as Daylight Saving Time.
ZonedDateTime zdtYesterday = zdtNow.minusDays( 1 );
Subtract a duration of five hours and forty-five minutes.
Duration d = Duration.ofHours( 5 ).plusMinutes( 45 ); // or Duration.parse( "PT5H45M" ) in standard ISO 8601 string format.
ZonedDateTime zdtEarlier = zdtYesterday.minus( d ) ;
I am writing a program to produce a timestamp for every minute of every hour for a whole day.
I am using the Calendar class to get the timestamp, I have to use it so no point in suggesting other methods.
My idea to produce the file was to have a for loop for 24 hours and a nested for loop of 60 minutes in which the timestamp would be printed to the .dat file. I thought this would work and would print the data for the whole day and then stop.
However I was wrong, totally wrong!
The result is data being printed for every minute upto a date 2 years from now.
Here is my code so far;
public static void main (String [] args) throws FileNotFoundException
{
try
{
DateFormat df = new SimpleDateFormat("dd-MM-yyyy");
Date date = new Date();
File fileName = new File(df.format(date) + ".dat");
RandomAccessFile raf = new RandomAccessFile(fileName, "rw");
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
cal.add(Calendar.MILLISECOND, -cal.get(Calendar.MILLISECOND));
cal.add(Calendar.SECOND, -cal.get(Calendar.SECOND));
cal.add(Calendar.MINUTE, -cal.get(Calendar.MINUTE));
cal.add(Calendar.HOUR_OF_DAY, -cal.get(Calendar.HOUR_OF_DAY));
for(int hourInMinutes = 0; hourInMinutes < 1440; hourInMinutes++) //1440 is the total minutes in a day
{
for(int minute = 0; minute <= hourInMinutes; minute++)
{
raf.writeLong(cal.getTimeInMillis()); //Timestamp
cal.add(Calendar.MINUTE, 1);
}
}
raf.close();
}
catch(IOException iOE)
{
System.err.println(iOE);
}
}
The data starts at midnight (last night) and I want it to stop producing data at 11.59pm on the same day.
Anyone have any knowledge on how this is done?
Your for loop looks wrong, here is the updated version:
for(int hourInDay = 0; hourInDay < 24; hourInDay++)
{
for(int minute = 0; minute <= 59; minute++)
{
raf.writeLong(cal.getTimeInMillis());
cal.add(Calendar.MINUTE, 1);
}
}
Or you can get rid of an inner for loop (which has totally wrong second condition) and use the following version:
for(int minutesInDay = 0; minutesInDay < 1440; minutesInDay++) //1440 is the total minutes in a day
{
raf.writeLong(cal.getTimeInMillis());
cal.add(Calendar.MINUTE, 1);
}
And try to give distinct names to your variables. hourInMinutes sounds for me like "the number of hours in one minute". Obviously, it's not what this variable stands for.
You should throw out your inner loop:
for(int hourInMinutes = 0; hourInMinutes < 1440; hourInMinutes++) //1440 is the total minutes in a day
{
raf.writeLong(cal.getTimeInMillis()); //Timestamp
cal.add(Calendar.MINUTE, 1);
}
As you already loop every minute in a day, you shouldn't have a inner loop, that's all.
I prefer quartz-scheduler will be the best one to schedule a task for hour convenience
java.time
You are using old outmoded classes, now supplanted by java.time classes.
Time zone is crucial to determining a date and therefore the hours of that day. For any given moment the date varies around the globe by zone. Specify a ZoneId object.
ZoneId zoneId = ZoneId.of ( "America/Montreal" );
ZonedDateTime
Use that time zone to get the current moment in a ZonedDateTime object.
ZonedDateTime now = ZonedDateTime.now ( zoneId );
Get the date-only value (LocalDate) for use in naming the file.
String filename = now.toLocalDate().toString();
To get the first moment of the day, let java.time determine the value. The day does not always start at 00:00:00 in some time zones because of Daylight Saving Time (DST) or other anomalies. To get first moment, we go through the LocalDate class briefly.
ZonedDateTime start = now.toLocalDate ().atStartOfDay ( zoneId );
For there we loop every hour until reaching the next day. Secondarily loop each minute of the hour until reaching the next hour. We soft-code the loops to test going past the limits rather than hard-code a number of hours or a number of minutes. Anomalies such as Daylight Saving Time (DST) can shift the clock by hours or by minutes. For example, a 30-minute change in Venezuela in 2007.
ZonedDateTime nextDay = start.plusDays ( 1 );
ZonedDateTime zdt = start;
while ( zdt.isBefore ( nextDay ) ) {
ZonedDateTime zdtMinute = zdt;
ZonedDateTime zdtNextHour = zdtMinute.plusHours ( 1 );
while ( zdtMinute.isBefore ( zdtNextHour ) ) {
System.out.println ( zdtMinute.toString () );
// Prepare for next loop.
zdtMinute = zdtMinute.plusMinutes ( 1 );
}
// Prepare for next loop.
zdt = zdt.plusHours ( 1 );
}
When run.
2016-08-12T00:00-04:00[America/Montreal]
2016-08-12T00:01-04:00[America/Montreal]
2016-08-12T00:02-04:00[America/Montreal]
2016-08-12T00:03-04:00[America/Montreal]
…
2016-08-12T23:58-04:00[America/Montreal]
2016-08-12T23:59-04:00[America/Montreal]
Instant
If you want generic 24-hour days and 60-minute hours, instead of ZonedDateTime, use the Instant class as it is always in UTC by definition.