I'm a newbie to Java. I am given 3 times, in the "HH:mm:ss" format. I'm supposed to take an input(in integers(and must be in minutes)) add it to the 3rd time. If the sum of time is less than the 1st and 2nd time(1st time <=2nd time), it must print 1. If it is only less than the 2nd time, it should print 2. If neither is less, it prints false.
However, the values of the double variable I'm mapping the date to are returning
values in the negative sometimes (Please check the output).
Could someone help me understand why? Thanks.
import java.util.*;
import java.text.*;
public class TimeTrial2 {
public static void main(String q[]) throws ParseException
{
Scanner x=new Scanner(System.in);
SimpleDateFormat y=new SimpleDateFormat("HH");
SimpleDateFormat k=new SimpleDateFormat("HH:mm:ss");
String b=x.nextLine();
Date c=k.parse(b);//1st Time
String d=x.nextLine();
Date e=k.parse(d);//2nd Time
String f=x.nextLine();
Date g=k.parse(f);//Time to be added to the input
int a=x.nextInt();//Input time i
a=a/60;
Date z=y.parse(Integer.toString(a));
double p=(z.getTime()+g.getTime());
double r=c.getTime();
double s=e.getTime();
System.out.println(p+"\n"+r+"\n"+s); `//to check the values of p,r and s`
if(r>=p)
{
System.out.println("1");
}
else if(s>=p)
{
System.out.println("2");
}
else
{
System.out.println("FALSE!");
}
}
}
Input:
4:30:00
6:00:00
4:00:00
60
This is my output:
-2.16E7
-3600000.0
1800000.0
1
Edit: Adding 330 minutes (+5:30 GMT) rectifies the issue.
However, I'd recommend using Ole V.V's answer as it is much easier. I was unaware that such a date class and method existed. Thank you all for your help.
Consider how you add the time to the Date. I tried out the following code for adding minutes to the date and it worked.
Calendar calendar = GregorianCalendar.getInstance();
calendar.setTime(g);
calendar.add(GregorianCalendar.MINUTE, a);
Input:
g = 5:00:00
a = 40
Output:
Thu Jan 01 05:00:00 IST 1970
Thu Jan 01 05:40:00 IST 1970
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Scanner;
public class TimeTrial3 {
public static void main(String... commandLineArguments) {
Scanner consoleInput = new Scanner(System.in);
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("H:mm:ss");
String time1String = consoleInput.nextLine();
LocalTime time1 = LocalTime.parse(time1String, timeFormatter);
String time2String = consoleInput.nextLine();
LocalTime time2 = LocalTime.parse(time2String, timeFormatter);
if (time2.isBefore(time1)) {
System.err.println("First time must be before or equal to second time, they were"
+ time1 + " and " + time2);
System.exit(1);
}
String timeToAddString = consoleInput.nextLine();
LocalTime timetoAdd = LocalTime.parse(timeToAddString, timeFormatter);
int minutesToAdd = consoleInput.nextInt();
LocalTime timeToCompare = timetoAdd.plusMinutes(minutesToAdd);
if (timeToCompare.isBefore(time1))
{
System.out.println("1");
}
else if (timeToCompare.isBefore(time2))
{
System.out.println("2");
}
else
{
System.out.println("False");
}
}
}
Issues with your code
The Date class isn’t very well suited for representing a time of day only.
The Date and SimpleDateFormat classes are long outdated and the latter in particular notoriously troublesome. I recommend you don’t use them at all. Instead I am using and warmly recommending java.time, the modern Java date and time API. It is so much nicer to work with.
When you can use library classes for dates and/or times, do that. Don’t use double nor long.
An observation, not really a problem: It seems you are in a time zone at offset -05:30 from UTC (like Sri Lanka or India)? For example, your input of 4:30:00 was parsed into this time on January 1, 1970 (the epoch day) at offset -5:50, which is equal to 1 hour before the epoch, so it came out as -3600000.0 because -3600 seconds equals -1 hour. This is not a problem in itself as long as all your times are at the same offset. Then you can still compare them using before or after as harsha kumar Reddy said in another answer.
The trouble comes when you try to add the milliseconds from two Date objects. The third time, 4:00:00, is parsed into 1 hour 30 min before the epoch, and the 60 minutes into 4 hours 30 minutes before the epoch. When adding the two you expect a time of 5:00:00 (in your time zone). Instead you get 6 hours before the epoch, which is printed as -2.16E7 (on my computer I get a different incorrect result because I am in a different time zone).
By dividing the minutes from input by 60 to obtain hours, you are losing precision. For example, if the input was 90 minutes (one and a half hours), you get just 1 hour after division.
And as mentioned in the comment, you should use explanatory variable names. You may have had an idea behind the names you chose, but I didn’t get it.
Link
Oracle tutorial: Date Time explaining how to use java.time.
Try using equals() , before() , after() methods of Date class .
refer java Api docs
Related
I have written the code below but if the current date-time is 2022-07-03 09:48:05.448 and I add 30 minutes, my response returns 2022-07-03 09:79:05.448.
But minutes can never be 79, it is supposed to move to the hours instead...
public static String getExpiryDate(int additionalMinutesToCurrentMinute) {
LocalDateTime now = LocalDateTime.now();
int year = now.getYear();
int month = now.getMonthValue();
int day = now.getDayOfMonth();
int hour = now.getHour();
int minute = now.getMinute() + additionalMinutesToCurrentMinute;
int second = now.getSecond();
int millis = now.get(ChronoField.MILLI_OF_SECOND); // Note: no direct getter available.
String expiryDateAndTime = String.format("%d-%02d-%02d %02d:%02d:%02d.%03d", year, month, day, hour, minute, second, millis);
return expiryDateAndTime;
}
Explanation
The reason your code does not work as expected is because you are not involving javas Date/Time API at all in your "math".
Your adding the minutes with plain int-arithmetic
int minute = now.getMinute() + additionalMinutesToCurrentMinute;
and then you use plain string formatting
String.format("%d-%02d-%02d %02d:%02d:%02d.%03d", year, month, day, hour, minute, second, millis);
Nothing in this chain is "clever" and knows about date/time specifics.
Solution
You have to involve the Date/Time API for your math, then it will be clever and correctly adjust the hours as well. Fortunately, there is a method in LocalDateTime already that does what you want:
LocalDateTime expirationTime = LocalDateTime.now().plusMinutes(30);
and that is pretty much all you need.
For the formatting part, either roll with the default representation:
return expirationTime.toString();
or use a DateTimeFormatter:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd HH:mm:ss.AAA");
and then
return expirationTime.format(formatter);
Notes
Instant
You are actually using the incorrect type for an expiration time. Using LocalDateTime will result in your application failing under certain situations. For example if your computer moves across countries, or your government decides to change its timezone. Or when DST hits (summer vs winter time) or leap seconds are added and more...
The correct type would be Instant, which represents a single moment on the timeline, without interpretation of clock-time or calendar-dates.
The API is the same, so you can just use it the same way.
That said, your method should also return Instant and not a String. Keep the clever date/time type as long as possible, dont go to something as low level and raw as a string.
public static Instant getExpiryDate(int additionalMinutes) {
return Instant.now()
.plus(additionalMinutes, ChronoUnit.MINUTES);
}
Design
Design-wise it would be better if the method would not even take int additionalMinutes but also the unit. Otherwise the call-site is hard to read for users:
getExpiryDate(30) // 30 what? minutes? seconds? days?
with the unit, it would be easier to read and harder to misunderstand
getExpiryDate(30, ChronoUnit.MINUTES)
At which point one could argue that the method is kinda obsolete now.
Instead of editing the amount of minutes manually, try using the plusMinutes method on your LocalDateTime like so:
LocalDateTime now = LocalDateTime.now();
LocalDateTime then = now.plusMinutes(30);
This way, the class should increase the hour for you once it passes 60 minutes.
I need to write a function that accepts a java.util.Date and removes the hours, minutes, and milliseconds from it USING JUST MATH (no Date formatters, no Calendar objects, etc.):
private Date getJustDateFrom(Date d) {
//remove hours, minutes, and seconds, then return the date
}
The purpose of this method is to get the date from a millisecond value, without the time.
Here's what I have so far:
private Date getJustDateFrom(Date d) {
long milliseconds = d.getTime();
return new Date(milliseconds - (milliseconds%(1000*60*60)));
}
The problem is, this only removes minutes and seconds. I don't know how to remove hours.
If I do milliseconds - (milliseconds%(1000*60*60*23)), then it goes back to 23:00 hrs on the previous day.
EDIT:
Here's an alternative solution:
public static Date getJustDateFrom(Date d) {
Calendar c = Calendar.getInstance();
c.setTime(d);
c.set(Calendar.HOUR_OF_DAY, 0);
c.set(Calendar.MINUTE, 0);
return c.getTime();
}
Will this solution be affected by time zone differences between the client/server sides of my app?
There are 24 hours in a day. Use milliseconds%(1000*60*60*24).
Simply not possible by your definition.
A millisecond timestamp represents milliseconds elapsed from a fixed point in time (1970-01-01 00:00:00.000 UTC, if I remember correctly). This timestamp can not be converted into a date + time without specifying the timezone to convert to.
So you can only round the timestamp to full days in respect to a specific timezone, not in general. So any fiddling with Date.getTime() and not taking into account any timezone is guaranteed to work in only one time zone - the one you hardcoded for.
Do yourself a favor and use a Calendar.
You can make use of apache's commons lang DateUtils helper utility class.
For example, if you had the datetime of 28 Mar 2002
13:45:01.231, if you passed with Calendar.HOUR, it would return 28 Mar
2002 13:00:00.000. If this was passed with Calendar.MONTH, it would
return 1 Mar 2002 0:00:00.000.
Date newDate = DateUtils.truncate(new Date(1408338000000L), Calendar.DAY_OF_MONTH);
You can download commons lang jar at http://commons.apache.org/proper/commons-lang/
import java.sql.Date;
long dateInEpoch = 1_592_283_050_000L;
ZoneId defaultZoneId = ZoneId.systemDefault();
long currentDate = Date
.from(new Date(dateInEpoch)
.toLocalDate()
.atStartOfDay(defaultZoneId)
.toInstant())
.getTime();
input : 1592283050000
output: 1592245800000
In java, I want to get the number of days between two dates, excluding those two dates.
For example:
If first date = 11 November 2011 and the second date = 13 November 2011
then it should be 1.
This is the code I am using but doesn't work (secondDate and firstDate are Calendar objects):
long diff=secondDate.getTimeInMillis()-firstDate.getTimeInMillis();
float day_count=(float)diff / (24 * 60 * 60 * 1000);
daysCount.setText((int)day_count+"");
I even tried rounding the results but that didn't help.
How do I get the number of days between dates in java excluding the days themselves?
I've just tested on SDK 8 (Android 2.2) the following code snippet:
Calendar date1 = Calendar.getInstance();
Calendar date2 = Calendar.getInstance();
date1.clear();
date1.set(
datePicker1.getYear(),
datePicker1.getMonth(),
datePicker1.getDayOfMonth());
date2.clear();
date2.set(
datePicker2.getYear(),
datePicker2.getMonth(),
datePicker2.getDayOfMonth());
long diff = date2.getTimeInMillis() - date1.getTimeInMillis();
float dayCount = (float) diff / (24 * 60 * 60 * 1000);
textView.setText(Long.toString(diff) + " " + (int) dayCount);
it works perfectly and in both cases (Nov 10,2011 - Nov 8,2011) and (Nov 13,2011 - Nov 11,2011) gives dayCount = 2.0
Get Days between java.util.Dates, ignoring daylight savings time
Quick and dirty hack:
public int get_days_between_dates(Date date1, Date date2)
{
//if date2 is more in the future than date1 then the result will be negative
//if date1 is more in the future than date2 then the result will be positive.
return (int)((date2.getTime() - date1.getTime()) / (1000*60*60*24l));
}
This function will work 99.99% of the time, except when it surprises you later on in the edge cases during leap-seconds, daylight savings, timezone changes leap years and the like. If you are OK with the calculation being off by 1 (or 2) hours once in a while, this will suffice.
Get Days between Dates taking into account leapseconds, daylight savings, timezones, etc
If you are asking this question you need to slap yourself. What does it mean for two dates to be at least 1 day apart? It's very confusing. What if one Date is midnight in one timezone, and the other date is 1AM in another timezone? Depending on how you interpret it, the answer is both 1 and 0.
You think you can just force the dates you pass into the above function as Universal time format; that will fix some of your problems. But then you just relocate the problem into how you convert your local time to a universal time. The logical conversion from your timezone to universal time may not be what is intuitive. In some cases you will get a day difference when the dates passed in are obviously two days apart.
And you think you can deal with that? There are some simplistic calendar systems in the world which are constantly changing depending on the harvest season and installed political rulers. If you want to convert their time to UTC, java.util.Date is going to fail you at the worst moment.
If you need to calculate the days between dates and it is critical that everything come out right, you need to get an external library called Joda Time: (They have taken care of all the details for you, so you can stay blissfully unaware of them): http://joda-time.sourceforge.net/index.html
java.time
The java.time API, released with Java-8 in March 2014, supplanted the error-prone legacy date-time API. Since then, using this modern date-time API has been strongly recommended.
Solution using modern date-time API
Using Calendar#toInstant, convert your java.util.Calendar instances into java.time.Instant and then into java.time.ZonedDateTime instances and then use ChronoUnit.DAYS.between to get the number of days between them.
Demo:
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Calendar;
public class Main {
public static void main(String[] args) {
// Sample start and end dates as java.util.Date
Calendar startCal = Calendar.getInstance();
startCal.set(2011, 10, 11); // 11 November 2011
Calendar endCal = Calendar.getInstance();
endCal.set(2011, 10, 13); // 13 November 2011
// Convert the java.util.Calendar into java.time.ZonedDateTime
// Replace ZoneId.systemDefault() with the applicable ZoneId
ZonedDateTime startDateTime = startCal.toInstant().atZone(ZoneId.systemDefault());
ZonedDateTime endDateTime = endCal.toInstant().atZone(ZoneId.systemDefault());
// The end date is excluded by default. Subtract 1 to exclude the start date
long days = ChronoUnit.DAYS.between(startDateTime, endDateTime) - 1;
System.out.println(days);
}
}
Output:
1
Learn more about the modern Date-Time API from Trail: Date Time.
Don't use floats for integer calculations.
Are you sure your dates are days? The precision of the Date type is milliseconds. So the first thing you need to do is round the date to something which doesn't have hours. Example: It's just one hour from 23:30 2011-11-01 to 00:30 2011-11-02 but the two dates are on different days.
If you are only going to be dealing with dates between the years 1900 and 2100, there is a simple calculation which will give you the number of days since 1900:
public static int daysSince1900(Date date) {
Calendar c = new GregorianCalendar();
c.setTime(date);
int year = c.get(Calendar.YEAR);
if (year < 1900 || year > 2099) {
throw new IllegalArgumentException("daysSince1900 - Date must be between 1900 and 2099");
}
year -= 1900;
int month = c.get(Calendar.MONTH) + 1;
int days = c.get(Calendar.DAY_OF_MONTH);
if (month < 3) {
month += 12;
year--;
}
int yearDays = (int) (year * 365.25);
int monthDays = (int) ((month + 1) * 30.61);
return (yearDays + monthDays + days - 63);
}
Thus, to get the difference in days between two dates, you calculate their days since 1900 and calc the difference. Our daysBetween method looks like this:
public static Integer getDaysBetween(Date date1, Date date2) {
if (date1 == null || date2 == null) {
return null;
}
int days1 = daysSince1900(date1);
int days2 = daysSince1900(date2);
if (days1 < days2) {
return days2 - days1;
} else {
return days1 - days2;
}
}
In your case you would need to subtract an extra day (if the days are not equal).
And don't ask me where this calculation came from because we've used it since the early '90s.
I have two suggestions:
Make sure your float day_count is calculated correctly
float day_count = ((float)diff) / (24f * 60f * 60f * 1000f);
If it's rounding error, try using floor method
daysCount.setText("" + (int)Math.floor(day_count));
I have an app that takes a Timestamp as a boundary for the start date and end date of a sql selection, I want to populate a hashmap with weeks this year since the first monday of the year as the values and the week number as the keys. I'm finding it really hard to work with timestamps and I don't feel very good about adding 86,400,000 seconds to it to increment the day, as this doesn't account for the leap days, hours, seconds.
I plan on adding 13 days 23 hours, 59 minutes and 59 seconds to it so that I can lookup the start date in the map by the week as the key, then use the start date to get the end date.
So I'm looking to try to get something like this:
Week startDate endDate
1 2011-01-03 00:00:00 2011-01-16 23:59:59
2 2011-01-17 00:00:00 2011-01-30 23:59:59
With the first two columns in the Map and the last one being calculated after looking it up. How do I safely increment a java.sql.Timestamp?
java.sql.Timestamp ts = ...
Calendar cal = Calendar.getInstance();
cal.setTime(ts);
cal.add(Calendar.DAY_OF_WEEK, 14);
ts.setTime(cal.getTime().getTime()); // or
ts = new Timestamp(cal.getTime().getTime());
This will correctly cater for daylight-time transitions in your default Timezone. You can tell the Calendar class to use a different Timezone if need be.
It worth noting that 14 days is not always 14 * 24 * 3600 seconds. When you have daylight savings, this can be an hour shorter or longer. Historically it can be much more complex than that.
Instead I would suggest using JodaTime or the Calendar to perform the time zone dependant calculation.
Java 8
Timestamp old;
ZonedDateTime zonedDateTime = old.toInstant().atZone(ZoneId.of("UTC"));
Timestamp new = Timestamp.from(zonedDateTime.plus(14, ChronoUnit.DAYS).toInstant());
private Long dayToMiliseconds(int days){
Long result = Long.valueOf(days * 24 * 60 * 60 * 1000);
return result;
}
public Timestamp addDays(int days, Timestamp t1) throws Exception{
if(days < 0){
throw new Exception("Day in wrong format.");
}
Long miliseconds = dayToMiliseconds(days);
return new Timestamp(t1.getTime() + miliseconds);
}
Timestamp my14DaysAfter = Timestamp.valueOf(myTimestamp.toLocalDateTime().plusDays(14));
I want to work out the next payment date in my code. I have a start date and i have a payment frequency which can be DAY, WEEK, MONTH or YEAR. So if the start date was 10 FEB 2009 and had a payment frequency of MONTH and the current date is 13 NOV 2009 then the next payment date would be 10 DEC 2009
I have already written some meaty code using JDK data classes to work this out. But we have move other parts of the system to Joda and so i would like to migrate this code to.
So does any Joda guru know how to do it easily?
Here's a brute force method (ignoring working days etc). Note that you can't just repeatedly add the period, as (Jan 30th + 1 month) + 1 month != Jan 30th + 2 months.
import org.joda.time.LocalDate;
import org.joda.time.Period;
public class Test {
public static void main(String[] args) {
LocalDate start = new LocalDate(2009, 2, 10);
LocalDate now = new LocalDate(2009, 11, 13);
System.out.println(next(start, Period.months(1), now));
}
public static LocalDate next(LocalDate start, Period period, LocalDate now) {
Period current = Period.ZERO;
while (true) {
LocalDate candidate = start.plus(current);
if (candidate.isAfter(now)) {
return candidate;
}
current = current.plus(period);
}
}
}
It's possible that there are less brute-force ways of doing it - particularly if you don't have to be able to take a completely arbitrary period - but this is probably the simplest solution.
Just putting together the comments
public static void main(String[] args) {
LocalDate date = LocalDate.parse("03-10-2010",Constants.DEFAULT_DATE_FORMAT);
Months gap = Months.monthsBetween(date,LocalDate.now());
System.out.println(Months.monthsBetween(date,LocalDate.now()));
System.out.println("Cycle Start " + date.plusMonths(gap.getMonths()));
System.out.println("Cycle End " + date.plusMonths(gap.getMonths()+1));
}