Adding days to Epoch time [Java] [duplicate] - java

This question already has answers here:
Get java.util.Calendar from days since epoch
(3 answers)
Closed 6 years ago.
Epoch time is the number of milliseconds that have passed since 1st January 1970, so if i want to add x days to that time, it seems natural to add milliseconds equivalent to x days to get the result
Date date = new Date();
System.out.println(date);
// Adding 30 days to current time
long longDate = date.getTime() + 30*24*60*60*1000;
System.out.println(new Date(longDate));
it gives the following output
Mon Dec 26 06:07:19 GMT 2016
Tue Dec 06 13:04:32 GMT 2016
I know i can use Calendar class to solve this issue, but just wanted to understand about this behaviour

Its Because JVM is treating Value of multiplication 30*24*60*1000 as Int And multiplication result is out of range of Integer it will give result : -1702967296 intends of 2592000000 so its giving date smaller then current date
Try Below code :
public class Test {
public static void main(final String[] args) {
Date date = new Date();
System.out.println(date);
// Adding 30 days to current time
System.out.println(30 * 24 * 60 * 60 * 1000); // it will print -1702967296
long longDate = (date.getTime() + TimeUnit.DAYS.toMillis(30));
System.out.println(TimeUnit.DAYS.toMillis(30));
date = new Date(longDate);
System.out.println(date);
}
}

You're hitting integer overflow with your number. 30*24*60*60*1000 = 2,592,000,000, which is bigger than a signed, 32-bit integer can hold (2,147,483,647).
Use longs instead, by appending L onto any of the numbers: 1000L, for instance.
Note that if you want to deal with daylight savings time (to say nothing of leap seconds!), this still won't be enough. But if you're willing to assume that a day is always exactly 24 hours, using longs will fix your problem. (Time is a complicated thing, and I would suggest using a library like joda or Java 8's classes to handle it for you!)

Edit your code as follows:
long longDate = date.getTime() + 30*24*60*60*1000L;
It will work for sure.

Try this:
DateTime timePlusTwoDays = new DateTime().plusDays(days);
long longDate = timePlusTwoDays.getTime();
System.out.println(new Date(longDate));
Dateime class has:
public DateTime plusDays(int days) {
if (days == 0) {
return this;
}
long instant = getChronology().days().add(getMillis(), days);
return withMillis(instant);
}

Related

Issues Converting String dates into Long values and performing calculations

I have a map of string values which represent down times for different components.
dependencyMap.put ("sut", "14:26:12,14:27:19,00:01:07;15:01:54,15:02:54,00:01:00;15:44:30,15:46:30,00:02:00;16:10:30,16:11:30,00:01:00");
dependencyMap.put ("jms", "14:26:12,14:28:12,00:02:00;15:10:50,15:12:55,00:02:05;15:42:30,15:43:30,00:01:00;16:25:30,16:27:30,00:02:00");
The strings represent the start, end and duration of down times.
(start)14:26:12,(end)14:27:19,(duration)00:01:07
I read the values in, then add them to a list of DependencyDownTime objects which hold the Long values startTime, endTime and duration.
jArray.forEach (dependency ->{
String downTimeValues = knownDowntimesMap.get(dependency);
final String[] downtime = downTimeValues.split (";");
for (final String str : downtime) {
final DependencyDownTime depDownTime = new DependencyDownTime ();
final String[] strings = str.split (",");
if (strings.length == 3) {
final DateFormat dateFormat = new SimpleDateFormat ("HH:mm:ss");
try {
depDownTime.setStartTime(dateFormat.parse (strings[0]).getTime ());
depDownTime.setEndTime (dateFormat.parse (strings[1]).getTime ());
depDownTime.setDuration (dateFormat.parse (strings[2]).getTime ());
downTimes.add (depDownTime);
} catch (final ParseException e) {
//logger.warn (e.getMessage (), e);
}
} else {
//logger.warn ("");
}
}
I then perform simple arithmetic on the values, which calculates the total down time for each component.
// sort the list by start time
Collections.sort(downTimes, Comparator.comparing (DependencyDownTime::getStartTime));
int i = 1;
Long duration = 0L;
for(DependencyDownTime dts: downTimes){
Long curStart = dts.getStartTime ();
Long curEnd = dts.getEndTime();
Long nextStart = downTimes.get(i).getStartTime ();
Long nextEnd = downTimes.get(i).getEndTime ();
if(duration == 0){
duration = dts.getDuration();
}
if(curStart.equals(nextStart) && curEnd < nextEnd){
duration += (nextEnd - curEnd);
}
else if(nextStart > curEnd){
duration += downTimes.get(i).getDuration();
}
else if( curStart < nextStart && curEnd > nextStart){
duration += (nextEnd - curEnd);
}
else if(curEnd == nextStart){
duration += downTimes.get(i).getDuration();
}
i++;
if(i == downTimes.size ()){
componentDTimeMap.put (application, duration);
return;
}
The expected values should be something like 1970-01-01T 00:14:35 .000+0100, a matter of minutes. The actual result is usually extremely high off by a matter of hours in the difference 1969-12-31T 15:13:35 .000+0100
I have 2 questions.
Am I parsing the values correctly?
If my calculations are a little off when adding and subtracting the long values. When I convert the values back to Date format will there be a drastic difference in the expected value?
As explained in your other question, don't mistake those 2 different concepts:
a time of the day: it represents a specific point of a day, such as 10 AM or 14:45:50
a duration: it represents an amount of time, such as "1 hour and 10 minutes" or "2 years, 3 months and 4 days". The duration doesn't tell you when it starts or ends ("1 hour and 10 minutes" relative to what?), it's not attached to a chronology, it doesn't correspond to a specific point in the timeline. It's just the amount of time, by itself.
In your input, you have:
(start)14:26:12,(end)14:27:19,(duration)00:01:07
The start and end represents times of the day, and the duration represents the amount of time. SimpleDateFormat is designed to work with dates and times of the day, but not with durations. Treating the duration as a time of the day might work, but it's a hack as explained in this answer.
Another problem is that when SimpleDateFormat parses only a time, it defaults the day to January 1st 1970 at the JVM default timezone, leading to all the strange results you see. Unfortunately there's no way to avoid that, as java.util.Date works with full timestamps. A better alternative is to use the new date/time API.
As in your other question you're using Java 8, I'm assuming you can also use it here (but if you're using Java <= 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. The only difference is the package names (in Java 8 is java.time and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp), but the classes and methods names are the same).
As you're working only with times, there's no need to consider date fields (day/month/year), we can use a LocalTime instead. You can parse the strings directly, because they are in ISO861 compliant format:
LocalTime start = LocalTime.parse("14:26:12");
LocalTime end = LocalTime.parse("14:27:19");
Unfortunately there are no built-in parsers for a duration, so you'll have to parse it manually:
// parse the duration manually
String[] parts = "00:01:07".split(":");
Duration d = Duration
// get hours
.ofHours(Long.parseLong(parts[0]))
// plus minutes
.plusMinutes(Long.parseLong(parts[1]))
// plus seconds
.plusSeconds(Long.parseLong(parts[2]));
Another alternative is to remove the durations from your input (or ignore them) and calculate it using the start and end:
Duration d = Duration.between(start, end);
Both will give you a duration of 1 minute and 7 seconds.
My suggestion is to change the DependencyDownTime to store start and end as LocalTime objects, and the duration as a Duration object. With this, your algorithm would be like this:
Duration total = Duration.ZERO;
for (...) {
LocalTime curStart = ...
LocalTime curEnd = ...
LocalTime nextStart = ...
LocalTime nextEnd = ...
if (total.toMillis() == 0) {
duration = dts.getDuration();
}
if (curStart.equals(nextStart) && curEnd.isBefore(nextEnd)) {
total = total.plus(Duration.between(curEnd, nextEnd));
} else if (nextStart.isAfter(curEnd)) {
total = total.plus(downTimes.get(i).getDuration());
} else if (curStart.isBefore(nextStart) && curEnd.isAfter(nextStart)) {
total = total.plus(Duration.between(curEnd, nextEnd));
} else if (curEnd.equals(nextStart)) {
total = total.plus(downTimes.get(i).getDuration());
}
i++;
if (i == downTimes.size()) {
// assuming you want the duration as a total of milliseconds
componentDTimeMap.put(application, total.toMillis());
return;
}
}
You can either store the Duration object, or the respective value of milliseconds. Don't try to transform it to a Date, because a date is not designed nor supposed to work with durations. You can adapt this code to format a duration if you want (unfortunately there are no native formatters for durations).
Limitations
The code above assumes that all start and end times are in the same day. But if you have start at 23:50 and end at 00:10, should the duration be 20 minutes?
If that's the case, it's a little bit trickier, because LocalTime is not aware of the date (so it considers 23:50 > 00:10 and the duration between them is "minus 23 hours and 40 minutes").
In this case, you could do a trick and assume the dates are all at the current date, but when start is greater than end, it means that end time is in the next day:
LocalTime start = LocalTime.parse("23:50");
LocalTime end = LocalTime.parse("00:10");
// calculate duration
Duration d;
if (start.isAfter(end)) {
// start is after end, it means end is in the next day
// current date
LocalDate now = LocalDate.now();
// start is at the current day
LocalDateTime startDt = now.atTime(start);
// end is at the next day
LocalDateTime endDt = now.plusDays(1).atTime(end);
d = Duration.between(startDt, endDt);
} else {
// both start and end are in the same day
// just calculate the duration in the usual way
d = Duration.between(start, end);
}
In the code above, the result will be a Duration of 20 minutes.
Don't format dates as durations
Here are some examples of why SimpleDateFormat and Date aren't good to handle durations of time.
Suppose I have a duration of 10 seconds. If I try to transform it to a java.util.Date using the value 10 to a date (AKA treating a duration as a date):
// a 10 second duration (10000 milliseconds), treated as a date
Date date = new Date(10 * 1000);
System.out.println(date);
This will get a date that corresponds to "10000 milliseconds after unix epoch (1970-01-01T00:00Z)", which is 1970-01-01T00:00:10Z. But when I print the date object, the toString() method is implicity called (as explained here). And this method converts this millis value to the JVM default timezone.
In the JVM I'm using, the default timezone is America/Sao_Paulo, so the code above outputs:
Wed Dec 31 21:00:10 BRT 1969
Which is not what is expected: the UTC instant 1970-01-01T00:00:10Z corresponds to December 31st 1969 at 9 PM in São Paulo timezone.
This happens because I'm erroneously treating the duration as a date (and the output will be different, depending on the default timezone configured in the JVM).
A java.util.Date can't (must not) be used to work with durations. Actually, now that we have better API's, it should be avoided whenever possible. There are too many problems and design issues with this, just don't use it if you can.
SimpleDateFormat also won't work properly if you handle the durations as dates. In this code:
SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
Date d = dateFormat.parse("10:00:00");
The input has only time fields (hour, minute and second), so SimpleDateFormat sets the date to January 1st 1970 at the JVM default timezone. If I System.out.println this date, the result will be:
Thu Jan 01 10:00:00 BRT 1970
That's January 1st 1970 at 10 AM in São Paulo timezone, which in UTC is equivalent to 1970-01-01T13:00:00Z - so d.getTime() returns 46800000.
If I change the JVM default timezone to Europe/London, it will create a date that corresponds to January 1st 1970 at 10 AM in London (or UTC 1970-01-01T09:00:00Z) - and d.getTime() now returns 32400000 (because 10 AM in London and 10 AM in São Paulo happened at different instants).
SimpleDateFormat isn't the right tool to work with durations - it isn't even the best tool to work with dates, actually.

How to get the number of days between two java dates, comparing both the date and also time

I am trying to calculate the number of days between two java date objects using the following code:
public static int daysBetweenDates(Date startDate, Date endDate)
{
return Days.daysBetween( new LocalDate(startDate.getTime()), new LocalDate(endDate.getTime())).getDays();
}
I am using the Joda time here. But my problem is that when I compare two dates, example : Mon Apr 11 09:04:00 IST 2016 and Wed Apr 13 11:04:00 IST 2016, the result I get is 2. In fact the result I am expecting is 3 since there is more than 2 days between the given dates. Is there any way to do that.
The JavaDoc for Days.daysBetween() says (emphasis mine):
Creates a Days representing the number of whole days between the two
specified partial datetimes.
So just check whether there are any "left-overs", and increase if that's the case:
LocalDateTime now = new LocalDateTime();
LocalDateTime then = now.minusDays(2).minusMinutes(5);
int numberOfDaysBetween = Days.daysBetween(then, now).getDays();
LocalDateTime fullDayTime = then.plusDays(numberOfDaysBetween);
if (fullDayTime.isBefore(now)) {
numberOfDaysBetween++;
}
This should end up with numberOfDaysBetween being 3, since then is 2 days and 5 minutes before now.
No absolute need to use Joda time, or java.time, here. A day is (86400 * 1000) milliseconds. Java Dates give you the current time as UTC milliseconds in the Posix epoch. So ...
long diffMillis = endDate.getTime() - startDate.getTime();
int deltaDays = (int) Math.ceil(diffMillis / (86400.0 * 1000.0));

Subtracting 5 minutes from epoch date [duplicate]

This question already has answers here:
subtracting two days from current date in epoch milliseconds java [duplicate]
(5 answers)
Closed 8 years ago.
What is the best way to subtract 5 minutes from a given epoch date ?
public long fiveMinutesAgo(String epochDate) {
//ToDo
return fiveMinBack;
}
epochDate has to be a Date. Use a Calendar:
Calendar calendar = Calendar.getInstance();
calendar.setTime(epochDate);
calendar.add(Calendar.MINUTE, -5);
Date result = calendar.getTime();
You can use any of the above mentioned methods by other user , but if interested give a try to
Java 8 Date and Time API
public void subtract_minutes_from_date_in_java8 ()
{
LocalDateTime newYearsDay = LocalDateTime.of(2015, Month.JANUARY, 1, 0, 0);
LocalDateTime newYearsEve = newYearsDay.minusMinutes(1);// In your case use 5 here
java.time.format.DateTimeFormatter formatter =java.time.format.DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm:ss S");
logger.info(newYearsDay.format(formatter));
logger.info(newYearsEve.format(formatter));
}
Output :
01/01/2015 00:00:00 CST
12/31/2014 23:59:00 CST
Class LocalDateTime is an immutable date-time object present in java.time package in Java 8 that represents a date-time, often viewed as year-month-day-hour-minute-second.
Below is the syntax of of() method used :
static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute)
which obtains an instance of LocalDateTime from year, month, day, hour and minute, setting the second and nanosecond to zero.
You can subtract 5 minute equivalent of miiliseconds from date you get:-
//convert input string epochDate to Date object based on the format
long ms=date.getTime();
Date updatedDate=new Date(ms - (5 * 60000)); //60000 is 1 minute equivalent in milliseconds
return updatedDate.getTime();
Here's a body for your method:
private static final long FIVE_MINS_IN_MILLIS = 5 * 60 * 1000;
public long fiveMinutesAgo(String epochDate) throws ParseException {
DateFormat df = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss");
long time = df.parse(epochDate).getTime();
return time - FIVE_MINS_IN_MILLIS;
}
The time is in millis-since-the-epoch, so to find out five minutes before you simply have to subtract 5 mins in milliseconds (5 * 60 * 1000).
I would suggest renaming the method to: fiveMinutesBefore() and perhaps breaking it into two methods: one for parsing string dates into times and the other for subtracting minutes from the time.
You might also consider using Joda-Time as it's much better designed (and thread-safer) than the standard Java date package.

JAVA - Is it a bug in java.util.Calendar class or what?

I have faced the same problem many times.
The Same Problem was With This Question and Got Solution Like the Same,
How to compare known hours ad current hour in android?
Problem :
When I use Calendar calCurr = Calendar.getInstance(); to get the Calendar object of current date and time, It always return me wrong.
I have put logs and checked it and to make it correct I had to add in years and months and then I got the correct object for Current Date and Time.
See My Example :
Calendar calCurr = Calendar.getInstance();
Log.i("Time in mili of Current - Normal", ""+calCurr.getTimeInMillis());
// see what it gives? dont know why?
Date date = new Date();
calCurr.set(date.getYear()+1900, date.getMonth()+1, date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds());
// so added one month to it
Log.i("Time in mili of Current - after update", ""+calCurr.getTimeInMillis());
// now get correct
Question :
Why it's giving the wrong output?
Is it a bug in there or My concept about the Calendar class is wrong?
tell me what should have been done
for that?
It works perfectly as expected if you change to getDate() it outputs :
Time in mili of Current - Normal Wed Apr 04 11:34:34 BST 2012
Time in mili of Current - after update Fri May 04 11:34:34 BST 2012
What do you expect ? And in milleseconds it also equals 30 days :
Time in mili of Current - Normal 1333535834557
Time in mili of Current - after update 1336127834557
and the calculation is (difference, divided by milliseconds in a day) :
1336127834557 - 1333535834557 = 2 592 000 000
2592000000 / 86400000 = 30
And todays date in milliseconds after 1970 is 1333536754 ... which fits, I don't see a problem.
EDIT
Your Problem is you are setting Month like 3 for march...there you need to set 2..cause months are indexed from 0 to 11.
Do not use date.getXXX(). Do not use any setter or getter except Date.getTime(). They are all deprecated. Using them would cause unexpected results.
If you call Calendar.getInstance(), it is already set to the current date. If you want to set or add days, months, whatever, set them on the calendar.
E.g. calCurr.set(Calendar.MONTH,2) or calCurr.add(Calendar.DAY,1).
It is NOT a bug, the Calendar is returning what it should (at least here it is).
Calendar calCurr = Calendar.getInstance();
Log.i("Time in mili of Current - Normal", ""+calCurr.getTimeInMillis());
// see what it gives? dont know why?
I got 1333546375707 milliseconds, which is the correct value (also calculated by hand).
Which value are you expecting here? How you know it is wrong?
Date date = new Date();
calCurr.set(date.getYear()+1900, date.getMonth()+1, date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds());
// so added one month to it
Why adding ONE to the month? Month of both Date and Calendar are zero-based - no need to add 1.
EDIT
Calculating by hand (approximated):
2012 - 42 years * 365.24 days/year * 86400 seconds/day
April - (31 + 29 + 31) days * 86400
4th - 3 days * 86400
13:30 - 13.5 hours * 3600 seconds/hour
====================
1333553112 seconds
Calendar months are zero-indexed. So when want to set for March its 2 not 3
Also, Don't set year, month and date from the Date object. If you must initialise a Calendar to a date, do it like this:
Calendar cal = Calendar.getInstance();
cal.setTime(date);
be aware that your Date object might be a different locale to what you think it is.
When Calendar object is created by using Calendar.getInstance() the instance variable "time" in the Calendar object is set and this value will get changed only if you use
Calendar.setTimeInMillis() function.
Code snippet from Calendar object:
public long getTimeInMillis() {
if (!isTimeSet) {
updateTime();
}
return time;
}
Here "isTimeSet" will become "true" when Calendar.getInstance() is called and it returns "time" every time without updating the time.
This is the reason you get the same value of time every time you call
calCurr.getTimeInMillis();
Hope this helps.
It's the weird implementation of Calendar.
For some reasons January is month 0, and years are not very logical as well.
I recommend Joda time library.
We are using below lines of code for finding current date and time It's working fine our side.
java.util.Calendar calc = java.util.Calendar.getInstance();
int day = calc.get(java.util.Calendar.DATE);
int month = calc.get(java.util.Calendar.MONTH)+1;
int year = calc.get(java.util.Calendar.YEAR);
String dayStr,monthStr;
if(day<10){
dayStr = "0"+day;
}else{
dayStr = ""+day;
}
if(month<10){
monthStr = "0"+month;
}else{
monthStr = ""+month;
}
/*String currentdate = monthStr+"/"+dayStr+"/"+year+" ";*/
String currentdate = dayStr+"/"+monthStr+"/"+year+" ";
/*String currenttime = currentdate + String.valueOf(calc.get(java.util.Calendar.HOUR_OF_DAY))+ ":"+
String.valueOf(calc.get(java.util.Calendar.MINUTE))+":"+String.valueOf(calc.get(java.util.Calendar.SECOND));*/
return currentdate;
Java Date Based API is not properly designed.
in future versions I think some problems of The API are planned to address.
I would recommend to use JodaTime.

Time problem with this code

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
public class test {
/*
* Calculate the difference between two date/times *
*
*/
private static long dateDiff(Date toDate, Date fromDate) {
Calendar cal = Calendar.getInstance();
cal.setTime(toDate);
long ms = cal.getTimeInMillis();
cal.setTime(fromDate);
ms -= cal.getTimeInMillis();
return ms;
}
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss");
Date d1 = null;
Date d2 = null;
try {
d1 = sdf.parse("11:00:00");
d2 = sdf.parse("10:00:00");
} catch (Exception e) {
e.printStackTrace();
}
long result = dateDiff(d1, d2);
Date time = new Date(result);
System.out.println(time);
}
}
When I run it I get this result :
Thu Jan 01 02:00:00 CET 1970
I would expect 1 hour difference ?! again a problem with Timezone??
Any idea how I can fix it.
thx all
I don't know what you expect this to do, but what you are actually doing is outputting the date corresponding to one hour after midnight on Jan 1 1970, using the default timezone.
You seem to want to Date to represent a duration (i.e. a number of seconds). It doesn't do that, and neither will the Date formatters render a Date as a duration.
I need the time difference between two Date fields and then put it in MySql (time format)
For what you are trying to do, you need calculate the duration value as a long, then use the java.sql.Time(long) constructor to create a Time object. You can either serialize this object using its toString() method or use it as a parameter in a JDBC prepared statement.
It turns out that my advice above is incorrect too.
Your real problem is that the SQL Time type is for representing times ... not durations. In fact, SQL does not have a dedicated duration type, so the best you can do is represent the duration as an integer number of seconds or milliseconds or whatever.
(For the more general case, the Joda Time libraries are generally thought to provide the best APIs for manipulating dates, times and related temporal values. But for this simple case, the standard J2SE libraries should suffice ... provided that you use them correctly.)
The problem is that a difference of two Date types can not be represented by another Date type.
Why don't you just take the milliseconds of both dates and substract them from each other?
Calendar cal = Calendar.getInstance();
cal.setTime(d1);
long d1ms = cal.getTimeInMillis();
cal.setTime(d2);
long d2ms = cal.getTimeInMillis();
long diffMs = d1ms - d2ms;
long diffHour = diffMs * 1000 * 60 * 60;
Hi try this setting timezone to GMT. Remove day, month in words in the resultant time difference. This method does nothing but assumes these many milliseconds since starting of time counter in java, which is 1st Jan 1970. So if your result says 3rd Jan 1970 means 3 days have passed since time counter started, which is perfect. You just need to interpret it properly, but formatting your answer
...
long result = dateDiff(d1, d2); //This is your code in main([])
SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss SSS");
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println(dateFormat.format(new Date(result )));

Categories

Resources